Skip to content

Commit 6cfd596

Browse files
committed
update: add extra padding and end message
1 parent fa0a867 commit 6cfd596

File tree

8 files changed

+37
-25
lines changed

8 files changed

+37
-25
lines changed

build.gradle.kts

+1-1
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ plugins {
77
}
88

99
group = "io.github.gc-garcol"
10-
version = "1.2.1"
10+
version = "1.3.0"
1111

1212
java {
1313
withJavadocJar()

lib-benchmark/src/main/java/gc/garcol/libbenchmark/Pipeline1P3C_OneToManyRingBufferBechmark.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@
1414
@State(Scope.Thread)
1515
@BenchmarkMode({ Mode.Throughput, Mode.AverageTime })
1616
@OutputTimeUnit(TimeUnit.MILLISECONDS)
17-
@Measurement(iterations = 3, time = 3)
1817
@Fork(1)
1918
public class Pipeline1P3C_OneToManyRingBufferBechmark
2019
{
2120
@Benchmark
22-
@Timeout(time = 20)
23-
@Warmup(iterations = 3, time = 20)
21+
@Timeout(time = 60)
22+
@Measurement(iterations = 1, time = 60)
23+
@Warmup(iterations = 1, time = 10)
2424
public void publish(Pipeline1P3C_OneToManyRingBufferPlan ringBufferPlan, Blackhole blackhole) throws IOException
2525
{
2626
ringBufferPlan.writeBuffer.clear();

lib-benchmark/src/main/java/gc/garcol/libbenchmark/Pipeline1P3C_OneToManyRingBufferPlan.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public class Pipeline1P3C_OneToManyRingBufferPlan
2929
@Setup(Level.Trial)
3030
public void setUp(Blackhole blackhole) throws InterruptedException
3131
{
32-
ringBuffer = new OneToManyRingBuffer(16, 3);
32+
ringBuffer = new OneToManyRingBuffer(18, 3);
3333

3434
messageHandler = new MessageHandler()
3535
{

lib-benchmark/src/main/java/gc/garcol/libbenchmark/Unicast1P1C_OneToManyRingBufferBechmark.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,13 @@
1414
@State(Scope.Thread)
1515
@BenchmarkMode({ Mode.Throughput, Mode.AverageTime })
1616
@OutputTimeUnit(TimeUnit.MILLISECONDS)
17-
@Measurement(iterations = 3, time = 3)
1817
@Fork(1)
1918
public class Unicast1P1C_OneToManyRingBufferBechmark
2019
{
2120
@Benchmark
22-
@Timeout(time = 20)
23-
@Warmup(iterations = 2, time = 20)
21+
@Timeout(time = 60)
22+
@Measurement(iterations = 1, time = 60)
23+
@Warmup(iterations = 1, time = 10)
2424
public void publish(Unicast1P1C_OneToManyRingBufferPlan ringBufferPlan, Blackhole blackhole) throws IOException
2525
{
2626
ringBufferPlan.writeBuffer.clear();

lib-benchmark/src/main/java/gc/garcol/libbenchmark/Unicast1P1C_OneToManyRingBufferPlan.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ public class Unicast1P1C_OneToManyRingBufferPlan
2929
@Setup(Level.Trial)
3030
public void setUp(Blackhole blackhole) throws InterruptedException
3131
{
32-
ringBuffer = new OneToManyRingBuffer(16, 1);
32+
ringBuffer = new OneToManyRingBuffer(18, 1);
3333

3434
messageHandler = new MessageHandler()
3535
{

lib-core/build.gradle.kts

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ plugins {
44
}
55

66
group = "io.github.gc-garcol"
7-
version = "1.2.1"
7+
version = "1.3.0"
88

99
java {
1010
toolchain {

lib-core/src/main/java/gc/garcol/libcore/OneToManyRingBuffer.java

+19-11
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,9 @@ public class OneToManyRingBuffer
2424
private final UnsafeBuffer pointers;
2525

2626
private final int capacity;
27-
private final int maxMsgLength;
27+
private final int maxRecordLength;
2828
private final int lastConsumerIndex;
29+
private final int consumerSize;
2930

3031
private final int producerPointerIndex;
3132
private final int[] consumerPointerIndexes;
@@ -36,6 +37,8 @@ public class OneToManyRingBuffer
3637
*/
3738
public static final int HEADER_LENGTH = Integer.BYTES * 2; // length, type
3839

40+
public static final int EXTRA_PADDING_LENGTH = Long.BYTES * 8;
41+
3942
/**
4043
* Alignment as a multiple of bytes for each record.
4144
* Padding to align the record in order to prevent false sharing.
@@ -61,14 +64,15 @@ public OneToManyRingBuffer(int powSize, int consumerSize)
6164

6265
producerPointerIndex = Long.BYTES * 8;
6366
consumerPointerIndexes = new int[consumerSize];
67+
this.consumerSize = consumerSize;
6468

6569
consumerPointerIndexes[0] = Long.BYTES * 8 + Long.BYTES + Long.BYTES * 7; // padding + producer-pointer-block + padding
6670
for (int i = 1; i < consumerSize; i++)
6771
{
6872
consumerPointerIndexes[i] = consumerPointerIndexes[i - 1] + Long.BYTES + Long.BYTES * 7; // padding + consumer-pointer-block + padding
6973
}
7074

71-
maxMsgLength = capacity >> 3;
75+
maxRecordLength = capacity >> 3;
7276
}
7377

7478
/**
@@ -80,13 +84,15 @@ public OneToManyRingBuffer(int powSize, int consumerSize)
8084
*/
8185
public boolean write(int msgTypeId, ByteBuffer message)
8286
{
83-
int msgLength = message.limit();
84-
checkMsgLength(msgLength, maxMsgLength);
87+
int messageLength = message.limit();
88+
final int recordLength = calculateRecordLength(messageLength);
89+
final int alignedRecordLength = BitUtil.align(recordLength, ALIGNMENT);
90+
checkMsgLength(alignedRecordLength, maxRecordLength);
8591

8692
// [1] happen-before guarantee for reads
8793
long currentProducerPosition = pointers.getLongVolatile(producerPointerIndex);
8894
long firstConsumerPosition = pointers.getLongVolatile(consumerPointerIndexes[0]);
89-
long lastConsumerPosition = pointers.getLongVolatile(consumerPointerIndexes[lastConsumerIndex]);
95+
long lastConsumerPosition = consumerSize == 1 ? firstConsumerPosition : pointers.getLongVolatile(consumerPointerIndexes[lastConsumerIndex]);
9096

9197
int currentProducerOffset = offset(currentProducerPosition);
9298
boolean currentProducerFlip = flip(currentProducerPosition);
@@ -95,9 +101,6 @@ public boolean write(int msgTypeId, ByteBuffer message)
95101
int lastConsumerOffset = offset(lastConsumerPosition);
96102
boolean lastConsumerFlip = flip(lastConsumerPosition);
97103

98-
final int recordLength = msgLength + HEADER_LENGTH;
99-
final int alignedRecordLength = BitUtil.align(recordLength, ALIGNMENT);
100-
101104
final int expectedEndOffsetOfRecord = currentProducerOffset + alignedRecordLength - 1;
102105

103106
boolean sameCircleWithFirstConsumer = sameCircle(currentProducerFlip, firstConsumerFlip);
@@ -151,8 +154,8 @@ else if (!sameCircleWithLastConsumer) // !sameCircleWithFirstConsumer, the produ
151154
int nextProducerOffset = (realStartOfRecord + alignedRecordLength) % capacity; // maybe nextProducerOffset == 0
152155

153156
// when [2] happened, the [2] ensures that the these instructions are synchronized into main memory as well
154-
buffer.putBytes(realStartOfRecord + HEADER_LENGTH, message, 0, msgLength);
155-
buffer.putInt(realStartOfRecord, msgLength);
157+
buffer.putBytes(realStartOfRecord + HEADER_LENGTH, message, 0, messageLength);
158+
buffer.putInt(realStartOfRecord, messageLength);
156159
buffer.putInt(realStartOfRecord + Integer.BYTES, msgTypeId);
157160

158161
shouldFlip |= nextProducerOffset == 0;
@@ -284,7 +287,7 @@ public boolean readOne(int consumerIndex, final MessageHandler handler)
284287
return false;
285288
}
286289

287-
int recordLength = messageLength + HEADER_LENGTH;
290+
int recordLength = calculateRecordLength(messageLength);
288291
int alignedRecordLength = BitUtil.align(recordLength, ALIGNMENT);
289292
int endRecordOffset = currentConsumerOffset + alignedRecordLength - 1;
290293

@@ -305,4 +308,9 @@ public boolean readOne(int consumerIndex, final MessageHandler handler)
305308

306309
return true;
307310
}
311+
312+
private int calculateRecordLength(int messageLength)
313+
{
314+
return messageLength + HEADER_LENGTH + EXTRA_PADDING_LENGTH;
315+
}
308316
}

lib-core/src/test/java/gc/garcol/libcore/OneToManyRingBufferTest.java

+8-4
Original file line numberDiff line numberDiff line change
@@ -141,12 +141,15 @@ public void shouldConsumeThreadSafe_1P2C_10()
141141

142142
oneToManyRingBuffer = new OneToManyRingBuffer(10, 2);
143143

144+
int publishedMessage = 0;
144145
for (int i = 0; i < messages.size(); i++)
145146
{
146147
messageBufferWriter.clear();
147148
ByteBufferUtil.put(messageBufferWriter, 0, messages.get(i).getBytes());
148149
messageBufferWriter.flip();
149-
oneToManyRingBuffer.write(i, messageBufferWriter);
150+
if (oneToManyRingBuffer.write(i, messageBufferWriter)) {
151+
publishedMessage++;
152+
}
150153
}
151154

152155
Function<Integer, MessageHandler> handlerSupplier = (Integer consumerId) ->
@@ -180,7 +183,8 @@ public void shouldConsumeThreadSafe_1P2C_10()
180183
for (int i = 0; i < messages.size(); i++)
181184
{
182185
UncheckUtil.run(() -> Thread.sleep(15));
183-
oneToManyRingBuffer.read(0, handlerSupplier.apply(0), 1);
186+
int consumedMessage = oneToManyRingBuffer.read(0, handlerSupplier.apply(0), 1);
187+
System.out.println("Consumer 0 consume message: " + consumedMessage);
184188
}
185189
end.set(true);
186190
});
@@ -197,8 +201,8 @@ public void shouldConsumeThreadSafe_1P2C_10()
197201
UncheckUtil.run(thread0::join);
198202
UncheckUtil.run(thread1::join);
199203

200-
Assertions.assertEquals(messages.size(), consumedIndexes.get(0).get(), "Consumer 0 not consume all messages");
201-
Assertions.assertEquals(messages.size(), consumedIndexes.get(1).get(), "Consumer 1 not consume all messages");
204+
Assertions.assertEquals(publishedMessage, consumedIndexes.get(0).get(), "Consumer 0 not consume all messages");
205+
Assertions.assertEquals(publishedMessage, consumedIndexes.get(1).get(), "Consumer 1 not consume all messages");
202206
}
203207

204208
@Test

0 commit comments

Comments
 (0)