/**
* Copyright 2014 Netflix, Inc.
*
* Licensed 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 rx.internal.util;
import static java.util.concurrent.atomic.AtomicReferenceFieldUpdater.newUpdater;
import java.util.concurrent.atomic.AtomicReferenceFieldUpdater;
import rx.internal.util.MpscPaddedQueue.Node;
abstract class MpscLinkedQueuePad0<E> {
long p00, p01, p02, p03, p04, p05, p06, p07;
long p30, p31, p32, p33, p34, p35, p36, p37;
}
abstract class MpscLinkedQueueHeadRef<E> extends MpscLinkedQueuePad0<E> {
@SuppressWarnings("rawtypes")
private static final AtomicReferenceFieldUpdater<MpscLinkedQueueHeadRef, Node> UPDATER =
newUpdater(MpscLinkedQueueHeadRef.class, Node.class, "headRef");
private volatile Node<E> headRef;
protected final Node<E> headRef() {
return headRef;
}
protected final void headRef(Node<E> val) {
headRef = val;
}
protected final void lazySetHeadRef(Node<E> newVal) {
UPDATER.lazySet(this, newVal);
}
}
abstract class MpscLinkedQueuePad1<E> extends MpscLinkedQueueHeadRef<E> {
long p00, p01, p02, p03, p04, p05, p06, p07;
long p30, p31, p32, p33, p34, p35, p36, p37;
}
abstract class MpscLinkedQueueTailRef<E> extends MpscLinkedQueuePad1<E> {
@SuppressWarnings("rawtypes")
private static final AtomicReferenceFieldUpdater<MpscLinkedQueueTailRef, Node> UPDATER =
newUpdater(MpscLinkedQueueTailRef.class, Node.class, "tailRef");
private volatile Node<E> tailRef;
protected final Node<E> tailRef() {
return tailRef;
}
protected final void tailRef(Node<E> val) {
tailRef = val;
}
@SuppressWarnings("unchecked")
protected final Node<E> getAndSetTailRef(Node<E> newVal) {
return (Node<E>) UPDATER.getAndSet(this, newVal);
}
}
/**
* A multiple-producer single consumer queue implementation with padded reference to tail to avoid cache-line
* thrashing. Based on Netty's <a href='https://github.com/netty/netty/blob/master/common/src/main/java/io/netty/util/internal/MpscLinkedQueue.java'>MpscQueue implementation</a>
* but using {@code AtomicReferenceFieldUpdater} instead of {@code Unsafe}.<br>
* Original algorithm presented <a
* href="http://www.1024cores.net/home/lock-free-algorithms/queues/non-intrusive-mpsc-node-based-queue"> on 1024
* Cores</a> by D. Vyukov.<br>
* Data structure modified to avoid false sharing between head and tail references as per implementation of
* MpscLinkedQueue on <a href="https://github.com/JCTools/JCTools">JCTools project</a>.
*
* @param <E> the element type
*/
public final class MpscPaddedQueue<E> extends MpscLinkedQueueTailRef<E> {
long p00, p01, p02, p03, p04, p05, p06, p07;
long p30, p31, p32, p33, p34, p35, p36, p37;
/**
* Initializes the empty queue.
*/
public MpscPaddedQueue() {
Node<E> stub = new Node<E>(null);
headRef(stub);
tailRef(stub);
}
/**
* Offer a new value.
*
* @param v the value to offer
*/
public void offer(E v) {
Node<E> n = new Node<E>(v);
getAndSetTailRef(n).next(n);
}
/**
* @warn method description missing
* @return Poll a value from the head of the queue or return null if the queue is empty.
*/
public E poll() {
Node<E> n = peekNode();
if (n == null) {
return null;
}
E v = n.value;
n.value = null; // do not retain this value as the node still stays in the queue
lazySetHeadRef(n);
return v;
}
/**
* Check if there is a node available without changing anything.
* @return
*/
private Node<E> peekNode() {
for (;;) {
Node<E> t = headRef();
Node<E> n = t.next();
if (n != null || headRef() == t) {
return n;
}
}
}
/**
* Clears the queue.
*/
public void clear() {
for (;;) {
if (poll() == null) {
break;
}
}
}
/**
* Regular node with value and reference to the next node.
*/
static final class Node<E> {
E value;
@SuppressWarnings(value = "rawtypes")
static final AtomicReferenceFieldUpdater<Node, Node> TAIL_UPDATER = AtomicReferenceFieldUpdater.newUpdater(Node.class, Node.class, "next");
private volatile Node<E> next;
Node(E value) {
this.value = value;
}
void next(Node<E> newNext) {
TAIL_UPDATER.lazySet(this, newNext);
}
Node<E> next() {
return next;
}
}
}