diff --git a/.gitignore b/.gitignore index 73884b91fac2a2ba2270efee9c420d94098cebe6..de25edbef1b1df341abc149d95f47b973a90087d 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ build/ .idea/ .gradle/ -gradle.properties \ No newline at end of file +gradle.properties +target/ diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml new file mode 100644 index 0000000000000000000000000000000000000000..157b8780a51886db32115f65d4cf31b9c693e19c --- /dev/null +++ b/.gitlab-ci.yml @@ -0,0 +1,34 @@ +image: maven:3-eclipse-temurin-17 + +variables: + MAVEN_OPTS: "-Dhttps.protocols=TLSv1.2 -Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository -Dorg.slf4j.simpleLogger.log.org.apache.maven.cli.transfer.Slf4jMavenTransferListener=WARN -Dorg.slf4j.simpleLogger.showDateTime=true" + MAVEN_CLI_OPTS: "--batch-mode --errors --fail-at-end --show-version" + +cache: + key: "$CI_JOB_NAME" + paths: + - .m2/repository + +stages: + - build + - deploy + +build: + stage: build + script: + - mkdir -p src/main/resources/sh/blake/niouring/util/Linux/amd64/ +# disabled because compiling the drivers requires a c compiler toolchain +# - mvn -P jni compile native:compile native:link +# - cp target/libnio_uring.so src/main/resources/sh/blake/niouring/util/Linux/amd64/ + - mvn install -s ci_settings.xml -DskipTests + artifacts: + paths: + - target/ + +# build the docker image for the tool, see the Dockerfile for details +deploy: + stage: deploy + rules: + - if: $CI_COMMIT_TAG + script: + - mvn deploy -s ci_settings.xml -DskipTests diff --git a/build.sh b/build.sh new file mode 100644 index 0000000000000000000000000000000000000000..6fbce0c96d529716d86c05818e9dcb7e50a5291d --- /dev/null +++ b/build.sh @@ -0,0 +1,4 @@ +mvn -P jni compile native:compile native:link +mkdir -p src/main/resources/sh/blake/niouring/util/Linux/amd64/ +cp target/libnio_uring.so src/main/resources/sh/blake/niouring/util/Linux/amd64/ +mvn package diff --git a/ci_settings.xml b/ci_settings.xml new file mode 100644 index 0000000000000000000000000000000000000000..59c8c271cb4549ebcad535c1c9e1907839ba440f --- /dev/null +++ b/ci_settings.xml @@ -0,0 +1,16 @@ +<settings xmlns="http://maven.apache.org/SETTINGS/1.1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/SETTINGS/1.1.0 http://maven.apache.org/xsd/settings-1.1.0.xsd"> + <servers> + <server> + <id>gitlab-maven</id> + <configuration> + <httpHeaders> + <property> + <name>Job-Token</name> + <value>${env.CI_JOB_TOKEN}</value> + </property> + </httpHeaders> + </configuration> + </server> + </servers> +</settings> diff --git a/pom.xml b/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..16446a96fdd8c398c86a220487bbcea8ae6b034c --- /dev/null +++ b/pom.xml @@ -0,0 +1,138 @@ +<project> + <modelVersion>4.0.0</modelVersion> + <groupId>sh.blake.niouring</groupId> + <artifactId>nio_uring-jpms</artifactId> + <version>0.1.4</version> + <packaging>jar</packaging> + <properties> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + <jdk.version>17</jdk.version> + <junit.version>5.10.1</junit.version> + <junitplatform.version>1.10.1</junitplatform.version> + </properties> + <repositories> + <repository> + <id>central</id> + <name>Central Repository</name> + <url>https://repo.maven.apache.org/maven2</url> + </repository> + </repositories> + <dependencies> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-api</artifactId> + <version>${junit.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-engine</artifactId> + <version>${junit.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.junit.jupiter</groupId> + <artifactId>junit-jupiter-params</artifactId> + <version>${junit.version}</version> + <scope>test</scope> + </dependency> + <dependency> + <groupId>org.junit.platform</groupId> + <artifactId>junit-platform-commons</artifactId> + <version>${junitplatform.version}</version> + <scope>test</scope> + </dependency> + </dependencies> + <profiles> + <profile> + <id>default</id> + <activation> + <activeByDefault>true</activeByDefault> + </activation> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.12.1</version> + <configuration> + <release>${jdk.version}</release> + <source>${jdk.version}</source> + <target>${jdk.version}</target> + </configuration> + </plugin> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-jar-plugin</artifactId> + <version>3.3.0</version> + </plugin> + </plugins> + </build> + </profile> + <profile> + <id>jni</id> + <build> + <plugins> + <plugin> + <groupId>org.apache.maven.plugins</groupId> + <artifactId>maven-compiler-plugin</artifactId> + <version>3.10.1</version> + <executions> + <execution> + <phase>generate-sources</phase> + </execution> + </executions> + <configuration> + <compilerArgs> + <arg>-h</arg> + <arg>${project.build.directory}/include</arg> + </compilerArgs> + <compileSourceRoots>src/main/native</compileSourceRoots> + <outputDirectory>${project.build.directory}/include</outputDirectory> + <release>${jdk.version}</release> + <source>${jdk.version}</source> + <target>${jdk.version}</target> + </configuration> + </plugin> + <plugin> + <groupId>org.codehaus.mojo</groupId> + <artifactId>native-maven-plugin</artifactId> + <version>1.0-M1</version> + <extensions>true</extensions> + <configuration> + <sources> + <source> + <directory>src/main/c</directory> + <includes> + <include>**/*.c</include> + </includes> + </source> + </sources> + <linkerFinalName>libnio_uring</linkerFinalName> + <linkerFinalNameExt>so</linkerFinalNameExt> + <compilerStartOptions> + <compilerStartOption>-Os -c -fPIC -I${JAVA_HOME}/include -I${JAVA_HOME}/include/linux -I${project.build.directory}/include</compilerStartOption> + </compilerStartOptions> + <linkerStartOptions> + <linkerStartOption>-shared</linkerStartOption> + </linkerStartOptions> + <linkerEndOptions> + <linkerEndOption>-luring</linkerEndOption> + </linkerEndOptions> + </configuration> + </plugin> + </plugins> + </build> + </profile> + </profiles> + <distributionManagement> + <repository> + <id>gitlab-maven</id> + <url>${env.CI_API_V4_URL}/projects/${env.CI_PROJECT_ID}/packages/maven</url> + </repository> + <snapshotRepository> + <id>gitlab-maven</id> + <url>${env.CI_API_V4_URL}/projects/${env.CI_PROJECT_ID}/packages/maven</url> + </snapshotRepository> + </distributionManagement> +</project> diff --git a/src/main/java/module-info.java b/src/main/java/module-info.java new file mode 100644 index 0000000000000000000000000000000000000000..740220449c6d6d06d8bf31567cbd1a0a4e56ec1e --- /dev/null +++ b/src/main/java/module-info.java @@ -0,0 +1,5 @@ +module sh.blake.niouring { + opens sh.blake.niouring; + exports sh.blake.niouring; + exports sh.blake.niouring.util; +} diff --git a/src/main/java/sh/blake/niouring/AbstractIoUringChannel.java b/src/main/java/sh/blake/niouring/AbstractIoUringChannel.java index 1fcc3278ca0f6bff855bfbf9fe8459b60dd87676..01b4f71347c96e68c47431dda2a919a2bb74621c 100644 --- a/src/main/java/sh/blake/niouring/AbstractIoUringChannel.java +++ b/src/main/java/sh/blake/niouring/AbstractIoUringChannel.java @@ -1,10 +1,11 @@ package sh.blake.niouring; -import org.eclipse.collections.impl.map.mutable.primitive.LongObjectHashMap; import sh.blake.niouring.util.NativeLibraryLoader; import sh.blake.niouring.util.ReferenceCounter; import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; import java.util.function.Consumer; /** @@ -12,8 +13,8 @@ import java.util.function.Consumer; */ public abstract class AbstractIoUringChannel { private final int fd; - private final LongObjectHashMap<ReferenceCounter<ByteBuffer>> readBufferMap = new LongObjectHashMap<>(); - private final LongObjectHashMap<ReferenceCounter<ByteBuffer>> writeBufferMap = new LongObjectHashMap<>(); + private final Map<Long,ReferenceCounter<ByteBuffer>> readBufferMap = new HashMap<>(); + private final Map<Long,ReferenceCounter<ByteBuffer>> writeBufferMap = new HashMap<>(); private boolean closed = false; private Consumer<ByteBuffer> readHandler; private Consumer<ByteBuffer> writeHandler; @@ -146,7 +147,7 @@ public abstract class AbstractIoUringChannel { * * @return the read buffer map */ - LongObjectHashMap<ReferenceCounter<ByteBuffer>> readBufferMap() { + Map<Long,ReferenceCounter<ByteBuffer>> readBufferMap() { return readBufferMap; } @@ -155,7 +156,7 @@ public abstract class AbstractIoUringChannel { * * @return the write buffer map */ - LongObjectHashMap<ReferenceCounter<ByteBuffer>> writeBufferMap() { + Map<Long,ReferenceCounter<ByteBuffer>> writeBufferMap() { return writeBufferMap; } diff --git a/src/main/java/sh/blake/niouring/IoUring.java b/src/main/java/sh/blake/niouring/IoUring.java index e69cda392d57f1c7e6a4d4089cae2087aed3b0c8..8d12432e330f0b1ca4aec81e7f2e9af184b0d809 100644 --- a/src/main/java/sh/blake/niouring/IoUring.java +++ b/src/main/java/sh/blake/niouring/IoUring.java @@ -1,10 +1,11 @@ package sh.blake.niouring; -import org.eclipse.collections.impl.map.mutable.primitive.IntObjectHashMap; import sh.blake.niouring.util.ReferenceCounter; import sh.blake.niouring.util.NativeLibraryLoader; import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; import java.util.function.Consumer; /** @@ -20,7 +21,7 @@ public class IoUring { private final long ring; private final int ringSize; - private final IntObjectHashMap<AbstractIoUringChannel> fdToSocket = new IntObjectHashMap<>(); + private final Map<Integer,AbstractIoUringChannel> fdToSocket = new HashMap<>(); private Consumer<Exception> exceptionHandler; private boolean closed = false; private final long cqes; diff --git a/src/main/java/sh/blake/niouring/util/ByteBufferUtil.java b/src/main/java/sh/blake/niouring/util/ByteBufferUtil.java index bbad33ab5f7bfc19987f437d6be4a4ce30185598..fe5b6e8c0654cefa957db314e4dac8d10c268c1c 100644 --- a/src/main/java/sh/blake/niouring/util/ByteBufferUtil.java +++ b/src/main/java/sh/blake/niouring/util/ByteBufferUtil.java @@ -15,7 +15,7 @@ public class ByteBufferUtil { * @return the byte buffer */ public static ByteBuffer wrapDirect(byte[] data) { - return (ByteBuffer) ByteBuffer.allocateDirect(data.length).put(data).flip(); + return ByteBuffer.allocateDirect(data.length).put(data).flip(); } /** @@ -26,7 +26,7 @@ public class ByteBufferUtil { */ public static ByteBuffer wrapDirect(String utf8) { byte[] data = utf8.getBytes(StandardCharsets.UTF_8); - return (ByteBuffer) ByteBuffer.allocateDirect(data.length).put(data).flip(); + return ByteBuffer.allocateDirect(data.length).put(data).flip(); } /** @@ -41,6 +41,6 @@ public class ByteBufferUtil { return buffer; } buffer.flip(); - return (ByteBuffer) ByteBuffer.allocateDirect(buffer.remaining()).put(buffer).flip(); + return ByteBuffer.allocateDirect(buffer.remaining()).put(buffer).flip(); } } diff --git a/src/main/java/sh/blake/niouring/util/NativeLibraryLoader.java b/src/main/java/sh/blake/niouring/util/NativeLibraryLoader.java index dbf161728229f1932945fa4a9c6806f9d5431567..6f8d84977052606dd7e86cbe64d251c4da0367e0 100644 --- a/src/main/java/sh/blake/niouring/util/NativeLibraryLoader.java +++ b/src/main/java/sh/blake/niouring/util/NativeLibraryLoader.java @@ -1,9 +1,9 @@ package sh.blake.niouring.util; import java.io.File; -import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; +import java.nio.file.Files; public class NativeLibraryLoader { private static boolean loadAttempted = false; @@ -16,20 +16,16 @@ public class NativeLibraryLoader { } loadAttempted = true; - try (InputStream inputStream = NativeLibraryLoader.class.getResourceAsStream("/libnio_uring.so")) { - if (inputStream == null) { - throw new IOException("Native library not found"); - } - File tempFile = File.createTempFile("libnio_uring", ".tmp"); + var arch = System.getProperty("os.arch"); + var os = System.getProperty("os.name"); - byte[] buffer = new byte[8192]; - try (FileOutputStream fileOutputStream = new FileOutputStream(tempFile)) { - while (inputStream.available() > 0) { - int bytesRead = inputStream.read(buffer); - fileOutputStream.write(buffer, 0, bytesRead); - } - } + try (InputStream inputStream = + NativeLibraryLoader.class.getResourceAsStream(os + "/" + arch + "/libnio_uring.so")) { + if (inputStream == null) + throw new IOException("Native library not found"); + File tempFile = File.createTempFile("libnio_uring", ".tmp"); + Files.write(tempFile.toPath(), inputStream.readAllBytes()); System.load(tempFile.getAbsolutePath()); } } catch (IOException ex) { diff --git a/src/main/resources/sh/blake/niouring/util/Linux/amd64/libnio_uring.so b/src/main/resources/sh/blake/niouring/util/Linux/amd64/libnio_uring.so new file mode 100755 index 0000000000000000000000000000000000000000..46b8eb9ca5613d86d0af0156d6e80d10f9cc3bdf Binary files /dev/null and b/src/main/resources/sh/blake/niouring/util/Linux/amd64/libnio_uring.so differ diff --git a/src/test/java/sh/blake/niouring/IoUringFileTest.java b/src/test/java/sh/blake/niouring/IoUringFileTest.java index 7dcc2d1eadc3a5ea507847ecf0d5eb9091343763..ce35f2b8604b44966c759b0d129eed8b2e8f0c74 100644 --- a/src/test/java/sh/blake/niouring/IoUringFileTest.java +++ b/src/test/java/sh/blake/niouring/IoUringFileTest.java @@ -1,7 +1,7 @@ package sh.blake.niouring; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import java.nio.ByteBuffer; import java.nio.charset.StandardCharsets; @@ -31,7 +31,7 @@ public class IoUringFileTest extends TestBase { attemptUntil(ioUring::execute, readSuccessfully::get); - Assert.assertTrue("File read successfully", readSuccessfully.get()); + Assertions.assertTrue(readSuccessfully.get(), "File read successfully"); } @Test @@ -62,6 +62,6 @@ public class IoUringFileTest extends TestBase { ioUring.queueRead(file, buffer); attemptUntil(ioUring::execute, seekSuccessfully::get); - Assert.assertTrue("File seek successfully", seekSuccessfully.get()); + Assertions.assertTrue(seekSuccessfully.get(), "File seek successfully"); } } diff --git a/src/test/java/sh/blake/niouring/IoUringSocketTest.java b/src/test/java/sh/blake/niouring/IoUringSocketTest.java index 18a5802e24a8d1dad4a5dae5f9eac29933a45e4d..f361b3a28a00df27c1608755344645c3c342ccf0 100644 --- a/src/test/java/sh/blake/niouring/IoUringSocketTest.java +++ b/src/test/java/sh/blake/niouring/IoUringSocketTest.java @@ -1,7 +1,7 @@ package sh.blake.niouring; -import org.junit.Assert; -import org.junit.Test; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.Test; import sh.blake.niouring.util.ByteBufferUtil; import java.nio.ByteBuffer; @@ -31,16 +31,16 @@ public class IoUringSocketTest extends TestBase { }); IoUring ioUring = new IoUring(TEST_RING_SIZE) - .onException(Exception::printStackTrace) - .queueAccept(serverSocket) - .queueConnect(socket); + .onException(Exception::printStackTrace) + .queueAccept(serverSocket) + .queueConnect(socket); attemptUntil(ioUring::execute, () -> accepted.get() && connected.get()); ioUring.close(); - Assert.assertTrue("Server accepted connection", accepted.get()); - Assert.assertTrue("Client connected", connected.get()); + Assertions.assertTrue(accepted.get(), "Server accepted connection"); + Assertions.assertTrue(connected.get(), "Client connected"); } @Test @@ -58,9 +58,9 @@ public class IoUringSocketTest extends TestBase { socket.onException(ex -> exceptionProduced.set(true)); IoUring ioUring = new IoUring(TEST_RING_SIZE) - .onException(Exception::printStackTrace) - .queueAccept(serverSocket) - .queueConnect(socket); + .onException(Exception::printStackTrace) + .queueAccept(serverSocket) + .queueConnect(socket); attemptUntil(ioUring::execute, exceptionProduced::get); @@ -68,8 +68,8 @@ public class IoUringSocketTest extends TestBase { serverSocket.close(); socket.close(); - Assert.assertFalse("Server accepted connection", accepted.get()); - Assert.assertTrue("Client to connect (wrong port)", exceptionProduced.get()); + Assertions.assertFalse(accepted.get(), "Server accepted connection"); + Assertions.assertTrue(exceptionProduced.get(), "Client to connect (wrong port)"); } @Test @@ -108,18 +108,18 @@ public class IoUringSocketTest extends TestBase { }); IoUring ioUring = new IoUring(TEST_RING_SIZE) - .onException(Exception::printStackTrace) - .queueAccept(serverSocket) - .queueConnect(socket); + .onException(Exception::printStackTrace) + .queueAccept(serverSocket) + .queueConnect(socket); attemptUntil(ioUring::execute, () -> - serverAccepted.get() && clientConnected.get() && serverSent.get() && clientReceived.get()); + serverAccepted.get() && clientConnected.get() && serverSent.get() && clientReceived.get()); ioUring.close(); - Assert.assertTrue("Server accepted connection", serverAccepted.get()); - Assert.assertTrue("Server sent data", serverSent.get()); - Assert.assertTrue("Client connected", clientConnected.get()); - Assert.assertTrue("Client received data", clientReceived.get()); + Assertions.assertTrue(serverAccepted.get(), "Server accepted connection"); + Assertions.assertTrue(serverSent.get(), "Server sent data"); + Assertions.assertTrue(clientConnected.get(), "Client connected"); + Assertions.assertTrue(clientReceived.get(), "Client received data"); } }