[] segments = this.segments;
- long sum = 0;
- long check = 0;
- int[] mc = new int[segments.length];
- // Try a few times to get accurate count. On failure due to continuous
- // async changes in table, resort to locking.
- for (int k = 0; k < RETRIES_BEFORE_LOCK; ++ k) {
- check = 0;
- sum = 0;
- int mcsum = 0;
- for (int i = 0; i < segments.length; ++ i) {
- sum += segments[i].count;
- mcsum += mc[i] = segments[i].modCount;
- }
- if (mcsum != 0) {
- for (int i = 0; i < segments.length; ++ i) {
- check += segments[i].count;
- if (mc[i] != segments[i].modCount) {
- check = -1; // force retry
- break;
- }
- }
- }
- if (check == sum) {
- break;
- }
- }
- if (check != sum) { // Resort to locking all segments
- sum = 0;
- for (int i = 0; i < segments.length; ++ i) {
- segments[i].lock();
- }
- for (int i = 0; i < segments.length; ++ i) {
- sum += segments[i].count;
- }
- for (int i = 0; i < segments.length; ++ i) {
- segments[i].unlock();
- }
- }
- if (sum > Integer.MAX_VALUE) {
- return Integer.MAX_VALUE;
- } else {
- return (int) sum;
- }
- }
-
- /**
- * Returns the value to which the specified key is mapped, or {@code null}
- * if this map contains no mapping for the key.
- *
- * More formally, if this map contains a mapping from a key {@code k} to
- * a value {@code v} such that {@code key.equals(k)}, then this method
- * returns {@code v}; otherwise it returns {@code null}. (There can be at
- * most one such mapping.)
- *
- * @throws NullPointerException if the specified key is null
- */
- @Override
- public V get(Object key) {
- int hash = hashOf(key);
- return segmentFor(hash).get(key, hash);
- }
-
- /**
- * Tests if the specified object is a key in this table.
- *
- * @param key possible key
- * @return true if and only if the specified object is a key in
- * this table, as determined by the equals method;
- * false otherwise.
- * @throws NullPointerException if the specified key is null
- */
- @Override
- public boolean containsKey(Object key) {
- int hash = hashOf(key);
- return segmentFor(hash).containsKey(key, hash);
- }
-
- /**
- * Returns true if this map maps one or more keys to the specified
- * value. Note: This method requires a full internal traversal of the hash
- * table, and so is much slower than method containsKey.
- *
- * @param value value whose presence in this map is to be tested
- * @return true if this map maps one or more keys to the specified
- * value
- * @throws NullPointerException if the specified value is null
- */
-
- @Override
- public boolean containsValue(Object value) {
- if (value == null) {
- throw new NullPointerException();
- }
-
- // See explanation of modCount use above
-
- final Segment[] segments = this.segments;
- int[] mc = new int[segments.length];
-
- // Try a few times without locking
- for (int k = 0; k < RETRIES_BEFORE_LOCK; ++ k) {
- int mcsum = 0;
- for (int i = 0; i < segments.length; ++ i) {
- mcsum += mc[i] = segments[i].modCount;
- if (segments[i].containsValue(value)) {
- return true;
- }
- }
- boolean cleanSweep = true;
- if (mcsum != 0) {
- for (int i = 0; i < segments.length; ++ i) {
- if (mc[i] != segments[i].modCount) {
- cleanSweep = false;
- break;
- }
- }
- }
- if (cleanSweep) {
- return false;
- }
- }
- // Resort to locking all segments
- for (int i = 0; i < segments.length; ++ i) {
- segments[i].lock();
- }
- boolean found = false;
- try {
- for (int i = 0; i < segments.length; ++ i) {
- if (segments[i].containsValue(value)) {
- found = true;
- break;
- }
- }
- } finally {
- for (int i = 0; i < segments.length; ++ i) {
- segments[i].unlock();
- }
- }
- return found;
- }
-
- /**
- * Legacy method testing if some key maps into the specified value in this
- * table. This method is identical in functionality to
- * {@link #containsValue}, and exists solely to ensure full compatibility
- * with class {@link java.util.Hashtable}, which supported this method prior to
- * introduction of the Java Collections framework.
- *
- * @param value a value to search for
- * @return true if and only if some key maps to the value
- * argument in this table as determined by the equals
- * method; false otherwise
- * @throws NullPointerException if the specified value is null
- */
- public boolean contains(Object value) {
- return containsValue(value);
- }
-
- /**
- * Maps the specified key to the specified value in this table. Neither the
- * key nor the value can be null.
- *
- * The value can be retrieved by calling the get method with a
- * key that is equal to the original key.
- *
- * @param key key with which the specified value is to be associated
- * @param value value to be associated with the specified key
- * @return the previous value associated with key, or null
- * if there was no mapping for key
- * @throws NullPointerException if the specified key or value is null
- */
- @Override
- public V put(K key, V value) {
- if (value == null) {
- throw new NullPointerException();
- }
- int hash = hashOf(key);
- return segmentFor(hash).put(key, hash, value, false);
- }
-
- /**
- * {@inheritDoc}
- *
- * @return the previous value associated with the specified key, or
- * null if there was no mapping for the key
- * @throws NullPointerException if the specified key or value is null
- */
- public V putIfAbsent(K key, V value) {
- if (value == null) {
- throw new NullPointerException();
- }
- int hash = hashOf(key);
- return segmentFor(hash).put(key, hash, value, true);
- }
-
- /**
- * Copies all of the mappings from the specified map to this one. These
- * mappings replace any mappings that this map had for any of the keys
- * currently in the specified map.
- *
- * @param m mappings to be stored in this map
- */
- @Override
- public void putAll(Map extends K, ? extends V> m) {
- for (Entry extends K, ? extends V> e: m.entrySet()) {
- put(e.getKey(), e.getValue());
- }
- }
-
- /**
- * Removes the key (and its corresponding value) from this map. This method
- * does nothing if the key is not in the map.
- *
- * @param key the key that needs to be removed
- * @return the previous value associated with key, or null
- * if there was no mapping for key
- * @throws NullPointerException if the specified key is null
- */
- @Override
- public V remove(Object key) {
- int hash = hashOf(key);
- return segmentFor(hash).remove(key, hash, null, false);
- }
-
- /**
- * {@inheritDoc}
- *
- * @throws NullPointerException if the specified key is null
- */
- public boolean remove(Object key, Object value) {
- int hash = hashOf(key);
- if (value == null) {
- return false;
- }
- return segmentFor(hash).remove(key, hash, value, false) != null;
- }
-
- /**
- * {@inheritDoc}
- *
- * @throws NullPointerException if any of the arguments are null
- */
- public boolean replace(K key, V oldValue, V newValue) {
- if (oldValue == null || newValue == null) {
- throw new NullPointerException();
- }
- int hash = hashOf(key);
- return segmentFor(hash).replace(key, hash, oldValue, newValue);
- }
-
- /**
- * {@inheritDoc}
- *
- * @return the previous value associated with the specified key, or
- * null if there was no mapping for the key
- * @throws NullPointerException if the specified key or value is null
- */
- public V replace(K key, V value) {
- if (value == null) {
- throw new NullPointerException();
- }
- int hash = hashOf(key);
- return segmentFor(hash).replace(key, hash, value);
- }
-
- /**
- * Removes all of the mappings from this map.
- */
- @Override
- public void clear() {
- for (int i = 0; i < segments.length; ++ i) {
- segments[i].clear();
- }
- }
-
- /**
- * Returns a {@link java.util.Set} view of the keys contained in this map. The set is
- * backed by the map, so changes to the map are reflected in the set, and
- * vice-versa. The set supports element removal, which removes the
- * corresponding mapping from this map, via the Iterator.remove,
- * Set.remove, removeAll, retainAll, and
- * clear operations. It does not support the add or
- * addAll operations.
- *
- *
The view's iterator is a "weakly consistent" iterator that
- * will never throw {@link java.util.ConcurrentModificationException}, and guarantees
- * to traverse elements as they existed upon construction of the iterator,
- * and may (but is not guaranteed to) reflect any modifications subsequent
- * to construction.
- */
- @Override
- public Set keySet() {
- Set ks = keySet;
- return ks != null? ks : (keySet = new KeySet());
- }
-
- /**
- * Returns a {@link java.util.Collection} view of the values contained in this map.
- * The collection is backed by the map, so changes to the map are reflected
- * in the collection, and vice-versa. The collection supports element
- * removal, which removes the corresponding mapping from this map, via the
- * Iterator.remove, Collection.remove, removeAll,
- * retainAll, and clear operations. It does not support
- * the add or addAll operations.
- *
- * The view's iterator is a "weakly consistent" iterator that
- * will never throw {@link java.util.ConcurrentModificationException}, and guarantees
- * to traverse elements as they existed upon construction of the iterator,
- * and may (but is not guaranteed to) reflect any modifications subsequent
- * to construction.
- */
- @Override
- public Collection values() {
- Collection vs = values;
- return vs != null? vs : (values = new Values());
- }
-
- /**
- * Returns a {@link java.util.Set} view of the mappings contained in this map.
- * The set is backed by the map, so changes to the map are reflected in the
- * set, and vice-versa. The set supports element removal, which removes the
- * corresponding mapping from the map, via the Iterator.remove,
- * Set.remove, removeAll, retainAll, and
- * clear operations. It does not support the add or
- * addAll operations.
- *
- * The view's iterator is a "weakly consistent" iterator that
- * will never throw {@link java.util.ConcurrentModificationException}, and guarantees
- * to traverse elements as they existed upon construction of the iterator,
- * and may (but is not guaranteed to) reflect any modifications subsequent
- * to construction.
- */
- @Override
- public Set> entrySet() {
- Set> es = entrySet;
- return es != null? es : (entrySet = new EntrySet());
- }
-
- /**
- * Returns an enumeration of the keys in this table.
- *
- * @return an enumeration of the keys in this table
- * @see #keySet()
- */
- public Enumeration keys() {
- return new KeyIterator();
- }
-
- /**
- * Returns an enumeration of the values in this table.
- *
- * @return an enumeration of the values in this table
- * @see #values()
- */
- public Enumeration elements() {
- return new ValueIterator();
- }
-
- /* ---------------- Iterator Support -------------- */
-
- abstract class HashIterator {
- int nextSegmentIndex;
- int nextTableIndex;
- HashEntry[] currentTable;
- HashEntry nextEntry;
- HashEntry lastReturned;
- K currentKey; // Strong reference to weak key (prevents gc)
-
- HashIterator() {
- nextSegmentIndex = segments.length - 1;
- nextTableIndex = -1;
- advance();
- }
-
- public void rewind() {
- nextSegmentIndex = segments.length - 1;
- nextTableIndex = -1;
- currentTable = null;
- nextEntry = null;
- lastReturned = null;
- currentKey = null;
- advance();
- }
-
- public boolean hasMoreElements() {
- return hasNext();
- }
-
- final void advance() {
- if (nextEntry != null && (nextEntry = nextEntry.next) != null) {
- return;
- }
-
- while (nextTableIndex >= 0) {
- if ((nextEntry = currentTable[nextTableIndex --]) != null) {
- return;
- }
- }
-
- while (nextSegmentIndex >= 0) {
- Segment seg = segments[nextSegmentIndex --];
- if (seg.count != 0) {
- currentTable = seg.table;
- for (int j = currentTable.length - 1; j >= 0; -- j) {
- if ((nextEntry = currentTable[j]) != null) {
- nextTableIndex = j - 1;
- return;
- }
- }
- }
- }
- }
-
- public boolean hasNext() {
- while (nextEntry != null) {
- if (nextEntry.key() != null) {
- return true;
- }
- advance();
- }
-
- return false;
- }
-
- HashEntry nextEntry() {
- do {
- if (nextEntry == null) {
- throw new NoSuchElementException();
- }
-
- lastReturned = nextEntry;
- currentKey = lastReturned.key();
- advance();
- } while (currentKey == null); // Skip GC'd keys
-
- return lastReturned;
- }
-
- public void remove() {
- if (lastReturned == null) {
- throw new IllegalStateException();
- }
- ConcurrentIdentityHashMap.this.remove(currentKey);
- lastReturned = null;
- }
- }
-
- final class KeyIterator
- extends HashIterator implements ReusableIterator, Enumeration {
-
- public K next() {
- return super.nextEntry().key();
- }
-
- public K nextElement() {
- return super.nextEntry().key();
- }
- }
-
- final class ValueIterator
- extends HashIterator implements ReusableIterator, Enumeration {
-
- public V next() {
- return super.nextEntry().value();
- }
-
- public V nextElement() {
- return super.nextEntry().value();
- }
- }
-
- /*
- * This class is needed for JDK5 compatibility.
- */
- static class SimpleEntry implements Entry {
-
- private static final long serialVersionUID = -8144765946475398746L;
-
- private final K key;
-
- private V value;
-
- public SimpleEntry(K key, V value) {
- this.key = key;
- this.value = value;
-
- }
-
- public SimpleEntry(Entry extends K, ? extends V> entry) {
- this.key = entry.getKey();
- this.value = entry.getValue();
-
- }
-
- public K getKey() {
- return key;
- }
-
- public V getValue() {
- return value;
- }
-
- public V setValue(V value) {
- V oldValue = this.value;
- this.value = value;
- return oldValue;
- }
-
- @Override
- public boolean equals(Object o) {
- if (!(o instanceof Entry, ?>)) {
- return false;
- }
- @SuppressWarnings("rawtypes")
- Entry e = (Entry) o;
- return eq(key, e.getKey()) && eq(value, e.getValue());
- }
-
- @Override
- public int hashCode() {
- return (key == null? 0 : key.hashCode()) ^ (value == null? 0 : value.hashCode());
- }
-
- @Override
- public String toString() {
- return key + "=" + value;
- }
-
- private static boolean eq(Object o1, Object o2) {
- return o1 == null? o2 == null : o1.equals(o2);
- }
- }
-
- /**
- * Custom Entry class used by EntryIterator.next(), that relays setValue
- * changes to the underlying map.
- */
- final class WriteThroughEntry extends SimpleEntry {
-
- WriteThroughEntry(K k, V v) {
- super(k, v);
- }
-
- /**
- * Set our entry's value and write through to the map. The value to
- * return is somewhat arbitrary here. Since a WriteThroughEntry does not
- * necessarily track asynchronous changes, the most recent "previous"
- * value could be different from what we return (or could even have been
- * removed in which case the put will re-establish). We do not and can
- * not guarantee more.
- */
- @Override
- public V setValue(V value) {
-
- if (value == null) {
- throw new NullPointerException();
- }
- V v = super.setValue(value);
- ConcurrentIdentityHashMap.this.put(getKey(), value);
- return v;
- }
-
- }
-
- final class EntryIterator extends HashIterator implements
- ReusableIterator> {
- public Entry next() {
- HashEntry e = super.nextEntry();
- return new WriteThroughEntry(e.key(), e.value());
- }
- }
-
- final class KeySet extends AbstractSet {
- @Override
- public Iterator iterator() {
-
- return new KeyIterator();
- }
-
- @Override
- public int size() {
- return ConcurrentIdentityHashMap.this.size();
- }
-
- @Override
- public boolean isEmpty() {
- return ConcurrentIdentityHashMap.this.isEmpty();
- }
-
- @Override
- public boolean contains(Object o) {
- return ConcurrentIdentityHashMap.this.containsKey(o);
- }
-
- @Override
- public boolean remove(Object o) {
- return ConcurrentIdentityHashMap.this.remove(o) != null;
-
- }
-
- @Override
- public void clear() {
- ConcurrentIdentityHashMap.this.clear();
- }
- }
-
- final class Values extends AbstractCollection {
- @Override
- public Iterator iterator() {
- return new ValueIterator();
- }
-
- @Override
- public int size() {
- return ConcurrentIdentityHashMap.this.size();
- }
-
- @Override
- public boolean isEmpty() {
- return ConcurrentIdentityHashMap.this.isEmpty();
- }
-
- @Override
- public boolean contains(Object o) {
- return ConcurrentIdentityHashMap.this.containsValue(o);
- }
-
- @Override
- public void clear() {
- ConcurrentIdentityHashMap.this.clear();
- }
- }
-
- final class EntrySet extends AbstractSet> {
- @Override
- public Iterator> iterator() {
- return new EntryIterator();
- }
-
- @Override
- public boolean contains(Object o) {
- if (!(o instanceof Entry, ?>)) {
- return false;
- }
- Entry, ?> e = (Entry, ?>) o;
- V v = ConcurrentIdentityHashMap.this.get(e.getKey());
- return v != null && v.equals(e.getValue());
- }
-
- @Override
- public boolean remove(Object o) {
- if (!(o instanceof Entry, ?>)) {
- return false;
- }
- Entry, ?> e = (Entry, ?>) o;
- return ConcurrentIdentityHashMap.this.remove(e.getKey(), e.getValue());
- }
-
- @Override
- public int size() {
- return ConcurrentIdentityHashMap.this.size();
- }
-
- @Override
- public boolean isEmpty() {
- return ConcurrentIdentityHashMap.this.isEmpty();
- }
-
- @Override
- public void clear() {
- ConcurrentIdentityHashMap.this.clear();
- }
- }
-}
diff --git a/akka-actor/src/main/java/akka/util/internal/HashedWheelTimer.java b/akka-actor/src/main/java/akka/util/internal/HashedWheelTimer.java
index fcdee4866f..b455957fc2 100644
--- a/akka-actor/src/main/java/akka/util/internal/HashedWheelTimer.java
+++ b/akka-actor/src/main/java/akka/util/internal/HashedWheelTimer.java
@@ -20,10 +20,13 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
+import java.util.Iterator;
import java.util.concurrent.ThreadFactory;
+import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.locks.ReadWriteLock;
import java.util.concurrent.locks.ReentrantReadWriteLock;
+import akka.dispatch.SystemMessage;
import akka.util.Helpers;
import scala.concurrent.duration.Duration;
import scala.concurrent.duration.FiniteDuration;
@@ -89,7 +92,6 @@ public class HashedWheelTimer implements Timer {
boolean shutdown = false;
final long tickDuration;
final Set[] wheel;
- final ReusableIterator[] iterators;
final int mask;
final ReadWriteLock lock = new ReentrantReadWriteLock();
volatile int wheelCursor;
@@ -127,7 +129,6 @@ public class HashedWheelTimer implements Timer {
// Normalize ticksPerWheel to power of two and initialize the wheel.
wheel = createWheel(ticksPerWheel);
- iterators = createIterators(wheel);
mask = wheel.length - 1;
// Convert to standardized tickDuration
@@ -152,20 +153,11 @@ public class HashedWheelTimer implements Timer {
final Set[] wheel = new Set[normalizeTicksPerWheel(ticksPerWheel)];
for (int i = 0; i < wheel.length; i ++) {
- wheel[i] = Collections.newSetFromMap(new ConcurrentIdentityHashMap(16, 0.95f, 4));
+ wheel[i] = Collections.newSetFromMap(new ConcurrentHashMap(16, 0.95f, 4));
}
return wheel;
}
- @SuppressWarnings("unchecked")
- private static ReusableIterator[] createIterators(Set[] wheel) {
- ReusableIterator[] iterators = new ReusableIterator[wheel.length];
- for (int i = 0; i < wheel.length; i ++) {
- iterators[i] = (ReusableIterator) wheel[i].iterator();
- }
- return iterators;
- }
-
private static int normalizeTicksPerWheel(int ticksPerWheel) {
int normalizedTicksPerWheel = 1;
while (normalizedTicksPerWheel < ticksPerWheel) {
@@ -323,16 +315,16 @@ public class HashedWheelTimer implements Timer {
lock.writeLock().lock();
try {
final int newWheelCursor = wheelCursor = wheelCursor + 1 & mask;
- return fetchExpiredTimeouts(iterators[newWheelCursor], deadline);
+ return fetchExpiredTimeouts(wheel[newWheelCursor], deadline);
} finally {
lock.writeLock().unlock();
}
}
- private ArrayList fetchExpiredTimeouts(final ReusableIterator i, final long deadline) {
+ private ArrayList fetchExpiredTimeouts(final Iterable it, final long deadline) {
final ArrayList expiredTimeouts = new ArrayList();
List slipped = null;
- i.rewind();
+ Iterator i = it.iterator();
while (i.hasNext()) {
HashedWheelTimeout timeout = i.next();
if (timeout.remainingRounds <= 0) {
@@ -483,6 +475,14 @@ public class HashedWheelTimer implements Timer {
}
}
+ @Override public final int hashCode() {
+ return System.identityHashCode(this);
+ }
+
+ @Override public final boolean equals(final Object that) {
+ return this == that;
+ }
+
@Override
public String toString() {
final long currentTime = System.nanoTime();
diff --git a/akka-actor/src/main/java/akka/util/internal/ReusableIterator.java b/akka-actor/src/main/java/akka/util/internal/ReusableIterator.java
deleted file mode 100644
index 8c8e5e50e5..0000000000
--- a/akka-actor/src/main/java/akka/util/internal/ReusableIterator.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2009 Red Hat, Inc.
- *
- * Red Hat 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 akka.util.internal;
-
-import java.util.Iterator;
-
-/**
- * @author The Netty Project
- * @author Trustin Lee
- * @version $Rev: 2080 $, $Date: 2010-01-26 18:04:19 +0900 (Tue, 26 Jan 2010) $
- */
-public interface ReusableIterator extends Iterator {
- void rewind();
-}
diff --git a/akka-actor/src/main/scala/akka/actor/ActorSystem.scala b/akka-actor/src/main/scala/akka/actor/ActorSystem.scala
index ef253884da..d99f716e8e 100644
--- a/akka-actor/src/main/scala/akka/actor/ActorSystem.scala
+++ b/akka-actor/src/main/scala/akka/actor/ActorSystem.scala
@@ -16,8 +16,8 @@ import scala.util.{ Failure, Success }
import scala.util.control.NonFatal
import akka.util._
import java.io.Closeable
-import akka.util.internal.{ HashedWheelTimer, ConcurrentIdentityHashMap }
-import java.util.concurrent.{ ThreadFactory, CountDownLatch, TimeoutException, RejectedExecutionException }
+import akka.util.internal.{ HashedWheelTimer }
+import java.util.concurrent.{ ConcurrentHashMap, ThreadFactory, CountDownLatch, TimeoutException, RejectedExecutionException }
import java.util.concurrent.TimeUnit.MILLISECONDS
import akka.actor.dungeon.ChildrenContainer
@@ -628,7 +628,7 @@ private[akka] class ActorSystemImpl(val name: String, applicationConfig: Config,
case _ ⇒
}
- private val extensions = new ConcurrentIdentityHashMap[ExtensionId[_], AnyRef]
+ private val extensions = new ConcurrentHashMap[ExtensionId[_], AnyRef]
/**
* Returns any extension registered to the specified Extension or returns null if not registered
diff --git a/akka-actor/src/main/scala/akka/actor/Extension.scala b/akka-actor/src/main/scala/akka/actor/Extension.scala
index 9b6f950d3f..38b6a6d37c 100644
--- a/akka-actor/src/main/scala/akka/actor/Extension.scala
+++ b/akka-actor/src/main/scala/akka/actor/Extension.scala
@@ -52,6 +52,9 @@ trait ExtensionId[T <: Extension] {
* internal use only.
*/
def createExtension(system: ExtendedActorSystem): T
+
+ override final def hashCode: Int = System.identityHashCode(this)
+ override final def equals(other: Any): Boolean = this eq other.asInstanceOf[AnyRef]
}
/**