diff --git a/README.md b/README.md index 044f00a63..9770cb2ca 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,16 @@ +# AWS Lambda Libs on CRaC + +This is a version of the original AWS Lambda Libraries with CRaC support added. + +To use, add next to the pom.xml: +``` + + io.github.crac.com.amazonaws + aws-lambda-java-runtime-interface-client + 2.2.0 + +``` + # AWS Lambda Java Support Libraries Key libraries for running Java on the AWS Lambda platform. diff --git a/aws-lambda-java-runtime-interface-client/pom.xml b/aws-lambda-java-runtime-interface-client/pom.xml index 8de738de6..f4742283e 100644 --- a/aws-lambda-java-runtime-interface-client/pom.xml +++ b/aws-lambda-java-runtime-interface-client/pom.xml @@ -2,7 +2,7 @@ xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd"> 4.0.0 - com.amazonaws + io.github.crac.com.amazonaws aws-lambda-java-runtime-interface-client 2.2.0 jar @@ -20,9 +20,15 @@ - https://github.com/aws/aws-lambda-java-libs.git + http://github.com/CRaC/aws-lambda-java-libs/tree/master + + antonkozlov + Anton Kozlov + https://github.com/AntonKozlov + akozlov@azul.com + AWS Lambda team Amazon Web Services @@ -53,6 +59,11 @@ aws-lambda-java-core 1.2.2 + + io.github.crac + org-crac + 0.1.0 + com.amazonaws aws-lambda-java-serialization @@ -258,8 +269,8 @@ 1.6.3 true - sonatype-nexus-staging - https://aws.oss.sonatype.org/ + ossrh + https://s01.oss.sonatype.org/ false diff --git a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/LambdaRuntimeClient.java b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/LambdaRuntimeClient.java index 05aa50a1b..b623bdb91 100644 --- a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/LambdaRuntimeClient.java +++ b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/LambdaRuntimeClient.java @@ -38,11 +38,11 @@ public LambdaRuntimeClient(String hostnamePort) { } public InvocationRequest waitForNextInvocation() { - return NativeClient.next(); + return NativeClient.nextWrapper(); } public void postInvocationResponse(String requestId, byte[] response) { - NativeClient.postInvocationResponse(requestId.getBytes(UTF_8), response); + NativeClient.postInvocationResponseWrapper(requestId.getBytes(UTF_8), response); } public void postInvocationError(String requestId, byte[] errorResponse, String errorType) throws IOException { diff --git a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/NativeClient.java b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/NativeClient.java index a9592e1a8..3a6378170 100644 --- a/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/NativeClient.java +++ b/aws-lambda-java-runtime-interface-client/src/main/java/com/amazonaws/services/lambda/runtime/api/client/runtimeapi/NativeClient.java @@ -2,8 +2,13 @@ package com.amazonaws.services.lambda.runtime.api.client.runtimeapi; +import org.crac.Context; +import org.crac.Resource; + import java.io.InputStream; +import java.lang.annotation.Native; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; import java.nio.file.StandardCopyOption; @@ -22,10 +27,67 @@ class NativeClient { "aws-lambda-runtime-interface-client.musl.so", }; private static final Throwable[] exceptions = new Throwable[libsToTry.length]; + + static class CheckpointState implements Resource { + enum State { + WORKING, + SYNCING, + SYNCED, + }; + + State state = State.WORKING; + + private void waitFor(State targetState) { + while (state != targetState) { + try { + this.wait(); + } catch (InterruptedException interruptedException) { + } + } + } + + @Override + public synchronized void beforeCheckpoint(Context context) throws Exception { + state = State.SYNCING; + waitFor(State.SYNCED); + deinitializeClient(); + } + + @Override + public synchronized void afterRestore(Context context) throws Exception { + initializeNativeClient(); + state = State.WORKING; + this.notifyAll(); + } + + public synchronized void syncPoint() { + if (state == State.SYNCING) { + state = State.SYNCED; + this.notifyAll(); + } + waitFor(State.WORKING); + } + } + + static CheckpointState checkpointState = new CheckpointState(); static { - boolean loaded = false; - for (int i = 0; !loaded && i < libsToTry.length; ++i) { - try (InputStream lib = NativeClient.class.getResourceAsStream( + boolean loaded = false; + String basestr = System.getProperty("com.amazonaws.services.lambda.runtime.api.client.NativeClient.libsBase", "/"); + Path base = Paths.get(basestr); + for (int i = 0; !loaded && i < libsToTry.length; ++i) { + Path p = base.resolve(libsToTry[i]); + if (Files.exists(p)) { + try { + System.load(p.toString()); + loaded = true; + } catch (UnsatisfiedLinkError e) { + exceptions[i] = e; + } catch (Exception e) { + exceptions[i] = e; + } + } + if (!loaded && exceptions[i] == null) { + try (InputStream lib = NativeClient.class.getResourceAsStream("/" + Paths.get(architecturePathSuffix, libsToTry[i]).toString())) { Files.copy(lib, Paths.get(nativeLibPath), StandardCopyOption.REPLACE_EXISTING); System.load(nativeLibPath); @@ -36,17 +98,25 @@ class NativeClient { exceptions[i] = e; } } - if (!loaded) { - for (int i = 0; i < libsToTry.length; ++i) { - System.err.printf("Failed to load the native runtime interface client library %s. Exception: %s\n", libsToTry[i], exceptions[i].getMessage()); - } - System.exit(-1); + } + + if (!loaded) { + for (int i = 0; i < libsToTry.length; ++i) { + System.err.print(exceptions[i]); + System.err.printf("Failed to load the native runtime interface client library %s. Exception: %s\n", libsToTry[i], exceptions[i].getMessage()); } - String userAgent = String.format( - "aws-lambda-java/%s-%s" , - System.getProperty("java.vendor.version"), - NativeClient.class.getPackage().getImplementationVersion()); - initializeClient(userAgent.getBytes()); + System.exit(-1); + } + initializeNativeClient(); + org.crac.Core.getGlobalContext().register(checkpointState); + } + + private static void initializeNativeClient() { + String userAgent = String.format( + "aws-lambda-java/%s-%s" , + System.getProperty("java.vendor.version"), + NativeClient.class.getPackage().getImplementationVersion()); + initializeClient(userAgent.getBytes()); } /** @@ -67,7 +137,18 @@ static String getArchIdentifier() { static native void initializeClient(byte[] userAgent); - static native InvocationRequest next(); + private static native InvocationRequest next(); + + static InvocationRequest nextWrapper() { + return next(); + } + + private static native void postInvocationResponse(byte[] requestId, byte[] response); + + static void postInvocationResponseWrapper(byte[] requestId, byte[] response) { + postInvocationResponse(requestId, response); + checkpointState.syncPoint(); + } - static native void postInvocationResponse(byte[] requestId, byte[] response); + static native void deinitializeClient(); } diff --git a/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.cpp b/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.cpp index 87fa9f028..240a8a795 100644 --- a/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.cpp +++ b/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.cpp @@ -149,3 +149,9 @@ JNIEXPORT void JNICALL Java_com_amazonaws_services_lambda_runtime_api_client_run throwLambdaRuntimeClientException(env, errorMessage, outcome.get_failure()); } } + +JNIEXPORT void JNICALL Java_com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient_deinitializeClient(JNIEnv *env, jobject thisObject) { + delete CLIENT; + CLIENT = NULL; +} + diff --git a/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.h b/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.h index 28a6f444a..47d1265df 100644 --- a/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.h +++ b/aws-lambda-java-runtime-interface-client/src/main/jni/com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient.h @@ -15,6 +15,9 @@ JNIEXPORT jobject JNICALL Java_com_amazonaws_services_lambda_runtime_api_client_ JNIEXPORT void JNICALL Java_com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient_postInvocationResponse (JNIEnv *, jobject, jbyteArray, jbyteArray); +JNIEXPORT void JNICALL Java_com_amazonaws_services_lambda_runtime_api_client_runtimeapi_NativeClient_deinitializeClient + (JNIEnv *, jobject); + #ifdef __cplusplus } #endif