rocketmq-commits mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From ding...@apache.org
Subject [rocketmq] branch graalvm updated: Graalvm expose an API for library file (#1167)
Date Fri, 19 Apr 2019 08:05:23 GMT
This is an automated email from the ASF dual-hosted git repository.

dinglei pushed a commit to branch graalvm
in repository https://gitbox.apache.org/repos/asf/rocketmq.git


The following commit(s) were added to refs/heads/graalvm by this push:
     new 382fb89  Graalvm expose an API for library file (#1167)
382fb89 is described below

commit 382fb89d88f7057615c13496839941ac4bb17cbf
Author: ziyilin <lin.ziyi@hotmail.com>
AuthorDate: Fri Apr 19 16:05:16 2019 +0800

    Graalvm expose an API for library file (#1167)
    
    * [graal] Successfully run with main method
    
    * [graal]Support build as a library
---
 client/native/rocketMQ.h                           |  15 ++
 client/pom.xml                                     |   6 +
 .../java/org/apache/rocketmq/client/Producer.java  | 177 ++++++++++++++++++---
 client/svm.sh                                      |  19 ++-
 4 files changed, 185 insertions(+), 32 deletions(-)

diff --git a/client/native/rocketMQ.h b/client/native/rocketMQ.h
new file mode 100644
index 0000000..51b363f
--- /dev/null
+++ b/client/native/rocketMQ.h
@@ -0,0 +1,15 @@
+#ifndef ROCKETMQ_H_
+#define ROCKETMQ_H_
+
+
+typedef struct Message_Send{
+  char* producer_name;
+  char* topic;
+  char* tags;
+  char* keys;
+  char* body;
+}Message_Send_Struct;
+
+
+
+#endif /* ROCKETMQ_H_ */
\ No newline at end of file
diff --git a/client/pom.xml b/client/pom.xml
index afa47c0..72c0454 100644
--- a/client/pom.xml
+++ b/client/pom.xml
@@ -33,6 +33,12 @@
     </properties>
 
     <dependencies>
+	    <!-- svm.jar is required to be manually installed first -->
+	    <dependency>
+	    <groupId>com.oracle.substratevm</groupId>
+	    <artifactId>svm</artifactId>
+	    <version>1.0.0-rc16-dev</version>
+	    </dependency>
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>rocketmq-common</artifactId>
diff --git a/client/src/main/java/org/apache/rocketmq/client/Producer.java b/client/src/main/java/org/apache/rocketmq/client/Producer.java
index ff87cd6..5f7d0b8 100644
--- a/client/src/main/java/org/apache/rocketmq/client/Producer.java
+++ b/client/src/main/java/org/apache/rocketmq/client/Producer.java
@@ -3,39 +3,164 @@ Main entry for building native image
 */
 package org.apache.rocketmq.client;
 
+import java.util.Collections;
+import java.util.List;
+
+import org.apache.rocketmq.client.Producer.CRocketMQDirectives;
 import org.apache.rocketmq.client.exception.MQClientException;
 import org.apache.rocketmq.client.producer.DefaultMQProducer;
 import org.apache.rocketmq.client.producer.SendResult;
 import org.apache.rocketmq.common.message.Message;
 import org.apache.rocketmq.remoting.common.RemotingHelper;
 
-import com.alibaba.fastjson.parser.ParserConfig;
+import org.graalvm.nativeimage.IsolateThread;
+import org.graalvm.nativeimage.c.CContext;
+import org.graalvm.nativeimage.c.function.CEntryPoint;
+import org.graalvm.nativeimage.c.struct.CField;
+import org.graalvm.nativeimage.c.struct.CStruct;
+import org.graalvm.nativeimage.c.type.CCharPointer;
+import org.graalvm.nativeimage.c.type.CTypeConversion;
+import org.graalvm.word.PointerBase;
 
-import io.netty.handler.logging.LoggingHandler;
-import io.netty.handler.logging.LogLevel;
+import com.alibaba.fastjson.parser.ParserConfig;
+import com.oracle.svm.core.c.ProjectHeaderFile;
 
+/**
+ * @CContext annotation tells this class providing the context to interact with
+ * C context. This is required to build as a SO library file, but not necessary to
+ * build an executable file.
+ * 
+ * @author cengfeng.lzy
+ *
+ */
+@CContext(CRocketMQDirectives.class)
 public class Producer {
-    private static final LoggingHandler log = new LoggingHandler(LogLevel.DEBUG);
-    public static void main(String[] args) throws MQClientException, InterruptedException
{
-    	ParserConfig.global.setAsmEnable(false);
-        DefaultMQProducer producer = new DefaultMQProducer("ProducerGroupName");
-        producer.start();
-
-        for (int i = 0; i < 128; i++)
-            try {
-                {
-                    Message msg = new Message("TopicTest",
-                        "TagA",
-                        "OrderID188",
-                        "Hello world".getBytes(RemotingHelper.DEFAULT_CHARSET));
-                    SendResult sendResult = producer.send(msg);
-                    System.out.printf("%s%n", sendResult);
-                }
-
-            } catch (Exception e) {
-                e.printStackTrace();
-            }
-
-        producer.shutdown();
-    }
+	static class CRocketMQDirectives implements CContext.Directives {
+
+		@Override
+		public List<String> getHeaderFiles() {
+			/*
+			 * The header file with the C declarations that are imported. Here we give the
+			 * name of the header file. SVM searches the header file according to the file
+			 * name specified here and the relative path specified in H:CLibraryPath in
+			 * option.
+			 */
+			return Collections.singletonList(ProjectHeaderFile.resolve("client", "rocketMQ.h"));
+		}
+	}
+
+	/**
+	 * This interface gives a Java version description of Message_Send_Struct data
+	 * structure defined in the C header file.
+	 * 
+	 * This declaration MUST be enclosed inside the @CContext class.
+	 *  
+	 * @author cengfeng.lzy
+	 *
+	 */
+	@CStruct("Message_Send_Struct")
+	interface CMessageSendStruct extends PointerBase {
+		@CField("producer_name")
+		CCharPointer getProducerName();
+
+		@CField("producer_name")
+		void setProducerName(CCharPointer value);
+
+		@CField("topic")
+		CCharPointer getTopic();
+
+		@CField("topic")
+		void setTopic(CCharPointer value);
+
+		@CField("tags")
+		CCharPointer getTags();
+
+		@CField("tags")
+		void setTags(CCharPointer value);
+
+		@CField("keys")
+		CCharPointer getKeys();
+
+		@CField("keys")
+		void setKeys(CCharPointer value);
+
+		@CField("body")
+		CCharPointer getBody();
+
+		@CField("body")
+		void setBody(CCharPointer value);
+	}
+
+	/**
+	 * This main method is used to generate an executable file by SVM.
+	 * @param args
+	 * @throws MQClientException
+	 * @throws InterruptedException
+	 */
+	public static void main(String[] args) throws MQClientException, InterruptedException {
+		ParserConfig.global.setAsmEnable(false);
+		DefaultMQProducer producer = new DefaultMQProducer("ProducerGroupName");
+		producer.start();
+
+		for (int i = 0; i < 128; i++)
+			try {
+				{
+					Message msg = new Message("TopicTest", "TagA", "OrderID188",
+							"Hello world".getBytes(RemotingHelper.DEFAULT_CHARSET));
+					SendResult sendResult = producer.send(msg);
+					System.out.printf("%s%n", sendResult);
+				}
+
+			} catch (Exception e) {
+				e.printStackTrace();
+			}
+
+		producer.shutdown();
+	}
+
+	/**
+	 * This example shows how to expose an API with complex data structure
+	 * parameter. This API wraps SendResult
+	 * org.apache.rocketmq.client.producer.DefaultMQProducer.send(Message msg)
+	 * 
+	 * @param thread        isolated thread is required by SVM
+	 * @param cmessageSends correspond to the Message_Send_Struct defined in the C
+	 *                      header file.
+	 * @return CCharPointer corresponds to char * in C
+	 */
+	@CEntryPoint(name = "send_message")
+	public static CCharPointer send(IsolateThread thread, CMessageSendStruct cmessageSends)
{
+		// Disable dynamic class generation and class loading in Fastjson
+		ParserConfig.global.setAsmEnable(false);
+		DefaultMQProducer producer = new DefaultMQProducer(
+				// Here shows how to get a char * to String
+				CTypeConversion.toJavaString(cmessageSends.getProducerName()));
+		try {
+			producer.start();
+		} catch (MQClientException e1) {
+			e1.printStackTrace();
+			// Here shows how to convert null to char *.
+			// As the returned value must be of WordBase type, but null is of Object type.
+			// So we cannot return a null directly, but have to convert it to a
+			// CCharPointer.
+			return CTypeConversion.toCString(null).get();
+		}
+
+		String topic = CTypeConversion.toJavaString(cmessageSends.getTopic()); // TopicTest
+		String tags = CTypeConversion.toJavaString(cmessageSends.getTags()); // TagA
+		String key = CTypeConversion.toJavaString(cmessageSends.getKeys()); // OrderID188
+		String body = CTypeConversion.toJavaString(cmessageSends.getBody()); // Hello world
+		try {
+			// Construct a Message instance from the data extracted from C structure.
+			Message msg = new Message(topic, tags, key, body.getBytes(RemotingHelper.DEFAULT_CHARSET));
+			SendResult sendResult = producer.send(msg);
+			// Return string contents in SendResult instance.
+			return CTypeConversion.toCString(sendResult.toString()).get();
+		} catch (Exception e) {
+			e.printStackTrace();
+			return CTypeConversion.toCString(null).get();
+		} finally {
+			producer.shutdown();
+		}
+	}
 }
diff --git a/client/svm.sh b/client/svm.sh
index e13cfcf..b56062d 100755
--- a/client/svm.sh
+++ b/client/svm.sh
@@ -7,9 +7,7 @@ SVM_OPT="${SVM_OPT} --delay-class-initialization-to-runtime=io.netty.handler.ssl
 SVM_OPT="${SVM_OPT} --delay-class-initialization-to-runtime=io.netty.handler.ssl.JdkAlpnSslEngine"
 SVM_OPT="${SVM_OPT} --delay-class-initialization-to-runtime=io.netty.util.internal.JavassistTypeParameterMatcherGenerator"
 SVM_OPT="${SVM_OPT} --delay-class-initialization-to-runtime=com.alibaba.fastjson.serializer.JodaCodec"
-# testing
-#SVM_OPT="${SVM_OPT} --delay-class-initialization-to-runtime=io.netty.handler.ssl.util.SelfSignedCertificate"
-#SVM_OPT="${SVM_OPT} --delay-class-initialization-to-runtime=io.netty.handler.ssl.util.ThreadLocalInsecureRandom"
+
 SVM_OPT="${SVM_OPT} --rerun-class-initialization-at-runtime=io.netty.handler.ssl.util.SelfSignedCertificate"
 SVM_OPT="${SVM_OPT} --rerun-class-initialization-at-runtime=io.netty.handler.ssl.util.ThreadLocalInsecureRandom"
 SVM_OPT="${SVM_OPT} --rerun-class-initialization-at-runtime=com.alibaba.fastjson.serializer.SerializeConfig"
@@ -18,7 +16,16 @@ SVM_OPT="${SVM_OPT} --rerun-class-initialization-at-runtime=com.alibaba.fastjson
 SVM_OPT="${SVM_OPT} --enable-url-protocols=http"
 
 WORKDIR=`pwd`
-CONFIG_OPT="-H:ConfigurationFileDirectories=${WORKDIR}/config -Dio.netty.noUnsafe=true -H:+ReportExceptionStackTraces
--allow-incomplete-classpath"
-native_image=/home/cengfeng.lzy/GraalDev/graal/vm/mxbuild/linux-amd64/GRAALVM_LIBGRAAL/graalvm-libgraal-1.0.0-rc16-dev/bin/native-image
-#native_image=~/tools/graalvm-ce-1.0.0-rc14/bin/native-image
+CONFIG_OPT="-H:ConfigurationFileDirectories=${WORKDIR}/config  -H:+ReportExceptionStackTraces
--allow-incomplete-classpath"
+
+#Disable unsafe usage in netty. This option is provided by netty, not an univeral solution.
A more general way
+#is to use Graal's substition mechenism (see "Unsafe memory access" in 
+#https://medium.com/graalvm/instant-netty-startup-using-graalvm-native-image-generation-ed6f14ff7692)
+CONFIG_OPT="${CONFIG_OPT} -Dio.netty.noUnsafe=true"
+#Compile to a SO file
+CONFIG_OPT="${CONFIG_OPT} --shared -H:Name=rocketMQClient"
+#Specify where is the C library file which defines the data structure used in exposed API.

+CONFIG_OPT="${CONFIG_OPT} -H:CLibraryPath=native"
+
+#Set your own $native_image enviroment variable which should refer to the bin\native-image
file in your graalvm JDK. 
 $native_image  $CONFIG_OPT $SVM_OPT  -jar target/rocketmq-client-4.5.1-SNAPSHOT-jar-with-dependencies.jar


Mime
View raw message