Skip to content

Commit

Permalink
update: documentation and github action
Browse files Browse the repository at this point in the history
  • Loading branch information
gc-garcol committed Nov 21, 2024
1 parent 22c1635 commit 6b243cf
Show file tree
Hide file tree
Showing 10 changed files with 222 additions and 32 deletions.
44 changes: 44 additions & 0 deletions .github/workflows/gradle-publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# This workflow uses actions that are not certified by GitHub.
# They are provided by a third-party and are governed by
# separate terms of service, privacy policy, and support
# documentation.
# This workflow will build a package using Gradle and then publish it to GitHub packages when a release is created
# For more information see: https://github.com/actions/setup-java/blob/main/docs/advanced-usage.md#Publishing-using-gradle

name: Gradle Package

on:
push:
branches:
- main

jobs:
build:

runs-on: ubuntu-latest
permissions:
contents: read
packages: write

steps:
- uses: actions/checkout@v4
- name: Set up JDK 21
uses: actions/setup-java@v4
with:
java-version: '21'
distribution: 'temurin'
server-id: github # Value of the distributionManagement/repository/id field of the pom.xml
settings-path: ${{ github.workspace }} # location for the settings.xml file

- name: Setup Gradle
uses: gradle/actions/setup-gradle@af1da67850ed9a4cedd57bfd976089dd991e2582 # v4.0.0

- name: Build with Gradle
run: ./gradlew :lib-core:build

# The USERNAME and TOKEN need to correspond to the credentials environment variables used in
# the publishing section of your build.gradle
- name: Publish to GitHub Packages
run: ./gradlew :lib-core:publish
env:
GITHUB_TOKEN: ${{ secrets.TOKEN }}
19 changes: 11 additions & 8 deletions lib-core/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,11 +1,13 @@
import org.jreleaser.model.Active

plugins {
`java-library`
`maven-publish`
id("org.jreleaser") version "1.15.0"
}

group = "gc.garcol"
version = "0.0.1-SNAPSHOT"
group = "io.github.gc-garcol"
version = "0.0.1"

java {
toolchain {
Expand All @@ -17,13 +19,9 @@ repositories {
mavenCentral()
}

var lombokVersion = "1.18.34"
var jupiterVersion = "5.11.3"

dependencies {
compileOnly("org.projectlombok:lombok:${lombokVersion}")
annotationProcessor("org.projectlombok:lombok:${lombokVersion}")

testImplementation("org.junit.jupiter:junit-jupiter-api:${jupiterVersion}")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:${jupiterVersion}")
}
Expand All @@ -41,7 +39,7 @@ java {
publishing {
publications {
create<MavenPublication>("maven") {
groupId = "gc.garcol"
groupId = "io.github.gc-garcol"
artifactId = "cafe-ringbuffer"

from(components["java"])
Expand Down Expand Up @@ -74,7 +72,12 @@ publishing {

repositories {
maven {
url = layout.buildDirectory.dir("staging-deploy").get().asFile.toURI()
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/gc-garcol/cafe-ringbuffer")
credentials {
username = System.getenv("GITHUB_ACTOR")
password = System.getenv("GITHUB_TOKEN")
}
}
}
}
32 changes: 31 additions & 1 deletion lib-core/src/main/java/gc/garcol/libcore/BufferUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,31 @@
import java.nio.ByteBuffer;

/**
* Utility class for working with ByteBuffers using VarHandles.
* Provides methods to access the underlying byte array and its offset.
*
* @author thaivc
* @since 2024
*/
public class BufferUtil
{

/**
* The base offset of the byte array in memory.
* Used for calculating the memory address of array elements.
*/
public static final long ARRAY_BASE_OFFSET = UnsafeHelper.UNSAFE.arrayBaseOffset(byte[].class);

/**
* VarHandle for accessing the "hb" field in ByteBuffer.
* This field represents the underlying byte array of the ByteBuffer.
*/
public static final VarHandle BYTE_BUFFER_HB_HANDLE;

/**
* VarHandle for accessing the "offset" field in ByteBuffer.
* This field represents the offset of the underlying byte array in the ByteBuffer.
*/
public static final VarHandle BYTE_BUFFER_OFFSET_HANDLE;

static
Expand All @@ -34,6 +51,13 @@ public class BufferUtil
}
}

/**
* Returns the underlying byte array of the given ByteBuffer.
*
* @param buffer the ByteBuffer to extract the byte array from
* @return the underlying byte array
* @throws IllegalArgumentException if the buffer is direct
*/
public static byte[] array(final ByteBuffer buffer)
{
if (buffer.isDirect())
Expand All @@ -44,8 +68,14 @@ public static byte[] array(final ByteBuffer buffer)
return (byte[])BYTE_BUFFER_HB_HANDLE.get(buffer);
}

/**
* Returns the offset of the underlying byte array in the given ByteBuffer.
*
* @param buffer the ByteBuffer to extract the offset from
* @return the offset of the underlying byte array
*/
public static int arrayOffset(final ByteBuffer buffer)
{
return (int)BYTE_BUFFER_OFFSET_HANDLE.get(buffer);
}
}
}
12 changes: 11 additions & 1 deletion lib-core/src/main/java/gc/garcol/libcore/ByteBufferUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,24 @@
import java.nio.ByteBuffer;

/**
* Utility class for working with ByteBuffers.
*
* @author thaivc
* @since 2024
*/
public class ByteBufferUtil
{
/**
* Puts the given byte array into the specified ByteBuffer at the given index.
* Updates the buffer's position to the end of the inserted data.
*
* @param buffer the ByteBuffer to put the byte array into
* @param bufferIndex the index in the buffer to start putting the byte array
* @param src the byte array to put into the buffer
*/
public static void put(ByteBuffer buffer, int bufferIndex, byte[] src)
{
buffer.put(bufferIndex, src);
buffer.position(bufferIndex + src.length);
}
}
}
17 changes: 15 additions & 2 deletions lib-core/src/main/java/gc/garcol/libcore/MemoryAccess.java
Original file line number Diff line number Diff line change
@@ -1,24 +1,37 @@
package gc.garcol.libcore;

/**
* Utility class for memory access operations using Unsafe.
*
* @author thaivc
* @since 2024
*/
public class MemoryAccess
{

/**
* Ensures that all previous loads are visible to subsequent loads.
* This method uses Unsafe's loadFence to provide the memory fence.
*/
public static void loadFence()
{
UnsafeHelper.UNSAFE.loadFence();
}

/**
* Ensures that all previous stores are visible to subsequent stores.
* This method uses Unsafe's storeFence to provide the memory fence.
*/
public static void storeFence()
{
UnsafeHelper.UNSAFE.storeFence();
}

/**
* Ensures that all previous loads and stores are visible to subsequent loads and stores.
* This method uses Unsafe's fullFence to provide the memory fence.
*/
public static void fullFence()
{
UnsafeHelper.UNSAFE.fullFence();
}
}
}
12 changes: 7 additions & 5 deletions lib-core/src/main/java/gc/garcol/libcore/MessageHandler.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
package gc.garcol.libcore;

/**
* Functional interface for handling messages read from a buffer.
*
* @author thaivc
* @since 2024
*/
Expand All @@ -11,11 +13,11 @@ public interface MessageHandler
/**
* Called for the processing of each message read from a buffer in turn.
*
* @param msgTypeId
* @param buffer
* @param index
* @param length
* @return should commit the consumed position or not
* @param msgTypeId the type identifier of the message
* @param buffer the buffer containing the message
* @param index the starting index of the message in the buffer
* @param length the length of the message in the buffer
* @return true if the consumed position should be committed, false otherwise
*/
boolean onMessage(int msgTypeId, UnsafeBuffer buffer, int index, int length);
}
37 changes: 28 additions & 9 deletions lib-core/src/main/java/gc/garcol/libcore/OneToManyRingBuffer.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@
import java.util.concurrent.atomic.AtomicLongArray;

/**
* A ring buffer that supports one producer and multiple consumers.
* Provides methods to write messages to the buffer and read messages from the buffer.
* Ensures memory visibility guarantees using happen-before relationships.
*
* @author thaivc
* @since 2024
*/
Expand All @@ -18,13 +22,24 @@ public class OneToManyRingBuffer
private final int maxMsgLength;
private final int lastConsumerIndex;

/**
* The length of the header in bytes.
* The header contains the length and type of the message.
*/
public static final int HEADER_LENGTH = Integer.BYTES * 2; // length, type

/**
* Alignment as a multiple of bytes for each record.
* Padding to align the record in order to prevent false sharing.
*/
public static final int ALIGNMENT = Long.BYTES * 8; // padding to align the record in order to prevent false sharing

/**
* Constructs a OneToManyRingBuffer with the specified size and number of consumers.
*
* @param powSize the power of two size for the ring buffer
* @param consumerSize the number of consumers
*/
public OneToManyRingBuffer(int powSize, int consumerSize)
{
Preconditions.checkArgument(powSize >= 10, "Ring buffer size must be greater than 1024");
Expand All @@ -40,11 +55,11 @@ public OneToManyRingBuffer(int powSize, int consumerSize)
}

/**
* Write a message to the ring buffer
* Writes a message to the ring buffer.
*
* @param msgTypeId
* @param message the message to write, the limit must be equals to the message length
* @return the message was written successfully or not
* @param msgTypeId the type identifier of the message
* @param message the message to write, the limit must be equal to the message length
* @return true if the message was written successfully, false otherwise
*/
public boolean write(int msgTypeId, ByteBuffer message)
{
Expand Down Expand Up @@ -133,18 +148,22 @@ else if (!sameCircleWithLastConsumer) // !sameCircleWithFirstConsumer, the produ
}

/**
* Read message from the ring buffer, apply for consumeIndex-th consumer
* Reads messages from the ring buffer for the specified consumer.
*
* @param consumerIndex the index of the consumer
* @param handler the handler to process the messages
* @return the number of messages read
*/
public int read(int consumerIndex, final MessageHandler handler)
{
return read(consumerIndex, handler, Integer.MAX_VALUE);
}

/**
* Read message from the ring buffer, apply for consumeIndex-th consumer
* Reads messages from the ring buffer for the specified consumer with a limit.
*
* @param consumerIndex the index of the consumer
* @param handler the handler to process the message
* @param handler the handler to process the messages
* @param limit the maximum number of messages to read
* @return the number of messages read
*/
Expand All @@ -161,11 +180,11 @@ public int read(int consumerIndex, final MessageHandler handler, int limit)
}

/**
* Read one message from the ring buffer, apply for consumeIndex-th consumer
* Reads one message from the ring buffer for the specified consumer.
*
* @param consumerIndex the index of the consumer
* @param handler the handler to process the message
* @return true if a message was read otherwise false
* @return true if a message was read, false otherwise
*/
public boolean readOne(int consumerIndex, final MessageHandler handler)
{
Expand Down
14 changes: 13 additions & 1 deletion lib-core/src/main/java/gc/garcol/libcore/Preconditions.java
Original file line number Diff line number Diff line change
@@ -1,16 +1,28 @@
package gc.garcol.libcore;

/**
* Utility class for checking preconditions.
* Provides methods to validate arguments and state conditions.
* Throws appropriate exceptions if conditions are not met.
*
* @author thaivc
* @since 2024
*/
public class Preconditions
{
/**
* Checks if the provided argument condition is true.
* Throws an IllegalArgumentException with the specified message if the condition is false.
*
* @param success the condition to check
* @param message the exception message to use if the check fails
* @throws IllegalArgumentException if the condition is false
*/
public static void checkArgument(boolean success, String message)
{
if (!success)
{
throw new IllegalArgumentException(message);
}
}
}
}
Loading

0 comments on commit 6b243cf

Please sign in to comment.