This is an automated email from the ASF dual-hosted git repository.
mmerli pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/bookkeeper.git
The following commit(s) were added to refs/heads/master by this push:
new bcccea06e BP-47 (task1): Add native IO library support (#3189)
bcccea06e is described below
commit bcccea06e4aab38925dfd28824fdb046825123f9
Author: Hang Chen <[email protected]>
AuthorDate: Mon Apr 11 07:49:39 2022 +0800
BP-47 (task1): Add native IO library support (#3189)
* Add native io library support
* fix jni compile issue
* fix findbugs failed
---
native-io/build.gradle | 42 ++++
native-io/pom.xml | 220 +++++++++++++++++++
native-io/src/main/assembly/assembly.xml | 62 ++++++
.../bookkeeper/common/util/nativeio/NativeIO.java | 61 ++++++
.../common/util/nativeio/NativeIOException.java | 46 ++++
.../common/util/nativeio/NativeIOImpl.java | 72 +++++++
.../common/util/nativeio/NativeIOJni.java | 62 ++++++
.../common/util/nativeio/NativeUtils.java | 83 ++++++++
.../common/util/nativeio/package-info.java | 22 ++
native-io/src/main/native-io-jni/build.gradle | 48 +++++
.../src/main/native-io-jni/cpp/native_io_jni.c | 232 +++++++++++++++++++++
pom.xml | 1 +
12 files changed, 951 insertions(+)
diff --git a/native-io/build.gradle b/native-io/build.gradle
new file mode 100644
index 000000000..b680940c8
--- /dev/null
+++ b/native-io/build.gradle
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+plugins {
+ id 'java'
+}
+
+dependencies {
+ compileOnly depLibs.lombok
+ compileOnly depLibs.spotbugsAnnotations
+ implementation depLibs.commonsLang3
+ implementation depLibs.guava
+ implementation depLibs.slf4j
+ testImplementation depLibs.junit
+
+ annotationProcessor depLibs.lombok
+}
+
+compileJava {
+ options.headerOutputDirectory = file("${buildDir}/javahGenerated")
+}
+
+jar {
+ from
(tasks.getByPath(":native-io:src:main:native-io-jni:linkRelease").outputs.files.filter
{ f -> f.isFile()} ) {
+ into "/lib"
+ }
+}
diff --git a/native-io/pom.xml b/native-io/pom.xml
new file mode 100644
index 000000000..8ba378dd0
--- /dev/null
+++ b/native-io/pom.xml
@@ -0,0 +1,220 @@
+<!--
+ Licensed to the Apache Software Foundation (ASF) under one or more
+ contributor license agreements. See the NOTICE file distributed with
+ this work for additional information regarding copyright ownership.
+ The ASF licenses this file to You under the Apache License, Version 2.0
+ (the "License"); you may not use this file except in compliance with
+ the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0
http://maven.apache.org/xsd/maven-4.0.0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <parent>
+ <groupId>org.apache.bookkeeper</groupId>
+ <artifactId>bookkeeper</artifactId>
+ <version>4.16.0-SNAPSHOT</version>
+ <relativePath>..</relativePath>
+ </parent>
+
+ <artifactId>native-io</artifactId>
+ <packaging>nar</packaging>
+ <name>Apache BookKeeper :: Native IO Library</name>
+ <description>Native IO Library</description>
+
+ <properties>
+ <nar.runtime>dynamic</nar.runtime>
+ </properties>
+
+ <dependencies>
+ <dependency>
+ <groupId>com.google.guava</groupId>
+ <artifactId>guava</artifactId>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.commons</groupId>
+ <artifactId>commons-lang3</artifactId>
+ </dependency>
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <configuration>
+ <source>1.8</source>
+ <target>1.8</target>
+ <compilerArgs>
+ <!-- Object.finalize() is deprecated at java 9 -->
+ <!-- <compilerArg>-Werror</compilerArg> -->
+ <compilerArg>-Xlint:deprecation</compilerArg>
+ <compilerArg>-Xlint:unchecked</compilerArg>
+ <!-- https://issues.apache.org/jira/browse/MCOMPILER-205 -->
+ <compilerArg>-Xpkginfo:always</compilerArg>
+ </compilerArgs>
+ </configuration>
+ </plugin>
+ <plugin>
+ <groupId>com.github.maven-nar</groupId>
+ <artifactId>nar-maven-plugin</artifactId>
+ <version>${nar-maven-plugin.version}</version>
+ <extensions>true</extensions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-assembly-plugin</artifactId>
+ <version>${maven-assembly-plugin.version}</version>
+ <configuration>
+ <descriptors>
+ <descriptor>src/main/assembly/assembly.xml</descriptor>
+ </descriptors>
+ <appendAssemblyId>false</appendAssemblyId>
+ <tarLongFileMode>posix</tarLongFileMode>
+ </configuration>
+ <executions>
+ <execution>
+ <id>make-assembly</id>
+ <phase>package</phase>
+ <goals>
+ <goal>single</goal>
+ </goals>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.rat</groupId>
+ <artifactId>apache-rat-plugin</artifactId>
+ </plugin>
+ </plugins>
+ </build>
+
+ <profiles>
+ <profile>
+ <!-- from JDK10 javah command is not available
+ see http://openjdk.java.net/jeps/313
+ -->
+ <id>jdk-without-javah</id>
+ <activation>
+ <jdk>[10,)</jdk>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>com.github.maven-nar</groupId>
+ <artifactId>nar-maven-plugin</artifactId>
+ <version>${nar-maven-plugin.version}</version>
+ <extensions>true</extensions>
+ <executions>
+ <execution>
+ <!-- javah is not present in JDK10 onwards,
+ you have to to use javac -h -->
+ <id>default-nar-javah</id>
+ <phase>none</phase>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>${maven-compiler-plugin.version}</version>
+ <configuration>
+ <source>1.8</source>
+ <target>1.8</target>
+ <compilerArgs>
+ <!-- Object.finalize() is deprecated at java 9 -->
+ <!-- <compilerArg>-Werror</compilerArg> -->
+ <compilerArg>-Xlint:deprecation</compilerArg>
+ <compilerArg>-Xlint:unchecked</compilerArg>
+ <!-- https://issues.apache.org/jira/browse/MCOMPILER-205 -->
+ <compilerArg>-Xpkginfo:always</compilerArg>
+ <!-- add -h flag to javac -->
+ <compilerArg>-h</compilerArg>
+
<compilerArg>${project.build.directory}/nar/javah-include</compilerArg>
+ </compilerArgs>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ <profile>
+ <id>mac</id>
+ <activation>
+ <os>
+ <name>Mac OS X</name>
+ </os>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>com.github.maven-nar</groupId>
+ <artifactId>nar-maven-plugin</artifactId>
+ <version>${nar-maven-plugin.version}</version>
+ <extensions>true</extensions>
+ <configuration>
+ <runtime>${nar.runtime}</runtime>
+ <output>native-io</output>
+ <libraries>
+ <library>
+ <type>jni</type>
+
<narSystemPackage>org.apache.bookkeeper.util.nativeio</narSystemPackage>
+ </library>
+ </libraries>
+ <cpp>
+ <optionSet>${nar.cpp.optionSet}</optionSet>
+ <exceptions>false</exceptions>
+ <rtti>false</rtti>
+ <optimize>full</optimize>
+ </cpp>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+
+ <profile>
+ <id>Linux</id>
+ <activation>
+ <os>
+ <name>Linux</name>
+ </os>
+ </activation>
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>com.github.maven-nar</groupId>
+ <artifactId>nar-maven-plugin</artifactId>
+ <version>${nar-maven-plugin.version}</version>
+ <extensions>true</extensions>
+ <configuration>
+ <runtime>${nar.runtime}</runtime>
+ <output>native-io</output>
+ <libraries>
+ <library>
+ <type>jni</type>
+
<narSystemPackage>org.apache.bookkeeper.util.nativeio</narSystemPackage>
+ </library>
+ </libraries>
+ <cpp>
+ <optionSet>${nar.cpp.optionSet}</optionSet>
+ <exceptions>false</exceptions>
+ <rtti>false</rtti>
+ <optimize>full</optimize>
+ </cpp>
+ <linker>
+ <libSet>rt</libSet>
+ </linker>
+ </configuration>
+ </plugin>
+ </plugins>
+ </build>
+ </profile>
+ </profiles>
+
+</project>
diff --git a/native-io/src/main/assembly/assembly.xml
b/native-io/src/main/assembly/assembly.xml
new file mode 100644
index 000000000..377b97ff5
--- /dev/null
+++ b/native-io/src/main/assembly/assembly.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+ Licensed to the Apache Software Foundation (ASF) under one
+ or more contributor license agreements. See the NOTICE file
+ distributed with this work for additional information
+ regarding copyright ownership. The ASF licenses this file
+ to you under the Apache License, Version 2.0 (the
+ "License"); you may not use this file except in compliance
+ with the License. You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing,
+ software distributed under the License is distributed on an
+ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ KIND, either express or implied. See the License for the
+ specific language governing permissions and limitations
+ under the License.
+
+-->
+<assembly>
+ <id>all</id>
+ <formats>
+ <format>jar</format>
+ </formats>
+
+ <includeBaseDirectory>false</includeBaseDirectory>
+ <fileSets>
+ <fileSet>
+
<directory>${project.build.directory}/nar/${project.artifactId}-${project.version}-${os.arch}-MacOSX-gpp-jni/lib/${os.arch}-MacOSX-gpp/jni
+ </directory>
+ <outputDirectory>lib</outputDirectory>
+ <includes>
+ <include>lib*</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+
<directory>${project.build.directory}/nar/${project.artifactId}-${project.version}-${os.arch}-Linux-gpp-jni/lib/${os.arch}-Linux-gpp/jni
+ </directory>
+ <outputDirectory>lib</outputDirectory>
+ <includes>
+ <include>lib*</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+
<directory>${project.build.directory}/nar/${project.artifactId}-${project.version}-${os.arch}-${os.name}-gpp-jni/lib/${os.arch}-${os.name}-gpp/jni
+ </directory>
+ <outputDirectory>lib</outputDirectory>
+ <includes>
+ <include>lib*</include>
+ </includes>
+ </fileSet>
+ <fileSet>
+
<directory>${project.build.directory}/classes</directory>
+ <outputDirectory></outputDirectory>
+ <includes>
+ <include>**/*</include>
+ </includes>
+ </fileSet>
+ </fileSets>
+</assembly>
diff --git
a/native-io/src/main/java/org/apache/bookkeeper/common/util/nativeio/NativeIO.java
b/native-io/src/main/java/org/apache/bookkeeper/common/util/nativeio/NativeIO.java
new file mode 100644
index 000000000..562b957ff
--- /dev/null
+++
b/native-io/src/main/java/org/apache/bookkeeper/common/util/nativeio/NativeIO.java
@@ -0,0 +1,61 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.bookkeeper.common.util.nativeio;
+
+/**
+ * NativeIO API.
+ */
+public interface NativeIO {
+
+ // These constants are different per each OS, so the correct values are
defined in JNI code
+ int O_CREAT = 0x01;
+ int O_RDONLY = 0x02;
+ int O_WRONLY = 0x04;
+ int O_TRUNC = 0x08;
+ int O_DIRECT = 0x10;
+ int O_DSYNC = 0x20;
+
+ int SEEK_SET = 0;
+ int SEEK_END = 2;
+
+ int FALLOC_FL_ZERO_RANGE = 0x10;
+
+ int open(String pathname, int flags, int mode) throws NativeIOException;
+
+ int fsync(int fd) throws NativeIOException;
+
+ /**
+ * fallocate is a linux-only syscall, so callers must handle the
possibility that it does
+ * not exist.
+ */
+ int fallocate(int fd, int mode, long offset, long len) throws
NativeIOException;
+
+ int pwrite(int fd, long pointer, int count, long offset) throws
NativeIOException;
+
+ long posix_memalign(int alignment, int size) throws NativeIOException;
+
+ void free(long pointer) throws NativeIOException;
+
+ long lseek(int fd, long offset, int whence) throws NativeIOException;
+
+ long pread(int fd, long pointer, long size, long offset) throws
NativeIOException;
+
+ int close(int fd) throws NativeIOException;
+}
diff --git
a/native-io/src/main/java/org/apache/bookkeeper/common/util/nativeio/NativeIOException.java
b/native-io/src/main/java/org/apache/bookkeeper/common/util/nativeio/NativeIOException.java
new file mode 100644
index 000000000..f32765876
--- /dev/null
+++
b/native-io/src/main/java/org/apache/bookkeeper/common/util/nativeio/NativeIOException.java
@@ -0,0 +1,46 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+
+package org.apache.bookkeeper.common.util.nativeio;
+
+import java.io.IOException;
+
+/**
+ * NativeIOException.
+ */
+public class NativeIOException extends IOException {
+
+ private final int errno;
+
+ public NativeIOException(String message) {
+ super(message);
+ this.errno = -1;
+ }
+
+ public NativeIOException(String message, int errno) {
+ super(message + " - errno=" + errno);
+ this.errno = errno;
+ }
+
+ public int getErrno() {
+ return errno;
+ }
+}
diff --git
a/native-io/src/main/java/org/apache/bookkeeper/common/util/nativeio/NativeIOImpl.java
b/native-io/src/main/java/org/apache/bookkeeper/common/util/nativeio/NativeIOImpl.java
new file mode 100644
index 000000000..b42155bb1
--- /dev/null
+++
b/native-io/src/main/java/org/apache/bookkeeper/common/util/nativeio/NativeIOImpl.java
@@ -0,0 +1,72 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.bookkeeper.common.util.nativeio;
+
+/**
+ * NativeIOImpl.
+ */
+public class NativeIOImpl implements NativeIO {
+ @Override
+ public int open(String pathname, int flags, int mode) throws
NativeIOException {
+ int res = NativeIOJni.open(pathname, flags, mode);
+ return res;
+ }
+
+ @Override
+ public int fsync(int fd) throws NativeIOException {
+ return NativeIOJni.fsync(fd);
+ }
+
+ @Override
+ public int fallocate(int fd, int mode, long offset, long len) throws
NativeIOException {
+ return NativeIOJni.fallocate(fd, mode, offset, len);
+ }
+
+ @Override
+ public long lseek(int fd, long offset, int whence) throws
NativeIOException {
+ return NativeIOJni.lseek(fd, offset, whence);
+ }
+
+ @Override
+ public int close(int fd) throws NativeIOException {
+ return NativeIOJni.close(fd);
+ }
+
+ @Override
+ public int pwrite(int fd, long pointer, int count, long offset) throws
NativeIOException {
+ return NativeIOJni.pwrite(fd, pointer, count, offset);
+ }
+
+ @Override
+ public long posix_memalign(int alignment, int size) throws
NativeIOException {
+ return NativeIOJni.posix_memalign(alignment, size);
+ }
+
+ @Override
+ public void free(long pointer) throws NativeIOException {
+ NativeIOJni.free(pointer);
+ }
+
+ @Override
+ public long pread(int fd, long pointer, long size, long offset) throws
NativeIOException {
+ return NativeIOJni.pread(fd, pointer, size, offset);
+ }
+}
diff --git
a/native-io/src/main/java/org/apache/bookkeeper/common/util/nativeio/NativeIOJni.java
b/native-io/src/main/java/org/apache/bookkeeper/common/util/nativeio/NativeIOJni.java
new file mode 100644
index 000000000..667a4008e
--- /dev/null
+++
b/native-io/src/main/java/org/apache/bookkeeper/common/util/nativeio/NativeIOJni.java
@@ -0,0 +1,62 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+package org.apache.bookkeeper.common.util.nativeio;
+
+import org.apache.commons.lang3.SystemUtils;
+
+class NativeIOJni {
+
+ static native int open(String pathname, int flags, int mode) throws
NativeIOException;
+
+ static native int fsync(int fd) throws NativeIOException;
+
+ /**
+ * fallocate is a linux-only syscall, so callers must handle the
possibility that it does
+ * not exist.
+ */
+ static native int fallocate(int fd, int mode, long offset, long len)
throws NativeIOException;
+
+ static native int pwrite(int fd, long pointer, int count, long offset)
throws NativeIOException;
+
+ static native long posix_memalign(int alignment, int size) throws
NativeIOException;
+
+ static native void free(long pointer) throws NativeIOException;
+
+ static native long lseek(int fd, long offset, int whence) throws
NativeIOException;
+
+ static native long pread(int fd, long pointer, long size, long offset)
throws NativeIOException;
+
+ static native int close(int fd) throws NativeIOException;
+
+ static {
+ try {
+ if (SystemUtils.IS_OS_MAC_OSX) {
+ NativeUtils.loadLibraryFromJar("/lib/libnative-io-jni.dylib");
+ } else if (SystemUtils.IS_OS_LINUX) {
+ NativeUtils.loadLibraryFromJar("/lib/libnative-io-jni.so");
+ } else {
+ throw new RuntimeException("OS not supported by Native-IO
utils");
+ }
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+}
diff --git
a/native-io/src/main/java/org/apache/bookkeeper/common/util/nativeio/NativeUtils.java
b/native-io/src/main/java/org/apache/bookkeeper/common/util/nativeio/NativeUtils.java
new file mode 100644
index 000000000..d3c83f118
--- /dev/null
+++
b/native-io/src/main/java/org/apache/bookkeeper/common/util/nativeio/NativeUtils.java
@@ -0,0 +1,83 @@
+/**
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ * <p>
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * <p>
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+package org.apache.bookkeeper.common.util.nativeio;
+
+import static com.google.common.base.Preconditions.checkArgument;
+
+import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
+
+import java.io.File;
+import java.io.FileNotFoundException;
+import java.io.FileOutputStream;
+import java.io.InputStream;
+import java.io.OutputStream;
+import java.nio.file.Files;
+
+import lombok.experimental.UtilityClass;
+
+/**
+ * Utility class to load jni library from inside a JAR.
+ */
+@UtilityClass
+class NativeUtils {
+ /**
+ * loads given library from the this jar. ie: this jar contains:
/lib/pulsar-checksum.jnilib
+ *
+ * @param path
+ * : absolute path of the library in the jar <br/>
+ * if this jar contains: /lib/pulsar-checksum.jnilib then
provide the same absolute path as input
+ * @throws Exception
+ */
+ @SuppressFBWarnings(
+ value = "OBL_UNSATISFIED_OBLIGATION",
+ justification = "work around for java 9:
https://github.com/spotbugs/spotbugs/issues/493")
+ static void loadLibraryFromJar(String path) throws Exception {
+ checkArgument(path.startsWith("/"), "absolute path must start with /");
+
+ String[] parts = path.split("/");
+ checkArgument(parts.length > 0, "absolute path must contain file
name");
+
+ String filename = parts[parts.length - 1];
+
+ File dir = Files.createTempDirectory("native").toFile();
+ dir.deleteOnExit();
+ File temp = new File(dir, filename);
+ temp.deleteOnExit();
+
+ byte[] buffer = new byte[1024];
+ int read;
+
+ try (InputStream input = NativeUtils.class.getResourceAsStream(path);
+ OutputStream out = new FileOutputStream(temp)) {
+ if (input == null) {
+ throw new FileNotFoundException("Couldn't find file into jar "
+ path);
+ }
+
+ while ((read = input.read(buffer)) != -1) {
+ out.write(buffer, 0, read);
+ }
+ }
+
+ if (!temp.exists()) {
+ throw new FileNotFoundException("Failed to copy file from jar at "
+ temp.getAbsolutePath());
+ }
+
+ System.load(temp.getAbsolutePath());
+ }
+}
diff --git
a/native-io/src/main/java/org/apache/bookkeeper/common/util/nativeio/package-info.java
b/native-io/src/main/java/org/apache/bookkeeper/common/util/nativeio/package-info.java
new file mode 100644
index 000000000..d215e4708
--- /dev/null
+++
b/native-io/src/main/java/org/apache/bookkeeper/common/util/nativeio/package-info.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * Utiltiies to access I/O using JNI.
+ */
+package org.apache.bookkeeper.common.util.nativeio;
diff --git a/native-io/src/main/native-io-jni/build.gradle
b/native-io/src/main/native-io-jni/build.gradle
new file mode 100644
index 000000000..6a65b161e
--- /dev/null
+++ b/native-io/src/main/native-io-jni/build.gradle
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+import org.gradle.internal.jvm.Jvm
+
+plugins {
+ id 'cpp-library'
+}
+
+library {
+ binaries.configureEach { CppBinary binary ->
+ def compileTask = binary.compileTask.get()
+ compileTask.dependsOn project(':native-io').compileJava
+ compileTask.includes.from("${Jvm.current().javaHome}/include",
+
project(':native-io').compileJava.options.headerOutputDirectory)
+
+ def osFamily =
binary.targetPlatform.targetMachine.operatingSystemFamily
+
+ if (osFamily.linux) {
+
compileTask.includes.from("${Jvm.current().javaHome}/include/linux")
+ compileTask.macros.put("_GNU_SOURCE", "1")
+ } else if (osFamily.macOs) {
+
compileTask.includes.from("${Jvm.current().javaHome}/include/darwin")
+ }
+
+ compileTask.includes.from("${Jvm.current().javaHome}/include/linux")
+ compileTask.includes.from("${Jvm.current().javaHome}/include/darwin")
+ compileTask.source.from fileTree(dir: "cpp", include: "**/*.c")
+
+ compileTask.compilerArgs.addAll(["-x", "c", "-std=c11"])
+ }
+}
+
diff --git a/native-io/src/main/native-io-jni/cpp/native_io_jni.c
b/native-io/src/main/native-io-jni/cpp/native_io_jni.c
new file mode 100644
index 000000000..4b90a2d2e
--- /dev/null
+++ b/native-io/src/main/native-io-jni/cpp/native_io_jni.c
@@ -0,0 +1,232 @@
+/**
+ *
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ *
+ */
+#define _GNU_SOURCE
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include <org_apache_bookkeeper_common_util_nativeio_NativeIOJni.h>
+
+static void throwExceptionWithErrno(JNIEnv* env, const char* message) {
+ char err_msg[1024];
+ strerror_r(errno, err_msg, sizeof(err_msg));
+ unsigned long size = strlen(message) + strlen(err_msg) + 10;
+ char* str = malloc(size);
+ snprintf(str, size, "%s: %s", message, err_msg);
+
+ jstring javaMessage = (*env)->NewStringUTF(env, str);
+ free(str);
+
+ jclass clazz = (*env)->FindClass(env,
"org/apache/bookkeeper/common/util/nativeio/NativeIOException");
+ jmethodID ctorMethod = (*env)->GetMethodID(env, clazz, "<init>",
"(Ljava/lang/String;I)V");
+ jobject myException = (*env)->NewObject(env, clazz, ctorMethod,
javaMessage, errno);
+ (*env)->Throw(env, myException);
+}
+
+static void throwException(JNIEnv* env, const char* message) {
+ (*env)->ThrowNew(env, (*env)->FindClass(env,
"org/apache/bookkeeper/common/util/nativeio/NativeIOException"), message);
+}
+
+/*
+ * Class: org_apache_bookkeeper_common_util_nativeio_NativeIOJni
+ * Method: open
+ * Signature: (Ljava/lang/String;II)I
+ */
+JNIEXPORT jint JNICALL
+Java_org_apache_bookkeeper_common_util_nativeio_NativeIOJni_open(
+ JNIEnv *env, jclass clazz, jstring path, jint javaFlags, jint mode) {
+ const char *cPath = (*env)->GetStringUTFChars(env, path, 0);
+
+ int flags = 0;
+ if (javaFlags & 0x01) {
+ flags |= O_CREAT;
+ }
+
+ if (javaFlags & 0x02) {
+ flags |= O_RDONLY;
+ }
+
+ if (javaFlags & 0x04) {
+ flags |= O_WRONLY;
+ }
+
+ if (javaFlags & 0x08) {
+ flags |= O_TRUNC;
+ }
+
+#ifdef __linux__
+ if (javaFlags & 0x10) {
+ flags |= O_DIRECT;
+ }
+#endif
+
+ if (javaFlags & 0x20) {
+ flags |= O_DSYNC;
+ }
+
+ int fd = open(cPath, flags, mode);
+
+ (*env)->ReleaseStringUTFChars(env, path, cPath);
+
+ if (fd == -1) {
+ throwExceptionWithErrno(env, "Failed to open file");
+ }
+
+ return fd;
+}
+
+/*
+ * Class: org_apache_bookkeeper_common_util_nativeio_NativeIOJni
+ * Method: fsync
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_org_apache_bookkeeper_common_util_nativeio_NativeIOJni_fsync(JNIEnv * env,
+ jclass clazz,
+ jint fd) {
+ int res = fsync(fd);
+
+ if (res == -1) {
+ throwExceptionWithErrno(env, "Failed to fsync");
+ }
+
+ return res;
+}
+
+/*
+ * Class: org_apache_bookkeeper_common_util_nativeio_NativeIOJni
+ * Method: fallocate
+ * Signature: (IIJJ)I
+ */
+JNIEXPORT jint JNICALL
+Java_org_apache_bookkeeper_common_util_nativeio_NativeIOJni_fallocate(
+ JNIEnv* env, jclass clazz,
+ jint fd, jint mode, jlong offset, jlong len) {
+#ifdef __linux__
+ int res = fallocate(fd, mode, offset, len);
+ if (res == -1) {
+ throwExceptionWithErrno(env, "Failed to fallocate");
+ }
+ return res;
+#else
+ throwException(env, "fallocate is not available");
+ return -1;
+#endif
+}
+
+/*
+ * Class: org_apache_bookkeeper_common_util_nativeio_NativeIOJni
+ * Method: lseek
+ * Signature: (IJI)J
+ */
+JNIEXPORT jlong JNICALL
+Java_org_apache_bookkeeper_common_util_nativeio_NativeIOJni_lseek(
+ JNIEnv* env, jclass clazz,
+ jint fd, jlong offset, jint whence) {
+ int res = lseek(fd, offset, whence);
+
+ if (res == -1) {
+ throwExceptionWithErrno(env, "Failed to lseek");
+ }
+
+ return res;
+}
+
+/*
+ * Class: org_apache_bookkeeper_common_util_nativeio_NativeIOJni
+ * Method: close
+ * Signature: (I)I
+ */
+JNIEXPORT jint JNICALL
+Java_org_apache_bookkeeper_common_util_nativeio_NativeIOJni_close(JNIEnv* env,
jclass clazz,
+ jint fd) {
+ int res = close(fd);
+
+ if (res == -1) {
+ throwExceptionWithErrno(env, "Failed to close file");
+ }
+
+ return res;
+}
+
+/*
+ * Class: org_apache_bookkeeper_common_util_nativeio_NativeIOJni
+ * Method: pwrite
+ * Signature: (IJIJ)I
+ */
+JNIEXPORT jint JNICALL
Java_org_apache_bookkeeper_common_util_nativeio_NativeIOJni_pwrite
+ (JNIEnv* env, jclass clazz, jint fd, jlong pointer, jint count, jlong
offset) {
+ int res = pwrite(fd, (const void*) pointer, count, offset);
+
+ if (res == -1) {
+ throwExceptionWithErrno(env, "Failed to write on file");
+ }
+
+ return res;
+}
+
+/*
+ * Class: org_apache_bookkeeper_common_util_nativeio_NativeIOJni
+ * Method: posix_memalign
+ * Signature: (II)J
+ */
+JNIEXPORT jlong JNICALL
Java_org_apache_bookkeeper_common_util_nativeio_NativeIOJni_posix_1memalign
+ (JNIEnv* env, jclass clazz, jint alignment, jint size) {
+ void* ptr;
+ int res = posix_memalign(&ptr, alignment, size);
+
+ if (res != 0) {
+ throwExceptionWithErrno(env, "Failed to allocate aligned memory");
+ }
+
+ return (jlong) ptr;
+}
+
+/*
+ * Class: org_apache_bookkeeper_common_util_nativeio_NativeIOJni
+ * Method: pread
+ * Signature: (IJJJ)J
+ */
+JNIEXPORT jlong JNICALL
Java_org_apache_bookkeeper_common_util_nativeio_NativeIOJni_pread
+ (JNIEnv * env, jclass clazz, jint fd, jlong pointer, jlong size, jlong
offset) {
+
+ long res = pread(fd, (void*) pointer, size, offset);
+
+ if (res == -1) {
+ throwExceptionWithErrno(env, "Failed to read from file");
+ }
+
+ return res;
+}
+
+/*
+ * Class: org_apache_bookkeeper_common_util_nativeio_NativeIOJni
+ * Method: free
+ * Signature: (J)V
+ */
+JNIEXPORT void JNICALL
Java_org_apache_bookkeeper_common_util_nativeio_NativeIOJni_free
+ (JNIEnv * env, jclass clazz, jlong pointer) {
+ free((const void*) pointer);
+}
+
diff --git a/pom.xml b/pom.xml
index d150317fb..6b6367312 100644
--- a/pom.xml
+++ b/pom.xml
@@ -71,6 +71,7 @@
<module>shaded</module>
<module>microbenchmarks</module>
<module>tests</module>
+ <module>native-io</module>
</modules>
<mailingLists>
<mailingList>