All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.couchbase.client.deps.io.netty.util.internal.MpscLinkedQueue Maven / Gradle / Ivy

There is a newer version: 2.7.0
Show newest version
/*
 * Copyright 2014 The Netty Project
 *
 * The Netty Project licenses this file to you 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.
 */
/**
 * Copyright (C) 2009-2013 Typesafe Inc. 
 */
package com.couchbase.client.deps.io.netty.util.internal;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.Array;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.NoSuchElementException;
import java.util.Queue;

/**
 * A lock-free concurrent single-consumer multi-producer {@link Queue}.
 * It allows multiple producer threads to perform the following operations simultaneously:
 * 
    *
  • {@link #offer(Object)}, {@link #add(Object)}, and {@link #addAll(Collection)}
  • *
  • All other read-only operations: *
      *
    • {@link #contains(Object)} and {@link #containsAll(Collection)}
    • *
    • {@link #element()}, {@link #peek()}
    • *
    • {@link #size()} and {@link #isEmpty()}
    • *
    • {@link #iterator()} (except {@link Iterator#remove()}
    • *
    • {@link #toArray()} and {@link #toArray(Object[])}
    • *
    *
  • *
* .. while only one consumer thread is allowed to perform the following operations exclusively: *
    *
  • {@link #poll()} and {@link #remove()}
  • *
  • {@link #remove(Object)}, {@link #removeAll(Collection)}, and {@link #retainAll(Collection)}
  • *
  • {@link #clear()}
  • {@link #} *
* * The behavior of this implementation is undefined if you perform the operations for a consumer thread only * from multiple threads. * * The initial implementation is based on: * * and adopted padded head node changes from: * * data structure modified to avoid false sharing between head and tail Ref as per implementation of MpscLinkedQueue * on JCTools project. */ final class MpscLinkedQueue extends MpscLinkedQueueTailRef implements Queue { private static final long serialVersionUID = -1878402552271506449L; long p00, p01, p02, p03, p04, p05, p06, p07; long p30, p31, p32, p33, p34, p35, p36, p37; // offer() occurs at the tail of the linked list. // poll() occurs at the head of the linked list. // // Resulting layout is: // // head --next--> 1st element --next--> 2nd element --next--> ... tail (last element) // // where the head is a dummy node whose value is null. // // offer() appends a new node next to the tail using AtomicReference.getAndSet() // poll() removes head from the linked list and promotes the 1st element to the head, // setting its value to null if possible. // // Also note that this class extends AtomicReference for the "tail" slot (which is the one that is appended to) // since Unsafe does not expose XCHG operation intrinsically. MpscLinkedQueue() { MpscLinkedQueueNode tombstone = new DefaultNode(null); setHeadRef(tombstone); setTailRef(tombstone); } /** * Returns the node right next to the head, which contains the first element of this queue. */ private MpscLinkedQueueNode peekNode() { MpscLinkedQueueNode head = headRef(); MpscLinkedQueueNode next = head.next(); if (next == null && head != tailRef()) { // if tail != head this is not going to change until consumer makes progress // we can avoid reading the head and just spin on next until it shows up // // See https://github.com/akka/akka/pull/15596 do { next = head.next(); } while (next == null); } return next; } @Override @SuppressWarnings("unchecked") public boolean offer(E value) { if (value == null) { throw new NullPointerException("value"); } final MpscLinkedQueueNode newTail; if (value instanceof MpscLinkedQueueNode) { newTail = (MpscLinkedQueueNode) value; newTail.setNext(null); } else { newTail = new DefaultNode(value); } MpscLinkedQueueNode oldTail = getAndSetTailRef(newTail); oldTail.setNext(newTail); return true; } @Override public E poll() { final MpscLinkedQueueNode next = peekNode(); if (next == null) { return null; } // next becomes a new head. MpscLinkedQueueNode oldHead = headRef(); // Similar to 'headRef.node = next', but slightly faster (storestore vs loadstore) // See: http://robsjava.blogspot.com/2013/06/a-faster-volatile.html // See: http://psy-lob-saw.blogspot.com/2012/12/atomiclazyset-is-performance-win-for.html lazySetHeadRef(next); // Break the linkage between the old head and the new head. oldHead.unlink(); return next.clearMaybe(); } @Override public E peek() { final MpscLinkedQueueNode next = peekNode(); if (next == null) { return null; } return next.value(); } @Override public int size() { int count = 0; MpscLinkedQueueNode n = peekNode(); for (;;) { if (n == null) { break; } count ++; n = n.next(); } return count; } @Override public boolean isEmpty() { return peekNode() == null; } @Override public boolean contains(Object o) { MpscLinkedQueueNode n = peekNode(); for (;;) { if (n == null) { break; } if (n.value() == o) { return true; } n = n.next(); } return false; } @Override public Iterator iterator() { return new Iterator() { private MpscLinkedQueueNode node = peekNode(); @Override public boolean hasNext() { return node != null; } @Override public E next() { MpscLinkedQueueNode node = this.node; if (node == null) { throw new NoSuchElementException(); } E value = node.value(); this.node = node.next(); return value; } @Override public void remove() { throw new UnsupportedOperationException(); } }; } @Override public boolean add(E e) { if (offer(e)) { return true; } throw new IllegalStateException("queue full"); } @Override public E remove() { E e = poll(); if (e != null) { return e; } throw new NoSuchElementException(); } @Override public E element() { E e = peek(); if (e != null) { return e; } throw new NoSuchElementException(); } @Override public Object[] toArray() { final Object[] array = new Object[size()]; final Iterator it = iterator(); for (int i = 0; i < array.length; i ++) { if (it.hasNext()) { array[i] = it.next(); } else { return Arrays.copyOf(array, i); } } return array; } @Override @SuppressWarnings("unchecked") public T[] toArray(T[] a) { final int size = size(); final T[] array; if (a.length >= size) { array = a; } else { array = (T[]) Array.newInstance(a.getClass().getComponentType(), size); } final Iterator it = iterator(); for (int i = 0; i < array.length; i++) { if (it.hasNext()) { array[i] = (T) it.next(); } else { if (a == array) { array[i] = null; return array; } if (a.length < i) { return Arrays.copyOf(array, i); } System.arraycopy(array, 0, a, 0, i); if (a.length > i) { a[i] = null; } return a; } } return array; } @Override public boolean remove(Object o) { throw new UnsupportedOperationException(); } @Override public boolean containsAll(Collection c) { for (Object e: c) { if (!contains(e)) { return false; } } return true; } @Override public boolean addAll(Collection c) { if (c == null) { throw new NullPointerException("c"); } if (c == this) { throw new IllegalArgumentException("c == this"); } boolean modified = false; for (E e: c) { add(e); modified = true; } return modified; } @Override public boolean removeAll(Collection c) { throw new UnsupportedOperationException(); } @Override public boolean retainAll(Collection c) { throw new UnsupportedOperationException(); } @Override public void clear() { while (poll() != null) { continue; } } private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); for (E e: this) { out.writeObject(e); } out.writeObject(null); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); final MpscLinkedQueueNode tombstone = new DefaultNode(null); setHeadRef(tombstone); setTailRef(tombstone); for (;;) { @SuppressWarnings("unchecked") E e = (E) in.readObject(); if (e == null) { break; } add(e); } } private static final class DefaultNode extends MpscLinkedQueueNode { private T value; DefaultNode(T value) { this.value = value; } @Override public T value() { return value; } @Override protected T clearMaybe() { T value = this.value; this.value = null; return value; } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy