Skip to content

Commit 229f67a

Browse files
committed
Use getAndAdd for the offer fast path
1 parent 1af524e commit 229f67a

File tree

1 file changed

+17
-7
lines changed

1 file changed

+17
-7
lines changed

internal-api/internal-api-9/src/main/java/datadog/trace/util/queue/MpscArrayQueueVarHandle.java

Lines changed: 17 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -82,9 +82,7 @@ public MpscArrayQueueVarHandle(int requestedCapacity) {
8282
public boolean offer(E e) {
8383
Objects.requireNonNull(e);
8484

85-
// jctools does the same local copy to have the jitter optimise the accesses
8685
final Object[] localBuffer = this.buffer;
87-
8886
long localProducerLimit = (long) PRODUCER_LIMIT_HANDLE.getVolatile(this);
8987
long cachedHead = 0L; // Local cache of head to reduce volatile reads
9088

@@ -94,33 +92,45 @@ public boolean offer(E e) {
9492
while (true) {
9593
long currentTail = (long) TAIL_HANDLE.getVolatile(this);
9694

97-
// Check if producer limit exceeded
95+
// Slow path: refresh producer limit when queue is near full
9896
if (currentTail >= localProducerLimit) {
99-
// Refresh head only when necessary
10097
cachedHead = (long) HEAD_HANDLE.getVolatile(this);
10198
localProducerLimit = cachedHead + capacity;
10299

103100
if (currentTail >= localProducerLimit) {
104101
return false; // queue full
105102
}
106103

107-
// Update producerLimit so other producers also benefit
108104
PRODUCER_LIMIT_HANDLE.setVolatile(this, localProducerLimit);
109105
}
110106

111-
// Attempt to claim a slot
107+
long freeSlots = localProducerLimit - currentTail;
108+
109+
// Fast path: getAndAdd if occupancy < 75%
110+
if (freeSlots > (long) (capacity * 0.25)) { // more than 25% free
111+
long slot = (long) TAIL_HANDLE.getAndAdd(this, 1L);
112+
final int index = (int) (slot & mask);
113+
114+
// Release-store ensures visibility to consumer
115+
ARRAY_HANDLE.setRelease(localBuffer, index, e);
116+
return true;
117+
}
118+
119+
// Slow path: CAS near limit
112120
if (TAIL_HANDLE.compareAndSet(this, currentTail, currentTail + 1)) {
113121
final int index = (int) (currentTail & mask);
114122

115-
// Release-store ensures producer's write is visible to consumer
123+
// Release-store ensures visibility to consumer
116124
ARRAY_HANDLE.setRelease(localBuffer, index, e);
117125
return true;
118126
}
119127

120128
// Backoff to reduce contention
121129
if ((spinCycles & 1) == 0) {
130+
// spin each even cycles
122131
Thread.onSpinWait();
123132
} else {
133+
// use a 'random' alternate backoff on odd cycles
124134
if (parkOnSpin) {
125135
LockSupport.parkNanos(1);
126136
} else {

0 commit comments

Comments
 (0)