[infinispan-commits] Infinispan SVN: r881 - in trunk/core/src: main/java/org/infinispan/distribution and 1 other directories.
infinispan-commits at lists.jboss.org
infinispan-commits at lists.jboss.org
Tue Sep 29 06:53:06 EDT 2009
Author: manik.surtani at jboss.com
Date: 2009-09-29 06:53:05 -0400 (Tue, 29 Sep 2009)
New Revision: 881
Removed:
trunk/core/src/main/java/org/infinispan/container/SpinLockBasedFIFODataContainer.java
trunk/core/src/main/java/org/infinispan/container/SpinLockBasedLRUDataContainer.java
trunk/core/src/test/java/org/infinispan/container/SpinLockBasedFIFODataContainerTest.java
trunk/core/src/test/java/org/infinispan/container/SpinLockBasedLRUDataContainerTest.java
Modified:
trunk/core/src/main/java/org/infinispan/distribution/DefaultConsistentHash.java
Log:
Fixed from findbugs report
Deleted: trunk/core/src/main/java/org/infinispan/container/SpinLockBasedFIFODataContainer.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/container/SpinLockBasedFIFODataContainer.java 2009-09-29 10:37:36 UTC (rev 880)
+++ trunk/core/src/main/java/org/infinispan/container/SpinLockBasedFIFODataContainer.java 2009-09-29 10:53:05 UTC (rev 881)
@@ -1,647 +0,0 @@
-package org.infinispan.container;
-
-import net.jcip.annotations.ThreadSafe;
-
-import org.infinispan.container.entries.InternalCacheEntry;
-import org.infinispan.container.entries.InternalEntryFactory;
-import org.infinispan.util.Immutables;
-
-import java.util.AbstractCollection;
-import java.util.AbstractSet;
-import java.util.Collection;
-import java.util.Iterator;
-import java.util.Set;
-import java.util.concurrent.atomic.AtomicBoolean;
-import java.util.concurrent.locks.ReentrantLock;
-
-/**
- * A data container that exposes an iterator that is ordered based on order of entry into the container, with the oldest
- * entries first.
- * <p/>
- * This data container that maintains a concurrent hashtable of entries, and also maintains linking between the elements
- * for ordered iterators.
- * <p/>
- * This uses concepts from {@link java.util.concurrent.ConcurrentHashMap} in that it maintains a table of lockable
- * Segments, each of which is a specialized Hashtable, but HashEntries are also linked to each other such that they can
- * be navigated, like a {@link java.util.LinkedHashMap}. To ensure thread safety of links between entries, we follow
- * auxillary node ideas expressed in John D. Valois' paper, <a href="http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.41.9506"><i>Lock-Free
- * Linked Lists Using Compare-and-Swap</i></a>.
- * <p/>
- * The locks maintained on linkable entrues are implemented using {@link org.infinispan.container.SpinLockBasedFIFODataContainer.SpinLock}s,
- * and due to the nature of these spin locks, they should only be held for a minimal amount of time.
- *
- * @author Manik Surtani
- * @author Galder Zamarreño
- * @since 4.0
- */
- at ThreadSafe
-public class SpinLockBasedFIFODataContainer implements DataContainer {
- /**
- * The maximum capacity, used if a higher value is implicitly specified by either of the constructors with arguments.
- * MUST be a power of two <= 1<<30 to ensure that entries are indexable using ints.
- */
- static final int MAXIMUM_CAPACITY = 1 << 30;
-
- final LinkedEntry dummyEntry = new LinkedEntry(); // a dummy linked entry
-
- // -- these fields are all very similar to JDK's ConcurrentHashMap
-
- /**
- * Mask value for indexing into segments. The upper bits of a key's hash code are used to choose the segment.
- */
- final int segmentMask;
-
- /**
- * Shift value for indexing within segments.
- */
- final int segmentShift;
-
- /**
- * The segments, each of which is a specialized hash table
- */
- final Segment[] segments;
-
- Set<Object> keySet;
-
- public SpinLockBasedFIFODataContainer() {
- float loadFactor = 0.75f;
- int initialCapacity = 16;
- int concurrencyLevel = 16;
-
- // Find power-of-two sizes best matching arguments
- int sshift = 0;
- int ssize = 1;
- while (ssize < concurrencyLevel) {
- ++sshift;
- ssize <<= 1;
- }
- segmentShift = 32 - sshift;
- segmentMask = ssize - 1;
- this.segments = Segment.newArray(ssize);
-
- if (initialCapacity > MAXIMUM_CAPACITY)
- initialCapacity = MAXIMUM_CAPACITY;
- int c = initialCapacity / ssize;
- if (c * ssize < initialCapacity)
- ++c;
- int cap = 1;
- while (cap < c)
- cap <<= 1;
-
- for (int i = 0; i < this.segments.length; ++i) this.segments[i] = new Segment(cap, loadFactor);
- initLinks();
- }
-
- // ---------- Public API methods
-
- public InternalCacheEntry get(Object k) {
- int h = hash(k.hashCode());
- Segment s = segmentFor(h);
- LinkedEntry le = s.get(k, h);
- InternalCacheEntry ice = le == null ? null : le.entry;
- if (ice != null) {
- if (ice.isExpired()) {
- remove(k);
- ice = null;
- } else {
- ice.touch();
- }
- }
-
- return ice;
- }
-
- public void put(Object k, Object v, long lifespan, long maxIdle) {
- // do a normal put first.
- int h = hash(k.hashCode());
- Segment s = segmentFor(h);
- s.lock();
- LinkedEntry le = null;
- Aux before = null, after = null;
- boolean newEntry = false;
- try {
- le = s.get(k, h);
- InternalCacheEntry ice = le == null ? null : le.entry;
- if (ice == null) {
- newEntry = true;
- ice = InternalEntryFactory.create(k, v, lifespan, maxIdle);
- // only update linking if this is a new entry
- le = new LinkedEntry();
- le.lock();
- after = new Aux();
- after.lock();
- le.next = after;
- after.next = dummyEntry;
- } else {
- ice.setValue(v);
- ice = ice.setLifespan(lifespan).setMaxIdle(maxIdle);
- }
-
- le.entry = ice;
- s.locklessPut(k, h, le);
-
- if (newEntry) {
- dummyEntry.lock();
- (before = dummyEntry.prev).lock();
- before.next = le;
- le.prev = before;
- dummyEntry.prev = after;
- }
- } finally {
- if (newEntry) {
- if (le != null) {
- before.unlock();
- dummyEntry.unlock();
- after.unlock();
- le.unlock();
- }
- }
- s.unlock();
- }
- }
-
- public boolean containsKey(Object k) {
- int h = hash(k.hashCode());
- Segment s = segmentFor(h);
- LinkedEntry le = s.get(k, h);
- InternalCacheEntry ice = le == null ? null : le.entry;
- if (ice != null) {
- if (ice.isExpired()) {
- remove(k);
- ice = null;
- }
- }
-
- return ice != null;
- }
-
- public InternalCacheEntry remove(Object k) {
- int h = hash(k.hashCode());
- Segment s = segmentFor(h);
- s.lock();
- InternalCacheEntry ice = null;
- LinkedEntry le = null;
- boolean linksLocked = false;
- LinkedEntry nextEntry = null;
- Aux before = null, after = null;
- try {
- le = s.locklessRemove(k, h);
- if (le != null) {
- ice = le.entry;
- linksLocked = true;
- // need to unlink
- le.lock();
- (before = le.prev).lock();
- (after = le.next).lock();
- nextEntry = after.next;
- before.next = after.next;
- before.next.prev = before;
- }
- } finally {
- if (linksLocked) {
- before.unlock();
- after.unlock();
- le.unlock();
- }
- s.unlock();
- }
-
- if (ice == null || ice.isExpired())
- return null;
- else
- return ice;
- }
-
- public int size() {
- // approximate sizing is good enough
- int sz = 0;
- final Segment[] segs = segments;
- for (Segment s : segs) sz += s.count;
- return sz;
- }
-
- public void clear() {
- // This is expensive...
- // lock all segments
- for (Segment s : segments) s.lock();
- try {
- for (Segment s : segments) s.locklessClear();
- initLinks();
- } finally {
- for (Segment s : segments) s.unlock();
- }
- }
-
- public Set<Object> keySet() {
- if (keySet == null) keySet = new KeySet();
- return keySet;
- }
-
- public Set<InternalCacheEntry> entrySet() {
- return new EntrySet();
- }
-
- public Collection<Object> values() {
- return new Values();
- }
-
- public void purgeExpired() {
- for (InternalCacheEntry ice : this) {
- if (ice.isExpired()) remove(ice.getKey());
- }
- }
-
- public Iterator<InternalCacheEntry> iterator() {
- return new EntryIterator();
- }
-
- // --------------- Internals
-
- /**
- * Initializes links to an empty container
- */
- protected final void initLinks() {
- Aux tail = new Aux();
- try {
- tail.lock();
- dummyEntry.prev = tail;
- dummyEntry.next = tail;
- tail.next = dummyEntry;
- } finally {
- tail.unlock();
- dummyEntry.unlock();
- }
- }
-
- /**
- * Similar to ConcurrentHashMap's hash() function: applies a supplemental hash function to a given hashCode, which
- * defends against poor quality hash functions. This is critical because ConcurrentHashMap uses power-of-two length
- * hash tables, that otherwise encounter collisions for hashCodes that do not differ in lower or upper bits.
- */
- final int hash(int h) {
- // Spread bits to regularize both segment and index locations,
- // using variant of single-word Wang/Jenkins hash.
- h += (h << 15) ^ 0xffffcd7d;
- h ^= (h >>> 10);
- h += (h << 3);
- h ^= (h >>> 6);
- h += (h << 2) + (h << 14);
- return h ^ (h >>> 16);
- }
-
- /**
- * Returns the segment that should be used for key with given hash
- *
- * @param hash the hash code for the key
- * @return the segment
- */
- final Segment segmentFor(int hash) {
- return segments[(hash >>> segmentShift) & segmentMask];
- }
-
- /**
- * ConcurrentHashMap list entry. Note that this is never exported out as a user-visible Map.Entry.
- * <p/>
- * Because the value field is volatile, not final, it is legal wrt the Java Memory Model for an unsynchronized reader
- * to see null instead of initial value when read via a data race. Although a reordering leading to this is not
- * likely to ever actually occur, the Segment.readValueUnderLock method is used as a backup in case a null
- * (pre-initialized) value is ever seen in an unsynchronized access method.
- */
- static final class HashEntry {
- final Object key;
- final int hash;
- volatile LinkedEntry value;
- final HashEntry next;
-
- HashEntry(Object key, int hash, HashEntry next, LinkedEntry value) {
- this.key = key;
- this.hash = hash;
- this.next = next;
- this.value = value;
- }
- }
-
-
- /**
- * Very similar to a Segment in a ConcurrentHashMap
- */
- static final class Segment extends ReentrantLock {
- /**
- * The number of elements in this segment's region.
- */
- transient volatile int count;
-
- /**
- * The table is rehashed when its size exceeds this threshold. (The value of this field is always
- * <tt>(int)(capacity * loadFactor)</tt>.)
- */
- transient int threshold;
-
- /**
- * The per-segment table.
- */
- transient volatile HashEntry[] table;
-
- /**
- * The load factor for the hash table. Even though this value is same for all segments, it is replicated to avoid
- * needing links to outer object.
- *
- * @serial
- */
- final float loadFactor;
-
- Segment(int initialCapacity, float lf) {
- loadFactor = lf;
- setTable(new HashEntry[initialCapacity]);
- }
-
- static final Segment[] newArray(int i) {
- return new Segment[i];
- }
-
- /**
- * Sets table to new HashEntry array. Call only while holding lock or in constructor.
- */
- final void setTable(HashEntry[] newTable) {
- threshold = (int) (newTable.length * loadFactor);
- table = newTable;
- }
-
- /**
- * Returns properly casted first entry of bin for given hash.
- */
- final HashEntry getFirst(int hash) {
- HashEntry[] tab = table;
- return tab[hash & (tab.length - 1)];
- }
-
- /**
- * Reads value field of an entry under lock. Called if value field ever appears to be null. This is possible only
- * if a compiler happens to reorder a HashEntry initialization with its table assignment, which is legal under
- * memory model but is not known to ever occur.
- */
- final LinkedEntry readValueUnderLock(HashEntry e) {
- lock();
- try {
- return e.value;
- } finally {
- unlock();
- }
- }
-
- /* Specialized implementations of map methods */
-
- final LinkedEntry get(Object key, int hash) {
- if (count != 0) { // read-volatile
- HashEntry e = getFirst(hash);
- while (e != null) {
- if (e.hash == hash && key.equals(e.key)) {
- LinkedEntry v = e.value;
- if (v != null)
- return v;
- return readValueUnderLock(e); // recheck
- }
- e = e.next;
- }
- }
- return null;
- }
-
- /**
- * This put is lockless. Make sure you call segment.lock() first.
- */
- final LinkedEntry locklessPut(Object key, int hash, LinkedEntry value) {
- int c = count;
- if (c++ > threshold) // ensure capacity
- rehash();
- HashEntry[] tab = table;
- int index = hash & (tab.length - 1);
- HashEntry first = tab[index];
- HashEntry e = first;
- while (e != null && (e.hash != hash || !key.equals(e.key)))
- e = e.next;
-
- LinkedEntry oldValue;
- if (e != null) {
- oldValue = e.value;
- e.value = value;
- } else {
- oldValue = null;
- tab[index] = new HashEntry(key, hash, first, value);
- count = c; // write-volatile
- }
- return oldValue;
- }
-
- final void rehash() {
- HashEntry[] oldTable = table;
- int oldCapacity = oldTable.length;
- if (oldCapacity >= MAXIMUM_CAPACITY)
- return;
-
- /*
- * Reclassify nodes in each list to new Map. Because we are
- * using power-of-two expansion, the elements from each bin
- * must either stay at same index, or move with a power of two
- * offset. We eliminate unnecessary node creation by catching
- * cases where old nodes can be reused because their next
- * fields won't change. Statistically, at the default
- * threshold, only about one-sixth of them need cloning when
- * a table doubles. The nodes they replace will be garbage
- * collectable as soon as they are no longer referenced by any
- * reader thread that may be in the midst of traversing table
- * right now.
- */
-
- HashEntry[] newTable = new HashEntry[oldCapacity << 1];
- threshold = (int) (newTable.length * loadFactor);
- int sizeMask = newTable.length - 1;
- for (int i = 0; i < oldCapacity; i++) {
- // We need to guarantee that any existing reads of old Map can
- // proceed. So we cannot yet null out each bin.
- HashEntry e = oldTable[i];
-
- if (e != null) {
- HashEntry next = e.next;
- int idx = e.hash & sizeMask;
-
- // Single node on list
- if (next == null)
- newTable[idx] = e;
-
- else {
- // Reuse trailing consecutive sequence at same slot
- HashEntry lastRun = e;
- int lastIdx = idx;
- for (HashEntry last = next;
- last != null;
- last = last.next) {
- int k = last.hash & sizeMask;
- if (k != lastIdx) {
- lastIdx = k;
- lastRun = last;
- }
- }
- newTable[lastIdx] = lastRun;
-
- // Clone all remaining nodes
- for (HashEntry p = e; p != lastRun; p = p.next) {
- int k = p.hash & sizeMask;
- HashEntry n = newTable[k];
- newTable[k] = new HashEntry(p.key, p.hash, n, p.value);
- }
- }
- }
- }
- table = newTable;
- }
-
- /**
- * This is a lockless remove. Make sure you acquire locks using segment.lock() first.
- */
- final LinkedEntry locklessRemove(Object key, int hash) {
- int c = count - 1;
- HashEntry[] tab = table;
- int index = hash & (tab.length - 1);
- HashEntry first = tab[index];
- HashEntry e = first;
- while (e != null && (e.hash != hash || !key.equals(e.key)))
- e = e.next;
-
- LinkedEntry oldValue = null;
- if (e != null) {
- oldValue = e.value;
- // All entries following removed node can stay
- // in list, but all preceding ones need to be
- // cloned.
- HashEntry newFirst = e.next;
- for (HashEntry p = first; p != e; p = p.next)
- newFirst = new HashEntry(p.key, p.hash,
- newFirst, p.value);
- tab[index] = newFirst;
- count = c; // write-volatile
-
- }
- return oldValue;
- }
-
- /**
- * This is a lockless clear. Ensure you acquire locks on the segment first using segment.lock().
- */
- final void locklessClear() {
- if (count != 0) {
- HashEntry[] tab = table;
- for (int i = 0; i < tab.length; i++)
- tab[i] = null;
- count = 0; // write-volatile
- }
- }
- }
-
- protected final class KeySet extends AbstractSet<Object> {
- public Iterator<Object> iterator() {
- return new KeyIterator();
- }
-
- public int size() {
- return SpinLockBasedFIFODataContainer.this.size();
- }
- }
-
- protected final class Values extends AbstractCollection<Object> {
- public Iterator<Object> iterator() {
- return new ValueIterator();
- }
-
- public int size() {
- return SpinLockBasedFIFODataContainer.this.size();
- }
- }
-
- protected final class EntrySet extends AbstractSet<InternalCacheEntry> {
- public Iterator<InternalCacheEntry> iterator() {
- return new ImmutableEntryIterator();
- }
-
- public int size() {
- return SpinLockBasedFIFODataContainer.this.size();
- }
- }
-
- protected abstract class LinkedIterator {
- Aux nextAux = dummyEntry.next;
-
- public boolean hasNext() {
- return nextAux.next != dummyEntry;
- }
-
- public void remove() {
- throw new UnsupportedOperationException();
- }
- }
-
- protected final class EntryIterator extends LinkedIterator implements Iterator<InternalCacheEntry> {
- public InternalCacheEntry next() {
- LinkedEntry le = nextAux.next;
- if (le == dummyEntry) return null;
- nextAux = le.next;
- return le.entry;
- }
- }
-
- protected final class ImmutableEntryIterator extends LinkedIterator implements Iterator<InternalCacheEntry> {
- public InternalCacheEntry next() {
- LinkedEntry le = nextAux.next;
- if (le == dummyEntry) return null;
- nextAux = le.next;
- return Immutables.immutableInternalCacheEntry(le.entry);
- }
- }
-
- protected final class KeyIterator extends LinkedIterator implements Iterator<Object> {
- public Object next() {
- LinkedEntry le = nextAux.next;
- if (le == dummyEntry) return null;
- nextAux = le.next;
- return le.entry.getKey();
- }
- }
-
- protected final class ValueIterator extends LinkedIterator implements Iterator<Object> {
- public Object next() {
- LinkedEntry le = nextAux.next;
- if (le == dummyEntry) return null;
- nextAux = le.next;
- return le.entry.getValue();
- }
- }
-
- protected static abstract class SpinLock {
- final AtomicBoolean l = new AtomicBoolean(false);
-
- final void lock() {
- while (!l.compareAndSet(false, true)) {
- // spin, spin, spin!
- }
- }
-
- final boolean tryLock() {
- return l.compareAndSet(false, true);
- }
-
- final void unlock() {
- l.set(false);
- }
- }
-
- protected final static class Aux extends SpinLock {
- volatile LinkedEntry next;
- }
-
- protected final static class LinkedEntry extends SpinLock {
- volatile Aux prev;
- volatile Aux next;
- volatile InternalCacheEntry entry;
- }
-}
-
Deleted: trunk/core/src/main/java/org/infinispan/container/SpinLockBasedLRUDataContainer.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/container/SpinLockBasedLRUDataContainer.java 2009-09-29 10:37:36 UTC (rev 880)
+++ trunk/core/src/main/java/org/infinispan/container/SpinLockBasedLRUDataContainer.java 2009-09-29 10:53:05 UTC (rev 881)
@@ -1,136 +0,0 @@
-package org.infinispan.container;
-
-import net.jcip.annotations.ThreadSafe;
-
-import org.infinispan.container.entries.InternalCacheEntry;
-import org.infinispan.container.entries.InternalEntryFactory;
-
-/**
- * A data container that exposes an iterator that is ordered based on least recently used (visited) entries first.
- * <p/>
- * This builds on the {@link SpinLockBasedFIFODataContainer} by calling {@link
- * SpinLockBasedLRUDataContainer#updateLinks(org.infinispan.container.SpinLockBasedFIFODataContainer.LinkedEntry)} even for
- * {@link #get(Object)} invocations to make sure ordering is intact, as per LRU.
- * <p/>
- *
- * @author Manik Surtani
- * @author Galder Zamarreño
- * @since 4.0
- */
- at ThreadSafe
-public class SpinLockBasedLRUDataContainer extends SpinLockBasedFIFODataContainer {
-
- @Override
- public InternalCacheEntry get(Object k) {
- int h = hash(k.hashCode());
- Segment s = segmentFor(h);
- LinkedEntry le = s.get(k, h);
- InternalCacheEntry ice = le == null ? null : le.entry;
- if (ice != null) {
- if (ice.isExpired()) {
- remove(k);
- ice = null;
- } else {
- ice.touch();
- updateLinks(le);
- }
- }
-
- return ice;
- }
-
- @Override
- public void put(Object k, Object v, long lifespan, long maxIdle) {
- // do a normal put first.
- int h = hash(k.hashCode());
- Segment s = segmentFor(h);
- s.lock();
- LinkedEntry le = null;
- Aux before = null, after = null;
- boolean newEntry = false;
- try {
- le = s.get(k, h);
- InternalCacheEntry ice = le == null ? null : le.entry;
- if (ice == null) {
- newEntry = true;
- ice = InternalEntryFactory.create(k, v, lifespan, maxIdle);
- // only update linking if this is a new entry
- le = new LinkedEntry();
- le.lock();
- after = new Aux();
- after.lock();
- le.next = after;
- after.next = dummyEntry;
- } else {
- ice.setValue(v);
- ice = ice.setLifespan(lifespan).setMaxIdle(maxIdle);
- updateLinks(le);
- }
-
- le.entry = ice;
- s.locklessPut(k, h, le);
-
- if (newEntry) {
- dummyEntry.lock();
- (before = dummyEntry.prev).lock();
- before.next = le;
- le.prev = before;
- dummyEntry.prev = after;
- }
- } finally {
- if (newEntry) {
- if (le != null) {
- before.unlock();
- dummyEntry.unlock();
- after.unlock();
- le.unlock();
- }
- }
- s.unlock();
- }
- }
-
- /**
- * Updates links on this entry, moving it to the end of the linked list
- *
- * @param l linked entry to update
- */
- protected final void updateLinks(LinkedEntry l) {
- if (l.next != dummyEntry.prev) {
-
- // if we cannot lock l it means it is being updated by another process, either removing it or updating it anyway
- // so we can skip updating links in that case.
- if (l.tryLock()) {
- try {
- Aux before = l.prev;
- before.lock();
- Aux after = l.next;
- after.lock();
-
- LinkedEntry nextEntry = after.next;
- nextEntry.lock();
- dummyEntry.lock();
- Aux last = dummyEntry.prev;
- last.lock();
-
- try {
- last.next = l;
- l.prev = last;
- after.next = dummyEntry;
- dummyEntry.prev = after;
- nextEntry.prev = before;
- before.next = nextEntry;
- } finally {
- last.unlock();
- dummyEntry.unlock();
- nextEntry.unlock();
- after.unlock();
- before.unlock();
- }
- } finally {
- l.unlock();
- }
- }
- }
- }
-}
Modified: trunk/core/src/main/java/org/infinispan/distribution/DefaultConsistentHash.java
===================================================================
--- trunk/core/src/main/java/org/infinispan/distribution/DefaultConsistentHash.java 2009-09-29 10:37:36 UTC (rev 880)
+++ trunk/core/src/main/java/org/infinispan/distribution/DefaultConsistentHash.java 2009-09-29 10:53:05 UTC (rev 881)
@@ -48,7 +48,9 @@
}
public List<Address> locate(Object key, int replCount) {
- int hash = Math.abs(key.hashCode());
+ int keyHashCode = key.hashCode();
+ if (keyHashCode == Integer.MIN_VALUE) keyHashCode += 1;
+ int hash = Math.abs(keyHashCode);
int clusterSize = addresses.size();
int numCopiesToFind = min(replCount, clusterSize);
Deleted: trunk/core/src/test/java/org/infinispan/container/SpinLockBasedFIFODataContainerTest.java
===================================================================
--- trunk/core/src/test/java/org/infinispan/container/SpinLockBasedFIFODataContainerTest.java 2009-09-29 10:37:36 UTC (rev 880)
+++ trunk/core/src/test/java/org/infinispan/container/SpinLockBasedFIFODataContainerTest.java 2009-09-29 10:53:05 UTC (rev 881)
@@ -1,211 +0,0 @@
-package org.infinispan.container;
-
-import org.infinispan.container.entries.ImmortalCacheEntry;
-import org.infinispan.container.entries.InternalCacheEntry;
-import org.infinispan.container.entries.MortalCacheEntry;
-import org.infinispan.container.entries.TransientCacheEntry;
-import org.infinispan.container.entries.TransientMortalCacheEntry;
-import org.testng.annotations.Test;
-
-import java.util.Random;
-import java.util.concurrent.CountDownLatch;
-
- at Test(groups = "unit", testName = "container.SpinLockBasedFIFODataContainerTest")
-public class SpinLockBasedFIFODataContainerTest extends SimpleDataContainerTest {
-
- @Override
- protected DataContainer createContainer() {
- return new SpinLockBasedFIFODataContainer();
- }
-
- public void testOrdering() {
- long lifespan = 600000;
- long idle = 600000;
- for (int i = 0; i < 10; i++) dc.put("k" + i, "value", -1, -1);
- for (int i = 10; i < 20; i++) dc.put("k" + i, "value", lifespan, -1);
- for (int i = 20; i < 30; i++) dc.put("k" + i, "value", -1, idle);
- for (int i = 30; i < 40; i++) dc.put("k" + i, "value", lifespan, idle);
-
- // random visits
- Random r = new Random();
- for (int i = 0; i < 100; i++) dc.get("k" + r.nextInt(40));
-
- // ensure order is maintained.
- int i = 0;
- for (InternalCacheEntry ice : dc) {
- assert ice.getKey().equals("k" + i);
- if (i < 10) assert ice instanceof ImmortalCacheEntry;
- if (i >= 10 && i < 20) assert ice instanceof MortalCacheEntry;
- if (i >= 20 && i < 30) assert ice instanceof TransientCacheEntry;
- if (i >= 30 && i < 40) assert ice instanceof TransientMortalCacheEntry;
- i++;
- }
- }
-
- private void setInitialEntry() {
- SpinLockBasedFIFODataContainer ldc = (SpinLockBasedFIFODataContainer) dc;
- dc.put("k", "v", -1, -1);
-
- assert dc.size() == 1;
-
- SpinLockBasedFIFODataContainer.Aux last = ldc.dummyEntry.prev;
- SpinLockBasedFIFODataContainer.Aux next = ldc.dummyEntry.next;
- SpinLockBasedFIFODataContainer.LinkedEntry le = next.next;
- SpinLockBasedFIFODataContainer.Aux last2 = le.next;
-
- assert last == last2;
- assert last != next;
- assert le != ldc.dummyEntry;
- assert le.prev == next;
- assert le.next == last;
- assert le.entry != null;
- assert le.entry.getKey().equals("k");
- assert le.entry.getValue().equals("v");
- }
-
- public void testInsertingLinks() {
- SpinLockBasedFIFODataContainer ldc = (SpinLockBasedFIFODataContainer) dc;
- assert dc.size() == 0;
- assert ldc.dummyEntry.prev == ldc.dummyEntry.next;
- assert ldc.dummyEntry.entry == null;
-
- setInitialEntry();
-
- // add one more
- dc.put("k2", "v2", -1, -1);
-
- assert dc.size() == 2;
-
- SpinLockBasedFIFODataContainer.Aux last = ldc.dummyEntry.prev;
- SpinLockBasedFIFODataContainer.Aux next = ldc.dummyEntry.next;
- SpinLockBasedFIFODataContainer.LinkedEntry le1 = next.next;
- SpinLockBasedFIFODataContainer.Aux next2 = le1.next;
- SpinLockBasedFIFODataContainer.LinkedEntry le2 = next2.next;
- SpinLockBasedFIFODataContainer.Aux last2 = le2.next;
-
- assert last == last2;
- assert last != next;
- assert last != next2;
- assert next != next2;
- assert le1 != ldc.dummyEntry;
- assert le2 != ldc.dummyEntry;
- assert le1 != le2;
-
- assert le1.prev == next;
- assert le1.next == next2;
- assert le2.prev == next2;
- assert le2.next == last;
-
- assert le1.entry != null;
- assert le1.entry.getKey().equals("k");
- assert le1.entry.getValue().equals("v");
-
- assert le2.entry != null;
- assert le2.entry.getKey().equals("k2");
- assert le2.entry.getValue().equals("v2");
- }
-
- public void testRemovingLinks() {
- SpinLockBasedFIFODataContainer aldc = (SpinLockBasedFIFODataContainer) dc;
- assert dc.size() == 0;
- assert aldc.dummyEntry.prev == aldc.dummyEntry.next;
- assert aldc.dummyEntry.entry == null;
-
- setInitialEntry();
-
- dc.remove("k");
-
- assert dc.size() == 0;
- assert aldc.dummyEntry.prev == aldc.dummyEntry.next;
- assert aldc.dummyEntry.entry == null;
- }
-
- public void testClear() {
- SpinLockBasedFIFODataContainer aldc = (SpinLockBasedFIFODataContainer) dc;
- assert dc.size() == 0;
- assert aldc.dummyEntry.prev == aldc.dummyEntry.next;
- assert aldc.dummyEntry.entry == null;
-
- setInitialEntry();
-
- dc.clear();
-
- assert dc.size() == 0;
- assert aldc.dummyEntry.prev == aldc.dummyEntry.next;
- assert aldc.dummyEntry.entry == null;
- }
-
- public void testMultithreadAccess() throws InterruptedException {
- assert dc.size() == 0;
- int NUM_THREADS = 5;
- long testDuration = 2000; // millis
-
- Random r = new Random();
- CountDownLatch startLatch = new CountDownLatch(1);
-
- Worker[] workers = new Worker[NUM_THREADS];
- for (int i = 0; i < NUM_THREADS; i++) workers[i] = new Worker("Worker-" + i, r, startLatch);
- for (Worker w : workers) w.start();
-
- startLatch.countDown();
-
- Thread.sleep(testDuration); // generate some noise
-
- for (Worker w : workers) w.running = false;
- for (Worker w : workers) w.join();
-
- assertNoStaleSpinLocks((SpinLockBasedFIFODataContainer) dc);
- }
-
- protected void assertNoStaleSpinLocks(SpinLockBasedFIFODataContainer fdc) {
- SpinLockBasedFIFODataContainer.SpinLock first = fdc.dummyEntry;
- SpinLockBasedFIFODataContainer.SpinLock next = fdc.dummyEntry;
-
- do {
- assert !next.l.get() : "Should NOT be locked!";
- if (next instanceof SpinLockBasedFIFODataContainer.Aux)
- next = ((SpinLockBasedFIFODataContainer.Aux) next).next;
- else
- next = ((SpinLockBasedFIFODataContainer.LinkedEntry) next).next;
-
- } while (first != next);
- }
-
- protected final class Worker extends Thread {
- CountDownLatch startLatch;
- Random r;
- volatile boolean running = true;
-
- public Worker(String name, Random r, CountDownLatch startLatch) {
- super(name);
- this.r = r;
- this.startLatch = startLatch;
- }
-
- @Override
- public void run() {
- try {
- startLatch.await();
- } catch (InterruptedException ignored) {
- }
-
- while (running) {
- try {
- sleep(r.nextInt(5) * 10);
- } catch (InterruptedException ignored) {
- }
- switch (r.nextInt(3)) {
- case 0:
- dc.put("key" + r.nextInt(100), "value", -1, -1);
- break;
- case 1:
- dc.remove("key" + r.nextInt(100));
- break;
- case 2:
- dc.get("key" + r.nextInt(100));
- break;
- }
- }
- }
- }
-}
Deleted: trunk/core/src/test/java/org/infinispan/container/SpinLockBasedLRUDataContainerTest.java
===================================================================
--- trunk/core/src/test/java/org/infinispan/container/SpinLockBasedLRUDataContainerTest.java 2009-09-29 10:37:36 UTC (rev 880)
+++ trunk/core/src/test/java/org/infinispan/container/SpinLockBasedLRUDataContainerTest.java 2009-09-29 10:53:05 UTC (rev 881)
@@ -1,80 +0,0 @@
-package org.infinispan.container;
-
-import org.infinispan.container.entries.ImmortalCacheEntry;
-import org.infinispan.container.entries.InternalCacheEntry;
-import org.infinispan.container.entries.MortalCacheEntry;
-import org.infinispan.container.entries.TransientCacheEntry;
-import org.infinispan.container.entries.TransientMortalCacheEntry;
-import org.testng.annotations.Test;
-
- at Test(groups = "unit", testName = "container.SpinLockBasedLRUDataContainerTest")
-public class SpinLockBasedLRUDataContainerTest extends SpinLockBasedFIFODataContainerTest {
- @Override
- protected DataContainer createContainer() {
- return new SpinLockBasedLRUDataContainer();
- }
-
- @Override
- public void testOrdering() {
- long lifespan = 600000;
- long idle = 600000;
- for (int i = 0; i < 10; i++) dc.put(i, "value", -1, -1);
- for (int i = 10; i < 20; i++) dc.put(i, "value", lifespan, -1);
- for (int i = 20; i < 30; i++) dc.put(i, "value", -1, idle);
- for (int i = 30; i < 40; i++) dc.put(i, "value", lifespan, idle);
-
- // Visit all ODD numbered elements
- for (int i = 0; i < 40; i++) {
- if (i % 2 == 1) dc.get(i);
- }
-
- // ensure order is maintained. The first 20 elements should be EVEN.
- int i = 0;
- for (InternalCacheEntry ice : dc) {
- Integer key = (Integer) ice.getKey();
- if (i < 20)
- assert key % 2 == 0;
- else
- assert key % 2 == 1;
-
- if (key < 10) assert ice instanceof ImmortalCacheEntry;
- if (key >= 10 && key < 20) assert ice instanceof MortalCacheEntry;
- if (key >= 20 && key < 30) assert ice instanceof TransientCacheEntry;
- if (key >= 30 && key < 40) assert ice instanceof TransientMortalCacheEntry;
- i++;
- }
- }
-
- public void testOrderingUpdateExisting() {
- for (int i = 0; i < 10; i++) dc.put(i, "value", -1, -1);
-
- // update 1st key
- dc.put(0, "new-value", -1, -1);
- int i = 0;
- for (InternalCacheEntry ice : dc) {
- Integer key = (Integer) ice.getKey();
- assert key.equals((i + 1) % 10) : "Not equals, key=" + key + " and index=" + (i + 1) % 10;
- i++;
- }
-
-
- // update key in the middle
- dc.put(5, "new-value", -1, -1);
- Integer[] expected = new Integer[]{1, 2, 3, 4, 6, 7, 8, 9, 0, 5};
- i = 0;
- for (InternalCacheEntry ice : dc) {
- Integer key = (Integer) ice.getKey();
- assert key.equals(expected[i]) : "Not equals, key=" + key + " and expected=" + expected[i];
- i++;
- }
-
- // update last key
- dc.put(5, "yet-another-new-value", -1, -1);
- i = 0;
- for (InternalCacheEntry ice : dc) {
- Integer key = (Integer) ice.getKey();
- assert key.equals(expected[i]) : "Not equals, key=" + key + " and expected=" + expected[i];
- i++;
- }
- }
-}
More information about the infinispan-commits
mailing list