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>

Reply via email to