blob: a1ebd586bf867f1e2e6750602800e966ba028852 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF 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.
*/
package org.apache.ignite.internal.util;
import java.util.Collection;
import java.util.Comparator;
import java.util.NoSuchElementException;
import java.util.SortedSet;
import java.util.concurrent.atomic.AtomicInteger;
/**
* Concurrent ordered set that automatically manages its maximum size.
* Once it exceeds its maximum, it will start removing smallest elements
* until the maximum is reached again.
* <p>
* Note that due to concurrent nature of this set, it may grow slightly
* larger than its maximum allowed size, but in this case it will quickly
* readjust back to allowed size.
* <p>
* Note that {@link #remove(Object)} method is not supported for this kind of set.
*/
public class GridBoundedConcurrentOrderedSet<E> extends GridConcurrentSkipListSet<E> {
/** */
private static final long serialVersionUID = 0L;
/** Element count. */
private final AtomicInteger cnt = new AtomicInteger(0);
/** Maximum size. */
private int max;
/**
* Constructs a new, empty set that orders its elements according to
* their {@linkplain Comparable natural ordering}.
*
* @param max Upper bound of this set.
*/
public GridBoundedConcurrentOrderedSet(int max) {
assert max > 0;
this.max = max;
}
/**
* Constructs a new, empty set that orders its elements according to
* the specified comparator.
*
* @param max Upper bound of this set.
* @param comp the comparator that will be used to order this set.
* If <tt>null</tt>, the {@linkplain Comparable natural
* ordering} of the elements will be used.
*/
public GridBoundedConcurrentOrderedSet(int max, Comparator<? super E> comp) {
super(comp);
assert max > 0;
this.max = max;
}
/**
* Constructs a new set containing the elements in the specified
* collection, that orders its elements according to their
* {@linkplain Comparable natural ordering}.
*
* @param max Upper bound of this set.
* @param c The elements that will comprise the new set
* @throws ClassCastException if the elements in <tt>c</tt> are
* not {@link Comparable}, or are not mutually comparable
* @throws NullPointerException if the specified collection or any
* of its elements are {@code null}.
*/
public GridBoundedConcurrentOrderedSet(int max, Collection<? extends E> c) {
super(c);
assert max > 0;
this.max = max;
}
/**
* Constructs a new set containing the same elements and using the
* same ordering as the specified sorted set.
*
* @param max Upper bound of this set.
* @param s sorted set whose elements will comprise the new set
* @throws NullPointerException if the specified sorted set or any
* of its elements are {@code null}.
*/
public GridBoundedConcurrentOrderedSet(int max, SortedSet<E> s) {
super(s);
assert max > 0;
this.max = max;
}
/** {@inheritDoc} */
@Override public boolean add(E e) {
GridArgumentCheck.notNull(e, "e");
if (super.add(e)) {
cnt.incrementAndGet();
int c;
while ((c = cnt.get()) > max) {
// Decrement count.
if (cnt.compareAndSet(c, c - 1)) {
try {
while (!super.remove(first())) {
// No-op.
}
}
catch (NoSuchElementException e1) {
e1.printStackTrace(); // Should never happen.
assert false : "Internal error in grid bounded ordered set.";
}
}
}
return true;
}
return false;
}
/**
* Approximate size at this point of time. Note, that unlike {@code size}
* methods on other {@code concurrent} collections, this method executes
* in constant time without traversal of the elements.
*
* @return Approximate set size at this point of time.
*/
@Override public int size() {
int size = cnt.get();
return size < 0 ? 0 : size;
}
/** {@inheritDoc} */
@SuppressWarnings({"unchecked"})
@Override public GridBoundedConcurrentOrderedSet<E> clone() {
GridBoundedConcurrentOrderedSet<E> s = (GridBoundedConcurrentOrderedSet<E>)super.clone();
s.max = max;
return s;
}
/**
* This method is not supported and always throws {@link UnsupportedOperationException}.
*
* @param o {@inheritDoc}
* @return {@inheritDoc}
*/
@Override public boolean remove(Object o) {
if (super.remove(o)) {
cnt.decrementAndGet();
return true;
}
return false;
}
}