This is an automated email from the ASF dual-hosted git repository. asf-gitbox-commits pushed a commit to branch master in repository https://gitbox.apache.org/repos/asf/commons-jcs.git
commit 02a06385a9484dde2ab96a21173777f8e1ffaea3 Author: Thomas Vandahl <[email protected]> AuthorDate: Wed Sep 16 18:11:02 2026 +0200 Move sharding to DoubleLinkedList --- .../AbstractDoubleLinkedListMemoryCache.java | 171 ++++-------- .../jcs4/utils/struct/DoubleLinkedList.java | 293 +++++++++++++-------- .../jcs4/utils/struct/DoubleLinkedListNode.java | 25 +- .../utils/struct/DoubleLinkedListDumpUnitTest.java | 4 +- .../utils/struct/DoubleLinkedListUnitTest.java | 14 +- 5 files changed, 279 insertions(+), 228 deletions(-) diff --git a/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/memory/AbstractDoubleLinkedListMemoryCache.java b/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/memory/AbstractDoubleLinkedListMemoryCache.java index 1ee65576..e0589973 100644 --- a/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/memory/AbstractDoubleLinkedListMemoryCache.java +++ b/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/engine/memory/AbstractDoubleLinkedListMemoryCache.java @@ -20,11 +20,9 @@ package org.apache.commons.jcs4.engine.memory; */ import java.io.IOException; -import java.util.Arrays; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; -import java.util.concurrent.atomic.AtomicInteger; import org.apache.commons.jcs4.engine.behavior.ICacheElement; import org.apache.commons.jcs4.engine.control.CompositeCache; @@ -53,41 +51,7 @@ public abstract class AbstractDoubleLinkedListMemoryCache<K, V> extends Abstract } /** Thread-safe double linked list for lru */ - private DoubleLinkedList<MemoryElementDescriptor<K, V>>[] lists; - - /** Number of shards */ - private int shards; - - private static class AtomicCyclicCounter - { - private final int max; - private final AtomicInteger counter; - - private AtomicCyclicCounter(int max) - { - this.max = max; - counter = new AtomicInteger(); - } - - private int incrementAndGet() - { - return counter.accumulateAndGet(1, (index, inc) -> (++index >= max ? 0 : index)); - } - } - - /** shard to spool */ - private AtomicCyclicCounter spoolShard; - - /** - * Returns the current cache shard for the given key - * - * @param key the cache key - * @return The shard - */ - protected int spreadShard(K key) - { - return Math.abs(key.hashCode() % shards); - } + private DoubleLinkedList<MemoryElementDescriptor<K, V>> list; /** * Adds a new node to the start of the link list. @@ -97,8 +61,7 @@ public abstract class AbstractDoubleLinkedListMemoryCache<K, V> extends Abstract */ protected void addFirst(final MemoryElementDescriptor<K, V> me) { - int shard = spreadShard(me.getCacheElement().key()); - lists[shard].addFirst(me); + list.addFirst(me); if ( log.isTraceEnabled() ) { verifyCache(me.getCacheElement().key()); @@ -113,8 +76,7 @@ public abstract class AbstractDoubleLinkedListMemoryCache<K, V> extends Abstract */ protected void addLast(final MemoryElementDescriptor<K,V> me) { - int shard = spreadShard(me.getCacheElement().key()); - lists[shard].addLast(me); + list.addLast(me); if ( log.isTraceEnabled() ) { verifyCache(me.getCacheElement().key()); @@ -153,11 +115,7 @@ public abstract class AbstractDoubleLinkedListMemoryCache<K, V> extends Abstract public IStats getStatistics() { final IStats stats = super.getStatistics(); - stats.addStatElement("Shards", Integer.valueOf(shards)); - for (int i = 0; i < shards; i++) - { - stats.addStatElement("List Size " + i, Integer.valueOf(lists[i].size())); - } + stats.addStatElement("Shards", Integer.valueOf(list.getShards())); return stats; } @@ -167,18 +125,12 @@ public abstract class AbstractDoubleLinkedListMemoryCache<K, V> extends Abstract * * @param hub */ - @SuppressWarnings("unchecked") @Override public void initialize(final CompositeCache<K, V> hub) { super.initialize(hub); - this.shards = getCacheAttributes().Shards(); - lists = new DoubleLinkedList[shards]; - for (int i = 0; i < shards; i++) - { - lists[i] = new DoubleLinkedList<>(); - } - this.spoolShard = new AtomicCyclicCounter(shards); + int shards = getCacheAttributes().Shards(); + list = new DoubleLinkedList<>(shards); log.info("initialized MemoryCache for {0}", this::getCacheName); } @@ -191,7 +143,10 @@ public abstract class AbstractDoubleLinkedListMemoryCache<K, V> extends Abstract @Override protected MemoryElementDescriptor<K, V> wrap(ICacheElement<K, V> ce) { - return new MemoryElementDescriptor<>(ce); + MemoryElementDescriptor<K, V> me = new MemoryElementDescriptor<>(ce); + me.setShard(list.spreadShard(ce.key())); + + return me; } /** @@ -202,8 +157,7 @@ public abstract class AbstractDoubleLinkedListMemoryCache<K, V> extends Abstract @Override protected void adjustGetElement(final MemoryElementDescriptor<K, V> me) { - int shard = spreadShard(me.getCacheElement().key()); - adjustListForGet(lists[shard], me); + adjustListForGet(list, me); } /** @@ -215,8 +169,7 @@ public abstract class AbstractDoubleLinkedListMemoryCache<K, V> extends Abstract @Override protected void adjustUpdateElement(MemoryElementDescriptor<K, V> newNode) throws IOException { - int shard = spreadShard(newNode.getCacheElement().key()); - lists[shard].makeFirst(newNode); + list.makeFirst(newNode); } /** @@ -225,7 +178,7 @@ public abstract class AbstractDoubleLinkedListMemoryCache<K, V> extends Abstract @Override protected void adjustRemoveAll() { - Arrays.stream(lists).forEach(DoubleLinkedList::removeAll); + list.removeAll(); } /** @@ -236,8 +189,7 @@ public abstract class AbstractDoubleLinkedListMemoryCache<K, V> extends Abstract @Override protected void adjustRemoveElement(final MemoryElementDescriptor<K, V> me) { - int shard = spreadShard(me.getCacheElement().key()); - lists[shard].remove(me); + list.remove(me); } /** @@ -307,8 +259,7 @@ public abstract class AbstractDoubleLinkedListMemoryCache<K, V> extends Abstract { ICacheElement<K, V> toSpool = null; - int shard = this.spoolShard.incrementAndGet(); - final MemoryElementDescriptor<K, V> last = lists[shard].getLast(); + final MemoryElementDescriptor<K, V> last = list.getLast(); if (last != null) { toSpool = last.getCacheElement(); @@ -337,13 +288,10 @@ public abstract class AbstractDoubleLinkedListMemoryCache<K, V> extends Abstract private void dumpCacheEntries() { log.trace("dumpingCacheEntries"); - for (int i = 0; i < shards; i++) + for (MemoryElementDescriptor<K, V> me : list) { - for (MemoryElementDescriptor<K, V> me : lists[i]) - { - log.trace("dumpCacheEntries> shard={0}, key={1}, val={2}", i, - me.getCacheElement().key(), me.getCacheElement().value()); - } + log.trace("dumpCacheEntries> key={0}, val={1}", + me.getCacheElement().key(), me.getCacheElement().value()); } } @@ -356,48 +304,42 @@ public abstract class AbstractDoubleLinkedListMemoryCache<K, V> extends Abstract boolean found = false; Map<K, MemoryElementDescriptor<K, V>> mapView = getMapView(); log.trace("verifycache[{0}]: map contains {1} elements, linked list " - + "contains {2} elements", getCacheName(), getSize(), - Arrays.stream(lists) - .mapToInt(DoubleLinkedList::size) - .sum()); + + "contains {2} elements", getCacheName(), getSize(), list.size()); log.trace("verifycache: checking linked list by key "); - for (int i = 0; i < shards; i++) + for (MemoryElementDescriptor<K, V> li : list) { - for (MemoryElementDescriptor<K, V> li : lists[i]) + final K key = li.getCacheElement().key(); + if (!mapView.containsKey(key)) { - final K key = li.getCacheElement().key(); - if (!mapView.containsKey(key)) + log.error("verifycache[{0}]: map does not contain key : {1}", + getCacheName(), key); + log.error("key class={0}", key.getClass()); + log.error("key hashCode={0}", key.hashCode()); + log.error("key toString={0}", key.toString()); + if (key instanceof GroupAttrName name) { - log.error("verifycache[{0}]: map does not contain key : {1}", - getCacheName(), key); - log.error("key class={0}", key.getClass()); - log.error("key hashCode={0}", key.hashCode()); - log.error("key toString={0}", key.toString()); - if (key instanceof GroupAttrName name) - { - log.error("GroupID hashCode={0}", name.groupId().hashCode()); - log.error("GroupID.class={0}", name.groupId().getClass()); - log.error("AttrName hashCode={0}", name.attrName().hashCode()); - log.error("AttrName.class={0}", name.attrName().getClass()); - } - dumpMap(); - } - else if (mapView.get(key) == null) - { - log.error("verifycache[{0}]: linked list retrieval returned " - + "null for key: {1}", getCacheName(), key); + log.error("GroupID hashCode={0}", name.groupId().hashCode()); + log.error("GroupID.class={0}", name.groupId().getClass()); + log.error("AttrName hashCode={0}", name.attrName().hashCode()); + log.error("AttrName.class={0}", name.attrName().getClass()); } + dumpMap(); + } + else if (mapView.get(key) == null) + { + log.error("verifycache[{0}]: linked list retrieval returned " + + "null for key: {1}", getCacheName(), key); } + } - log.trace("verifycache: checking linked list by value "); - for (MemoryElementDescriptor<K, V> li : lists[i]) + log.trace("verifycache: checking linked list by value "); + for (MemoryElementDescriptor<K, V> li : list) + { + if (!mapView.containsValue(li)) { - if (!mapView.containsValue(li)) - { - log.error("verifycache[{0}]: map does not contain value: {1}", - getCacheName(), li); - dumpMap(); - } + log.error("verifycache[{0}]: map does not contain value: {1}", + getCacheName(), li); + dumpMap(); } } @@ -406,17 +348,15 @@ public abstract class AbstractDoubleLinkedListMemoryCache<K, V> extends Abstract { found = false; - for (int i = 0; i < shards; i++) + for (MemoryElementDescriptor<K, V> li : list) { - for (MemoryElementDescriptor<K, V> li : lists[i]) + if (val.equals(li.getCacheElement().key())) { - if (val.equals(li.getCacheElement().key())) - { - found = true; - break; - } + found = true; + break; } } + if (!found) { log.error("verifycache[{0}]: key not found in list : {1}", @@ -445,20 +385,19 @@ public abstract class AbstractDoubleLinkedListMemoryCache<K, V> extends Abstract boolean found = false; // go through the linked list looking for the key - int shard = spreadShard(key); - for (MemoryElementDescriptor<K, V> li : lists[shard]) + for (MemoryElementDescriptor<K, V> li : list) { if (li.getCacheElement().key() == key) { found = true; - log.trace("verifycache(key) shard: {0}, key match: {1}", shard, key); + log.trace("verifycache(key) key match: {0}", key); break; } } if (!found) { - log.error("verifycache(key)[{0}], shard {1}, couldn't find key! : {2}", - getCacheName(), shard, key); + log.error("verifycache(key)[{0}], couldn't find key! : {1}", + getCacheName(), key); } } } diff --git a/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/utils/struct/DoubleLinkedList.java b/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/utils/struct/DoubleLinkedList.java index 950a524d..87e2c264 100644 --- a/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/utils/struct/DoubleLinkedList.java +++ b/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/utils/struct/DoubleLinkedList.java @@ -1,6 +1,7 @@ package org.apache.commons.jcs4.utils.struct; import java.util.Iterator; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; @@ -26,33 +27,12 @@ import java.util.concurrent.locks.ReentrantLock; import org.apache.commons.jcs4.log.Log; /** - * This is a generic double linked list. Thread safety is NOT provided by this class. - * <p> - * <b>THREAD SAFETY REQUIREMENT:</b> This class must be guarded by external synchronization - * in calling code. All operations assume the caller holds appropriate locks - * (e.g., ReentrantLock in {@link org.apache.commons.jcs4.engine.memory.AbstractDoubleLinkedListMemoryCache}). - * <p> - * This design eliminates double-locking problems when used with external locks and provides - * O(1) performance for node repositioning operations. - * <p> - * <b>Example Usage:</b> - * <pre> - * Lock lock = new java.util.concurrent.locks.ReentrantLock(); - * DoubleLinkedList<MyNode> list = new DoubleLinkedList<>(); - * - * // Caller must acquire lock before accessing - * lock.lock(); - * try { - * list.addFirst(node); // SAFE because lock is held - * } finally { - * lock.unlock(); - * } - * </pre> + * This is a generic thread-safe double linked list. It uses internal locking and sharding to achieve + * high throughput and little lock contention * * @see java.util.concurrent.locks.ReentrantLock * @see org.apache.commons.jcs4.engine.memory.AbstractDoubleLinkedListMemoryCache */ -@SuppressWarnings({"unchecked"}) // Don't know how to resolve this with generics public class DoubleLinkedList<T extends DoubleLinkedListNode> implements Iterable<T> { @@ -62,25 +42,83 @@ public class DoubleLinkedList<T extends DoubleLinkedListNode> /** Record size to avoid having to iterate */ private int size; - /** The lock */ - private final Lock lock; + /** Number of shards */ + private final int shards; + + /** The locks */ + private final Lock[] lock; /** LRU double linked list head node */ - private T first; + private DoubleLinkedListNode[] first; /** LRU double linked list tail node */ - private T last; + private DoubleLinkedListNode[] last; + + private static class AtomicCyclicCounter + { + private final int max; + private final AtomicInteger counter; + + private AtomicCyclicCounter(int max) + { + this.max = max; + counter = new AtomicInteger(); + } + + private int incrementAndGet() + { + return counter.accumulateAndGet(1, (index, inc) -> (++index >= max ? 0 : index)); + } + } + + /** shard to spool */ + private final AtomicCyclicCounter spoolShard; /** * Construct DoubleLinkedList + * + * @param shards Number of shards */ - public DoubleLinkedList() + public DoubleLinkedList(int shards) { - this.first = (T) new DoubleLinkedListNode(); - this.last = (T) new DoubleLinkedListNode(); - this.first.next = this.last; - this.last.prev = this.first; - this.lock = new ReentrantLock(); + this.shards = shards; + this.lock = new Lock[shards]; + this.first = new DoubleLinkedListNode[shards]; + this.last = new DoubleLinkedListNode[shards]; + this.spoolShard = new AtomicCyclicCounter(shards); + + for (int i = 0; i < shards; i++) + { + first[i] = new DoubleLinkedListNode(); + first[i].setShard(i); + last[i] = new DoubleLinkedListNode(); + last[i].setShard(i); + first[i].next = this.last[i]; + last[i].prev = this.first[i]; + lock[i] = new ReentrantLock(); + } + } + + /** + * Returns the number of shards + * + * @return the shards + */ + public int getShards() + { + return shards; + } + + + /** + * Returns the current cache shard for the given key + * + * @param key the cache key + * @return The shard + */ + public int spreadShard(Object key) + { + return Math.abs(key.hashCode() % shards); } /** @@ -90,18 +128,19 @@ public class DoubleLinkedList<T extends DoubleLinkedListNode> */ public void addFirst(final T me) { - lock.lock(); + int shard = me.getShard(); + lock[shard].lock(); try { - me.prev = first; - me.next = first.next; - first.next.prev = me; - first.next = me; + me.prev = first[shard]; + me.next = first[shard].next; + first[shard].next.prev = me; + first[shard].next = me; size++; } finally { - lock.unlock(); + lock[shard].unlock(); } } @@ -112,18 +151,19 @@ public class DoubleLinkedList<T extends DoubleLinkedListNode> */ public void addLast(final T me) { - lock.lock(); + int shard = me.getShard(); + lock[shard].lock(); try { - me.next = last; - me.prev = last.prev; - last.prev.next = me; - last.prev = me; + me.next = last[shard]; + me.prev = last[shard].prev; + last[shard].prev.next = me; + last[shard].prev = me; size++; } finally { - lock.unlock(); + lock[shard].unlock(); } } @@ -144,27 +184,47 @@ public class DoubleLinkedList<T extends DoubleLinkedListNode> } /** - * Removes the specified node from the link list. + * Returns the first node from the link list. * - * @return DoubleLinkedListNode, the first node. + * @return the first node, null if the list is empty. */ + @SuppressWarnings({"unchecked"}) // Don't know how to resolve this with generics public T getFirst() { log.debug("returning first node"); - DoubleLinkedListNode f = first.next; - return (T) (f == last ? null : f); + int shard = this.spoolShard.incrementAndGet(); + lock[shard].lock(); + try + { + DoubleLinkedListNode f = first[shard].next; + return (T) (f == last[shard] ? null : f); + } + finally + { + lock[shard].unlock(); + } } /** * Returns the last node from the link list, if there are any nodes. * - * @return The last node. + * @return The last node, null if the list is empty. */ + @SuppressWarnings({"unchecked"}) // Don't know how to resolve this with generics public T getLast() { log.debug("returning last node"); - DoubleLinkedListNode l = last.prev; - return (T) (l == first ? null : l); + int shard = this.spoolShard.incrementAndGet(); + lock[shard].lock(); + try + { + DoubleLinkedListNode l = last[shard].prev; + return (T) (l == first[shard] ? null : l); + } + finally + { + lock[shard].unlock(); + } } /** @@ -174,7 +234,8 @@ public class DoubleLinkedList<T extends DoubleLinkedListNode> */ public void makeFirst(final T ln) { - lock.lock(); + int shard = ln.getShard(); + lock[shard].lock(); try { if (ln.prev != null && ln.next != null) @@ -183,15 +244,15 @@ public class DoubleLinkedList<T extends DoubleLinkedListNode> ln.next.prev = ln.prev; size--; } - ln.prev = first; - ln.next = first.next; - first.next.prev = ln; - first.next = ln; + ln.prev = first[shard]; + ln.next = first[shard].next; + first[shard].next.prev = ln; + first[shard].next = ln; size++; } finally { - lock.unlock(); + lock[shard].unlock(); } } @@ -202,7 +263,8 @@ public class DoubleLinkedList<T extends DoubleLinkedListNode> */ public void makeLast(final T ln) { - lock.lock(); + int shard = ln.getShard(); + lock[shard].lock(); try { if (ln.prev != null && ln.next != null) @@ -211,15 +273,15 @@ public class DoubleLinkedList<T extends DoubleLinkedListNode> ln.next.prev = ln.prev; size--; } - ln.next = last; - ln.prev = last.prev; - last.prev.next = ln; - last.prev = ln; + ln.next = last[shard]; + ln.prev = last[shard].prev; + last[shard].prev.next = ln; + last[shard].prev = ln; size++; } finally { - lock.unlock(); + lock[shard].unlock(); } } @@ -232,7 +294,8 @@ public class DoubleLinkedList<T extends DoubleLinkedListNode> public boolean remove(final T me) { log.debug("removing node"); - lock.lock(); + int shard = me.getShard(); + lock[shard].lock(); try { if (me.prev != null && me.next != null) @@ -245,7 +308,7 @@ public class DoubleLinkedList<T extends DoubleLinkedListNode> } finally { - lock.unlock(); + lock[shard].unlock(); } return true; @@ -256,25 +319,28 @@ public class DoubleLinkedList<T extends DoubleLinkedListNode> */ public void removeAll() { - DoubleLinkedListNode me = getFirst(); - lock.lock(); - try + for (int i = 0; i < shards; i++) { - while (me != null && me.next != null) + lock[i].lock(); + try { - DoubleLinkedListNode toRemove = me; - me = me.next; - toRemove.prev = null; - toRemove.next = null; + DoubleLinkedListNode me = first[i].next; + while (me != last[i] && me.next != null) + { + DoubleLinkedListNode toRemove = me; + me = me.next; + toRemove.prev = null; + toRemove.next = null; + } + first[i].next = last[i]; + last[i].prev = first[i]; + } + finally + { + lock[i].unlock(); } - first.next = last; - last.prev = first; - size = 0; - } - finally - { - lock.unlock(); } + size = 0; } /** @@ -285,22 +351,13 @@ public class DoubleLinkedList<T extends DoubleLinkedListNode> public T removeLast() { log.debug("removing last node"); - lock.lock(); - try - { - final T temp = (T) last.prev; - if (temp != first) - { - remove(temp); - return temp; - } - } - finally + T me = getLast(); + if (me != null) { - lock.unlock(); + remove(me); } - return null; + return me; } /** @@ -314,42 +371,72 @@ public class DoubleLinkedList<T extends DoubleLinkedListNode> } /** - * Return an iterator over this list + * Return an iterator over this list of lists * * @return the iterator */ @Override + @SuppressWarnings({"unchecked"}) // Don't know how to resolve this with generics public Iterator<T> iterator() { return new Iterator<>() { - private T runner = first; + private int shard = 0; + private T runner = (T) first[shard]; @Override - public boolean hasNext() + public synchronized boolean hasNext() { - lock.lock(); + if (shard >= shards) + { + return false; + } + + boolean rollover = false; + + lock[shard].lock(); try { - return runner.next != null && runner.next != last; + if (runner.next == null) + { + return false; + } + rollover = runner.next == last[shard]; + if (!rollover) + { + return true; + } } finally { - lock.unlock(); + lock[shard].unlock(); + } + + if (rollover) + { + shard++; + if (shard < shards) + { + runner = (T) first[shard]; + } + + return hasNext(); } + + return false; } @Override - public T next() + public synchronized T next() { - lock.lock(); + lock[shard].lock(); try { runner = (T) runner.next; } finally { - lock.unlock(); + lock[shard].unlock(); } return runner; } diff --git a/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/utils/struct/DoubleLinkedListNode.java b/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/utils/struct/DoubleLinkedListNode.java index 55612a72..f1f0d1b9 100644 --- a/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/utils/struct/DoubleLinkedListNode.java +++ b/commons-jcs4-core/src/main/java/org/apache/commons/jcs4/utils/struct/DoubleLinkedListNode.java @@ -35,6 +35,29 @@ public class DoubleLinkedListNode /** Don't change. */ private static final long serialVersionUID = -1114934407695836097L; + /** Number of the shard I belong to */ + private volatile int shard = 0; + /** Double Linked list references */ - public volatile DoubleLinkedListNode prev, next; + protected volatile DoubleLinkedListNode prev, next; + + /** + * Returns the shard of this node + * + * @return the shard + */ + public int getShard() + { + return shard; + } + + /** + * Sets the shard of this node + * + * @param shard the shard to set + */ + public void setShard(int shard) + { + this.shard = shard; + } } diff --git a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/utils/struct/DoubleLinkedListDumpUnitTest.java b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/utils/struct/DoubleLinkedListDumpUnitTest.java index d3f279e2..ee2e310e 100644 --- a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/utils/struct/DoubleLinkedListDumpUnitTest.java +++ b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/utils/struct/DoubleLinkedListDumpUnitTest.java @@ -37,10 +37,12 @@ class DoubleLinkedListDumpUnitTest final StringWriter stringWriter = new StringWriter(); TestLogConfigurationUtil.configureLogger( stringWriter, DoubleLinkedList.class.getName() ); - final DoubleLinkedList<DoubleLinkedListNode> list = new DoubleLinkedList<>(); + final DoubleLinkedList<DoubleLinkedListNode> list = new DoubleLinkedList<>(2); final DoubleLinkedListNode node1 = new DoubleLinkedListNode(); + node1.setShard(0); final DoubleLinkedListNode node2 = new DoubleLinkedListNode(); + node2.setShard(1); list.addLast( node1 ); list.addLast( node2 ); diff --git a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/utils/struct/DoubleLinkedListUnitTest.java b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/utils/struct/DoubleLinkedListUnitTest.java index dd1be24a..69ad5927 100644 --- a/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/utils/struct/DoubleLinkedListUnitTest.java +++ b/commons-jcs4-core/src/test/java/org/apache/commons/jcs4/utils/struct/DoubleLinkedListUnitTest.java @@ -32,7 +32,7 @@ class DoubleLinkedListUnitTest void testAddLast_Empty() { // SETUP - final DoubleLinkedList<DoubleLinkedListNode> list = new DoubleLinkedList<>(); + final DoubleLinkedList<DoubleLinkedListNode> list = new DoubleLinkedList<>(1); final DoubleLinkedListNode node1 = new DoubleLinkedListNode(); @@ -48,7 +48,7 @@ class DoubleLinkedListUnitTest void testAddLast_NotEmpty() { // SETUP - final DoubleLinkedList<DoubleLinkedListNode> list = new DoubleLinkedList<>(); + final DoubleLinkedList<DoubleLinkedListNode> list = new DoubleLinkedList<>(1); final DoubleLinkedListNode node1 = new DoubleLinkedListNode(); final DoubleLinkedListNode node2 = new DoubleLinkedListNode(); @@ -66,7 +66,7 @@ class DoubleLinkedListUnitTest void testMakeLast_wasAlone() { // SETUP - final DoubleLinkedList<DoubleLinkedListNode> list = new DoubleLinkedList<>(); + final DoubleLinkedList<DoubleLinkedListNode> list = new DoubleLinkedList<>(1); final DoubleLinkedListNode node1 = new DoubleLinkedListNode(); @@ -86,7 +86,7 @@ class DoubleLinkedListUnitTest void testMakeLast_wasFirst() { // SETUP - final DoubleLinkedList<DoubleLinkedListNode> list = new DoubleLinkedList<>(); + final DoubleLinkedList<DoubleLinkedListNode> list = new DoubleLinkedList<>(1); final DoubleLinkedListNode node1 = new DoubleLinkedListNode(); final DoubleLinkedListNode node2 = new DoubleLinkedListNode(); @@ -108,7 +108,7 @@ class DoubleLinkedListUnitTest void testMakeLast_wasInMiddle() { // SETUP - final DoubleLinkedList<DoubleLinkedListNode> list = new DoubleLinkedList<>(); + final DoubleLinkedList<DoubleLinkedListNode> list = new DoubleLinkedList<>(1); final DoubleLinkedListNode node1 = new DoubleLinkedListNode(); final DoubleLinkedListNode node2 = new DoubleLinkedListNode(); @@ -132,7 +132,7 @@ class DoubleLinkedListUnitTest void testMakeLast_wasLast() { // SETUP - final DoubleLinkedList<DoubleLinkedListNode> list = new DoubleLinkedList<>(); + final DoubleLinkedList<DoubleLinkedListNode> list = new DoubleLinkedList<>(1); final DoubleLinkedListNode node1 = new DoubleLinkedListNode(); final DoubleLinkedListNode node2 = new DoubleLinkedListNode(); @@ -154,7 +154,7 @@ class DoubleLinkedListUnitTest void testRemove() { // SETUP - final DoubleLinkedList<DoubleLinkedListNode> list = new DoubleLinkedList<>(); + final DoubleLinkedList<DoubleLinkedListNode> list = new DoubleLinkedList<>(1); final DoubleLinkedListNode node1 = new DoubleLinkedListNode(); final DoubleLinkedListNode node2 = new DoubleLinkedListNode();
