/*
* Original work Copyright 2015 Real Logic Ltd.
* Modified work Copyright (c) 2008-2017, Hazelcast, Inc. All Rights Reserved.
*
* 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 com.hazelcast.internal.util.concurrent;
import com.hazelcast.util.QuickMath;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.concurrent.atomic.AtomicLongFieldUpdater;
import java.util.concurrent.atomic.AtomicReferenceArray;
/** Pad out a cacheline to the left of producer fields to prevent false sharing. */
@SuppressFBWarnings(value = "UuF", justification = "Fields used for padding are unused programatically")
class AbstractConcurrentArrayQueuePadding1 {
@SuppressWarnings({"unused", "checkstyle:multiplevariabledeclarations"})
protected long p1, p2, p3, p4, p5, p6, p7, p8, p9, p10, p11, p12, p13, p14, p15;
}
/** Values for the producer that are expected to be padded. */
class AbstractConcurrentArrayQueueProducer extends AbstractConcurrentArrayQueuePadding1 {
protected static final AtomicLongFieldUpdater<AbstractConcurrentArrayQueueProducer> TAIL =
AtomicLongFieldUpdater.newUpdater(AbstractConcurrentArrayQueueProducer.class, "tail");
protected static final AtomicLongFieldUpdater<AbstractConcurrentArrayQueueProducer> SHARED_HEAD_CACHE =
AtomicLongFieldUpdater.newUpdater(AbstractConcurrentArrayQueueProducer.class, "sharedHeadCache");
protected volatile long tail;
protected long headCache;
protected volatile long sharedHeadCache;
}
/** Pad out a cacheline between the producer and consumer fields to prevent false sharing. */
@SuppressFBWarnings(value = "UuF", justification = "Fields used for padding are unused programatically")
class AbstractConcurrentArrayQueuePadding2 extends AbstractConcurrentArrayQueueProducer {
@SuppressWarnings({"unused", "checkstyle:multiplevariabledeclarations"})
protected long p16, p17, p18, p19, p20, p21, p22, p23, p24, p25, p26, p27, p28, p29, p30;
}
/** Values for the consumer that are expected to be padded. */
class AbstractConcurrentArrayQueueConsumer extends AbstractConcurrentArrayQueuePadding2 {
protected static final AtomicLongFieldUpdater<AbstractConcurrentArrayQueueConsumer> HEAD =
AtomicLongFieldUpdater.newUpdater(AbstractConcurrentArrayQueueConsumer.class, "head");
protected volatile long head;
}
/** Pad out a cacheline to the right of consumer fields to prevent false sharing. */
@SuppressFBWarnings(value = "UuF", justification = "Fields used for padding are unused programatically")
class AbstractConcurrentArrayQueuePadding3 extends AbstractConcurrentArrayQueueConsumer {
@SuppressWarnings({"unused", "checkstyle:multiplevariabledeclarations"})
protected long p31, p32, p33, p34, p35, p36, p37, p38, p39, p40, p41, p42, p43, p44, p45;
}
/**
* Abstract base class for concurrent array queues.
* @param <E> type of elements in the queue.
*/
abstract class AbstractConcurrentArrayQueue<E>
extends AbstractConcurrentArrayQueuePadding3
implements QueuedPipe<E> {
protected final int capacity;
protected final AtomicReferenceArray<E> buffer;
@SuppressWarnings("unchecked")
protected AbstractConcurrentArrayQueue(int requestedCapacity) {
capacity = QuickMath.nextPowerOfTwo(requestedCapacity);
buffer = new AtomicReferenceArray(capacity);
}
@Override
public long addedCount() {
return tail;
}
@Override
public long removedCount() {
return head;
}
@Override
public int capacity() {
return capacity;
}
@Override
public int remainingCapacity() {
return capacity() - size();
}
@Override
@SuppressWarnings("unchecked")
public E peek() {
return buffer.get(seqToArrayIndex(head, capacity - 1));
}
@Override
public boolean add(E e) {
if (offer(e)) {
return true;
}
throw new IllegalStateException("Queue is full");
}
@Override
public E remove() {
final E e = poll();
if (e == null) {
throw new NoSuchElementException("Queue is empty");
}
return e;
}
@Override
public E element() {
final E e = peek();
if (e == null) {
throw new NoSuchElementException("Queue is empty");
}
return e;
}
@Override
public boolean isEmpty() {
return peek() == null;
}
@Override
public boolean contains(Object o) {
if (o == null) {
return false;
}
final AtomicReferenceArray<E> buffer = this.buffer;
long mask = capacity - 1;
for (long i = head, limit = tail; i < limit; i++) {
final Object e = buffer.get(seqToArrayIndex(i, mask));
if (o.equals(e)) {
return true;
}
}
return false;
}
@Override
public Iterator<E> iterator() {
throw new UnsupportedOperationException();
}
@Override
public Object[] toArray() {
throw new UnsupportedOperationException();
}
@Override
public <T> T[] toArray(T[] a) {
throw new UnsupportedOperationException();
}
@Override
public boolean remove(Object o) {
throw new UnsupportedOperationException();
}
@Override
public boolean containsAll(Collection<?> c) {
for (final Object o : c) {
if (!contains(o)) {
return false;
}
}
return true;
}
@Override
public boolean addAll(Collection<? extends E> c) {
for (E e : c) {
add(e);
}
return true;
}
@Override
public boolean removeAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
@Override
public boolean retainAll(Collection<?> c) {
throw new UnsupportedOperationException();
}
@Override
public void clear() {
Object value;
do {
value = poll();
} while (value != null);
}
@Override
public int size() {
long currentHeadBefore;
long currentTail;
long currentHeadAfter = head;
do {
currentHeadBefore = currentHeadAfter;
currentTail = tail;
currentHeadAfter = head;
} while (currentHeadAfter != currentHeadBefore);
return (int) (currentTail - currentHeadAfter);
}
protected static int seqToArrayIndex(long sequence, long mask) {
return (int) (sequence & mask);
}
}