Skip to content

Commit

Permalink
Upgrade JDK toolchain and target version for most packages to 17 to g…
Browse files Browse the repository at this point in the history
…et GraalJS+LiquidJS working via a transformer.

There's a rough test in place that shows the relative performance between Liquid.js and a raw javascript call.  The results on my mac were about 300x slower to use the templating solution than to just run JSON.stringify().

/Library/Java/JavaVirtualMachines/amazon-corretto-17.jdk/Contents/Home/bin/java -XX:+UnlockExperimentalVMOptions -XX:+EnableJVMCI ...
org.opensearch.migrations.transform.LiquidJsTransformerTest
[To redirect Truffle log output to a file use one of the following options:
* '--log.file=<path>' if the option is passed using a guest language launcher.
* '-Dpolyglot.log.file=<path>' if the option is passed using the host Java launcher.
* Configure logging using the polyglot embedding API.]
[engine] WARNING: The polyglot engine uses a fallback runtime that does not support runtime compilation to native code.
Execution without runtime compilation will negatively impact the guest application performance.
The following cause was found: Libgraal compilation is not available on this JVM. Alternatively, the org.graalvm.compiler:compiler module can be put on the --upgrade-module-path.
For more information see: https://www.graalvm.org/latest/reference-manual/embed-languages/#runtime-optimization-support.
To disable this warning use the '--engine.WarnInterpreterOnly=false' option or the '-Dpolyglot.engine.WarnInterpreterOnly=false' system property.
[To redirect Truffle log output to a file use one of the following options:
* '--log.file=<path>' if the option is passed using a guest language launcher.
* '-Dpolyglot.log.file=<path>' if the option is passed using the host Java launcher.
* Configure logging using the polyglot embedding API.]
[engine] WARNING: The polyglot engine uses a fallback runtime that does not support runtime compilation to native code.
Execution without runtime compilation will negatively impact the guest application performance.
The following cause was found: Libgraal compilation is not available on this JVM. Alternatively, the org.graalvm.compiler:compiler module can be put on the --upgrade-module-path.
For more information see: https://www.graalvm.org/latest/reference-manual/embed-languages/#runtime-optimization-support.
To disable this warning use the '--engine.WarnInterpreterOnly=false' option or the '-Dpolyglot.engine.WarnInterpreterOnly=false' system property.
[INFO ] 2024-12-20 04:11:56,654825 [main] LiquidJsTransformerTest - Run 0: PT4.052694709S
[INFO ] 2024-12-20 04:11:59,694596 [main] LiquidJsTransformerTest - Run 1: PT3.039395S
[INFO ] 2024-12-20 04:12:02,747087 [main] LiquidJsTransformerTest - Run 2: PT3.052563917S
[INFO ] 2024-12-20 04:12:05,823644 [main] LiquidJsTransformerTest - Run 3: PT3.076653792S
[INFO ] 2024-12-20 04:12:08,833241 [main] LiquidJsTransformerTest - Run 4: PT3.009687375S
[To redirect Truffle log output to a file use one of the following options:
* '--log.file=<path>' if the option is passed using a guest language launcher.
* '-Dpolyglot.log.file=<path>' if the option is passed using the host Java launcher.
* Configure logging using the polyglot embedding API.]
[engine] WARNING: The polyglot engine uses a fallback runtime that does not support runtime compilation to native code.
Execution without runtime compilation will negatively impact the guest application performance.
The following cause was found: Libgraal compilation is not available on this JVM. Alternatively, the org.graalvm.compiler:compiler module can be put on the --upgrade-module-path.
For more information see: https://www.graalvm.org/latest/reference-manual/embed-languages/#runtime-optimization-support.
To disable this warning use the '--engine.WarnInterpreterOnly=false' option or the '-Dpolyglot.engine.WarnInterpreterOnly=false' system property.
[INFO ] 2024-12-20 04:12:08,906295 [main] LiquidJsTransformerTest - Run 0: PT0.021998S
[INFO ] 2024-12-20 04:12:08,916581 [main] LiquidJsTransformerTest - Run 1: PT0.010198S
[INFO ] 2024-12-20 04:12:08,927812 [main] LiquidJsTransformerTest - Run 2: PT0.011137708S
[INFO ] 2024-12-20 04:12:08,938391 [main] LiquidJsTransformerTest - Run 3: PT0.010506958S
[INFO ] 2024-12-20 04:12:08,948759 [main] LiquidJsTransformerTest - Run 4: PT0.010288125S
[INFO ] 2024-12-20 04:12:08,959167 [main] LiquidJsTransformerTest - Run 5: PT0.010324625S

Signed-off-by: Greg Schohn <greg.schohn@gmail.com>
  • Loading branch information
gregschohn committed Dec 20, 2024
1 parent d1cf844 commit b00c63b
Show file tree
Hide file tree
Showing 21 changed files with 286 additions and 27 deletions.
4 changes: 2 additions & 2 deletions CreateSnapshot/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ plugins {
id 'org.opensearch.migrations.java-application-conventions'
}

java.sourceCompatibility = JavaVersion.VERSION_11
java.targetCompatibility = JavaVersion.VERSION_11
java.sourceCompatibility = JavaVersion.VERSION_17
java.targetCompatibility = JavaVersion.VERSION_17

dependencies {
implementation project(':coreUtilities')
Expand Down
4 changes: 2 additions & 2 deletions DataGenerator/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ plugins {
id 'io.freefair.lombok'
}

java.sourceCompatibility = JavaVersion.VERSION_11
java.targetCompatibility = JavaVersion.VERSION_11
java.sourceCompatibility = JavaVersion.VERSION_17
java.targetCompatibility = JavaVersion.VERSION_17

dependencies {
implementation project(":coreUtilities")
Expand Down
4 changes: 2 additions & 2 deletions DocumentsFromSnapshotMigration/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,8 @@ import com.bmuschko.gradle.docker.tasks.image.DockerBuildImage
import groovy.transform.Canonical
import org.opensearch.migrations.common.CommonUtils

java.sourceCompatibility = JavaVersion.VERSION_11
java.targetCompatibility = JavaVersion.VERSION_11
java.sourceCompatibility = JavaVersion.VERSION_17
java.targetCompatibility = JavaVersion.VERSION_17

@Canonical
class DockerServiceProps {
Expand Down
4 changes: 2 additions & 2 deletions MetadataMigration/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ plugins {
id 'io.freefair.lombok'
}

java.sourceCompatibility = JavaVersion.VERSION_11
java.targetCompatibility = JavaVersion.VERSION_11
java.sourceCompatibility = JavaVersion.VERSION_17
java.targetCompatibility = JavaVersion.VERSION_17

dependencies {
implementation project(":coreUtilities")
Expand Down
4 changes: 2 additions & 2 deletions RFS/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ plugins {
id 'me.champeau.jmh'
}

java.sourceCompatibility = JavaVersion.VERSION_11
java.targetCompatibility = JavaVersion.VERSION_11
java.sourceCompatibility = JavaVersion.VERSION_17
java.targetCompatibility = JavaVersion.VERSION_17

ext {
awsSdkVersion = '2.25.16'
Expand Down
8 changes: 1 addition & 7 deletions TrafficCapture/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ subprojects {
if (project.name == "trafficReplayer" || project.name == "trafficCaptureProxyServer") {
options.compilerArgs += [
"-XDcompilePolicy=simple",
"-Xplugin:ErrorProne -XepDisableAllChecks -Xep:MustBeClosed:ERROR -XepDisableWarningsInGeneratedCode",
// "-Xplugin:ErrorProne -XepDisableAllChecks -Xep:MustBeClosed:ERROR -XepDisableWarningsInGeneratedCode",
]
}
}
Expand All @@ -25,12 +25,6 @@ subprojects {
allprojects {
apply plugin: 'java'
apply plugin: 'org.owasp.dependencycheck'

java {
toolchain {
languageVersion = JavaLanguageVersion.of(11)
}
}
}

subprojects {
Expand Down
3 changes: 3 additions & 0 deletions TrafficCapture/captureKafkaOffloader/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ plugins {
id 'io.freefair.lombok'
}

java.sourceCompatibility = JavaVersion.VERSION_11
java.targetCompatibility = JavaVersion.VERSION_11

dependencies {
implementation project(':TrafficCapture:captureOffloader')
implementation project(':coreUtilities')
Expand Down
3 changes: 3 additions & 0 deletions TrafficCapture/captureOffloader/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@ plugins {
id 'java-test-fixtures'
}

java.sourceCompatibility = JavaVersion.VERSION_11
java.targetCompatibility = JavaVersion.VERSION_11

sourceSets {
main {
java {
Expand Down
3 changes: 3 additions & 0 deletions TrafficCapture/captureProtobufs/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ plugins {
id 'com.google.protobuf' version "0.9.2"
}

java.sourceCompatibility = JavaVersion.VERSION_11
java.targetCompatibility = JavaVersion.VERSION_11

dependencies {
api group: 'com.google.protobuf', name: 'protobuf-java'
}
Expand Down
3 changes: 3 additions & 0 deletions TrafficCapture/nettyWireLogging/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ plugins {
id 'io.freefair.lombok'
}

java.sourceCompatibility = JavaVersion.VERSION_11
java.targetCompatibility = JavaVersion.VERSION_11

dependencies {
implementation project(':TrafficCapture:captureOffloader')
implementation project(':coreUtilities')
Expand Down
3 changes: 3 additions & 0 deletions TrafficCapture/trafficCaptureProxyServer/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@ configurations {
opensearchSecurityPlugin
}

java.sourceCompatibility = JavaVersion.VERSION_11
java.targetCompatibility = JavaVersion.VERSION_11

dependencies {
def openSearch = '2.11.1'
implementation "org.opensearch.plugin:opensearch-security:${openSearch}.0"
Expand Down
4 changes: 2 additions & 2 deletions awsUtilities/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@ plugins {
id 'java'
}

java.sourceCompatibility = JavaVersion.VERSION_11
java.targetCompatibility = JavaVersion.VERSION_11
java.sourceCompatibility = JavaVersion.VERSION_17
java.targetCompatibility = JavaVersion.VERSION_17

dependencies {
implementation group: 'software.amazon.awssdk', name: 'arns'
Expand Down
9 changes: 8 additions & 1 deletion build.gradle
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
plugins {
id "com.dorongold.task-tree" version "2.1.1"
// id "com.dorongold.task-tree" version "2.1.1"
id 'io.freefair.lombok' version '8.6' apply false
id "com.diffplug.spotless" version '6.25.0'
id 'me.champeau.jmh' version '0.7.2' apply false
Expand Down Expand Up @@ -85,6 +85,13 @@ subprojects {
apply plugin: 'maven-publish'
apply plugin: "com.diffplug.spotless"

java {
toolchain {
languageVersion.set(JavaLanguageVersion.of(17))
vendor.set(JvmVendorSpec.AMAZON)
}
}

// See https://github.com/diffplug/spotless/tree/main/plugin-gradle#java for some documentation,
// though what '#' does is still undocumented from what I can tell
spotless {
Expand Down
3 changes: 0 additions & 3 deletions dashboardsSanitizer/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -19,9 +19,6 @@ repositories {
}

dependencies {
implementation project(':coreUtilities')
implementation project(":RFS")

implementation group: 'com.fasterxml.jackson.core', name:'jackson-databind'
implementation group: 'org.slf4j', name: 'slf4j-api'
implementation group: 'org.apache.logging.log4j', name: 'log4j-slf4j2-impl'
Expand Down
3 changes: 3 additions & 0 deletions libraries/kafkaCommandLineFormatter/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ plugins {
id 'io.freefair.lombok'
}

java.sourceCompatibility = JavaVersion.VERSION_17
java.targetCompatibility = JavaVersion.VERSION_17

dependencies {
implementation group: 'org.apache.kafka', name:'kafka-clients', version:'3.8.0'
}
3 changes: 1 addition & 2 deletions settings.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,9 @@ import java.nio.file.Paths

plugins {
id("com.gradle.develocity") version("3.18.1")
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.7.0'
id 'org.gradle.toolchains.foojay-resolver-convention' version '0.9.0'
}


void addSubProjects(String path, File dir) {
if (dir.isDirectory() == false) {
return;
Expand Down
3 changes: 3 additions & 0 deletions testHelperFixtures/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@ plugins {
id 'java-test-fixtures'
}

java.sourceCompatibility = JavaVersion.VERSION_11
java.targetCompatibility = JavaVersion.VERSION_11

dependencies {
testFixturesImplementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind'
testFixturesImplementation group: 'com.google.guava', name: 'guava'
Expand Down
4 changes: 2 additions & 2 deletions transformation/build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ plugins {
id 'java-test-fixtures'
}

java.sourceCompatibility = JavaVersion.VERSION_11
java.targetCompatibility = JavaVersion.VERSION_11
java.sourceCompatibility = JavaVersion.VERSION_17
java.targetCompatibility = JavaVersion.VERSION_17

dependencies {
implementation project(':transformation:transformationPlugins:jsonMessageTransformers:jsonMessageTransformerInterface')
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
plugins {
id 'org.opensearch.migrations.java-library-conventions'
id 'io.freefair.lombok'
id 'de.undercouch.download' version '5.4.0' // For downloading LiquidJS
}

def graalVersion = '24.1.1'

dependencies {
implementation project(':transformation:transformationPlugins:jsonMessageTransformers:jsonMessageTransformerInterface')

implementation group: 'com.google.guava', name: 'guava'
implementation group: 'org.slf4j', name: 'slf4j-api'
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-databind'
implementation group: 'com.fasterxml.jackson.core', name: 'jackson-core'
implementation group: 'org.codehaus.groovy', name: 'groovy-all', version: '3.0.13'
implementation group: "org.graalvm.js", name: 'js', version: "${graalVersion}"
implementation group: "org.graalvm.js", name: 'js-scriptengine', "version": "${graalVersion}"

testImplementation project(':TrafficCapture:trafficReplayer')
testImplementation project(':transformation:transformationPlugins:jsonMessageTransformers:jsonMessageTransformerLoaders')
testImplementation testFixtures(project(path: ':testHelperFixtures'))
testImplementation testFixtures(project(path: ':TrafficCapture:trafficReplayer'))

testImplementation group:'org.junit.jupiter', name:'junit-jupiter-api'
testImplementation group:'org.junit.jupiter', name:'junit-jupiter-params'
testImplementation group:'org.slf4j', name: 'slf4j-api'
testRuntimeOnly group:'org.junit.jupiter', name:'junit-jupiter-engine'
}

// Task to download LiquidJS
task downloadLiquidJs(type: Download) {
src 'https://cdn.jsdelivr.net/npm/liquidjs/dist/liquid.browser.min.js'
dest new File(projectDir, 'src/main/resources/liquid.min.js')
overwrite true
}

processResources.dependsOn downloadLiquidJs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package org.opensearch.migrations.transform;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.CompletableFuture;
import java.util.function.UnaryOperator;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.io.Resources;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Value;
import org.graalvm.polyglot.proxy.ProxyExecutable;
import org.graalvm.polyglot.proxy.ProxyObject;

@Slf4j
public class LiquidJSTransformer implements IJsonTransformer {

ObjectMapper objectMapper = new ObjectMapper();
private final Context context;
private final UnaryOperator<Map<String, Object>> bindingsProvider;

public LiquidJSTransformer(String templateString,
UnaryOperator<Map<String, Object>> bindingsProvider) throws IOException {
this.bindingsProvider = bindingsProvider;
this.context = Context.newBuilder("js")
.allowAllAccess(true)
.build();

context.getBindings("js").putMember("userProvidedTemplate", templateString);

// Load LiquidJS javascript script
var liquidJsContent = Resources.toString(Resources.getResource("liquid.min.js"), StandardCharsets.UTF_8);

// First evaluate the library
context.eval("js", liquidJsContent);

// Then use the global Liquid object that was created
context.eval("js", "" +
"const engine = new liquidjs.Liquid();"
+ "var parsedTemplate = engine.parse(userProvidedTemplate);"
);
}

public CompletableFuture<Object> transformJsonFuture(Map<String, Object> incomingJson) {
var userBindings = bindingsProvider.apply(incomingJson);
context.getBindings("js").putMember("incomingJson", ProxyObject.fromMap(userBindings));
Value promise = context.eval("js", "engine.render(parsedTemplate, incomingJson);");
return fromPromise(promise);
}

@SneakyThrows
public String runJavascript(Map<String, Object> incomingJson) {
context.getBindings("js").putMember("incomingJson", ProxyObject.fromMap(incomingJson));
var resultPromise = context.eval("js", "" +
"JSON.stringify(incomingJson);\n");
var resultStr = (String) fromPromise(resultPromise).get();
log.atTrace().setMessage("resultStr={}").addArgument(resultStr).log();
return resultStr;
}

@SneakyThrows
@Override
public Map<String, Object> transformJson(Map<String, Object> incomingJson) {
var resultStr = (String) transformJsonFuture(incomingJson).get();
log.atTrace().setMessage("resultStr={}").addArgument(resultStr).log();
var parsedObj = (Map<String,Object>) objectMapper.readValue(resultStr, LinkedHashMap.class);
return parsedObj;
}

@SuppressWarnings("Unchecked")
private static <T> CompletableFuture<T> fromPromise(Value value) {
CompletableFuture<T> future = new CompletableFuture<>();

if (value.canInvokeMember("then")) {
// It's a Promise - handle with then()
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/then
value.invokeMember("then",
(ProxyExecutable) onFulfilledArg -> {
T result = (T) onFulfilledArg[0].as(Object.class);
future.complete(result);
return null;
},
(ProxyExecutable) failureArgs -> {
Throwable error = new RuntimeException(failureArgs[0].toString());
future.completeExceptionally(error);
return null;
}
);
} else {
// It's a direct value - complete immediately
T result = (T) value.as(Object.class);
future.complete(result);
}
return future;
}
}
Loading

0 comments on commit b00c63b

Please sign in to comment.