Skip to main content
summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBrian Vosburgh2016-02-09 14:57:14 +0000
committerBrian Vosburgh2017-05-18 22:36:37 +0000
commit2d621b758345525c3e4a55aa951b48d82908675d (patch)
treea9eb33807bb546e995b91e5f505f0ea8bacbacde /common/tests
parent2b03c9849ab29da6af817f2b2c8be9859e26c3a0 (diff)
downloadwebtools.dali-2d621b758345525c3e4a55aa951b48d82908675d.tar.gz
webtools.dali-2d621b758345525c3e4a55aa951b48d82908675d.tar.xz
webtools.dali-2d621b758345525c3e4a55aa951b48d82908675d.zip
test and fix(!) CachingConcurrentStack
Diffstat (limited to 'common/tests')
-rw-r--r--common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/CachingConcurrentStackTests.java162
1 files changed, 160 insertions, 2 deletions
diff --git a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/CachingConcurrentStackTests.java b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/CachingConcurrentStackTests.java
index eb05335c2c..3e68f24b94 100644
--- a/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/CachingConcurrentStackTests.java
+++ b/common/tests/org.eclipse.jpt.common.utility.tests/src/org/eclipse/jpt/common/utility/tests/internal/stack/CachingConcurrentStackTests.java
@@ -9,7 +9,13 @@
******************************************************************************/
package org.eclipse.jpt.common.utility.tests.internal.stack;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Vector;
+import org.eclipse.jpt.common.utility.internal.ArrayTools;
import org.eclipse.jpt.common.utility.internal.ObjectTools;
+import org.eclipse.jpt.common.utility.internal.reference.SynchronizedBoolean;
+import org.eclipse.jpt.common.utility.internal.stack.CachingConcurrentStack;
import org.eclipse.jpt.common.utility.internal.stack.StackTools;
import org.eclipse.jpt.common.utility.stack.Stack;
@@ -26,6 +32,156 @@ public class CachingConcurrentStackTests
return StackTools.cachingConcurrentStack();
}
+ public void testConcurrentAccess() throws InterruptedException {
+ CachingConcurrentStack<Integer> stack = StackTools.cachingConcurrentStack();
+
+ int threadCount = 10;
+ int elementsPerThread = 100000;
+ SynchronizedBoolean startFlag = new SynchronizedBoolean(false);
+
+ PushRunnable[] pushRunnables = new PushRunnable[threadCount];
+ Thread[] pushThreads = new Thread[threadCount];
+ for (int i = 0; i < threadCount; i++) {
+ PushRunnable pushRunnable = new PushRunnable(stack, (i * elementsPerThread), elementsPerThread, startFlag);
+ pushRunnables[i] = pushRunnable;
+ Thread pushThread = new Thread(pushRunnable);
+ pushThreads[i] = pushThread;
+ pushThread.start();
+ }
+
+ PopRunnable[] popRunnables = new PopRunnable[threadCount];
+ Thread[] popThreads = new Thread[threadCount];
+ for (int i = 0; i < threadCount; i++) {
+ PopRunnable popRunnable = new PopRunnable(stack, elementsPerThread, startFlag);
+ popRunnables[i] = popRunnable;
+ Thread popThread = new Thread(popRunnable);
+ popThreads[i] = popThread;
+ popThread.start();
+ }
+
+ startFlag.setTrue();
+ for (int i = 0; i < threadCount; i++) {
+ pushThreads[i].join();
+ assertTrue(pushRunnables[i].exceptions.isEmpty());
+ }
+ for (int i = 0; i < threadCount; i++) {
+ popThreads[i].join();
+ assertTrue(popRunnables[i].exceptions.isEmpty());
+ }
+
+ // if we get here, we have, at the least, popd as many elements as we pushd...
+ // ...now verify that all the popd elements are unique
+ // (i.e. none were lost or duplicated)
+ int totalCount = threadCount * elementsPerThread;
+ int uberMax = totalCount + 1;
+ int uberMaxThreadIndex = threadCount + 1;
+ int[] indexes = ArrayTools.fill(new int[threadCount], 0);
+ for (int i = 0; i < totalCount; i++) {
+ int min = uberMax;
+ int minThreadIndex = uberMaxThreadIndex;
+ for (int j = 0; j < threadCount; j++) {
+ int currentIndex = indexes[j];
+ if (currentIndex < elementsPerThread) {
+ int current = popRunnables[j].elements[currentIndex].intValue();
+ if (current < min) {
+ min = current;
+ minThreadIndex = j;
+ }
+ }
+ }
+ assertEquals(i, min);
+ indexes[minThreadIndex]++;
+ }
+ }
+
+ public static class PushRunnable
+ implements Runnable
+ {
+ private final Stack<Integer> stack;
+ private final int start;
+ private final int stop;
+ private final SynchronizedBoolean startFlag;
+ final List<InterruptedException> exceptions = new Vector<>();
+
+ public PushRunnable(Stack<Integer> stack, int start, int count, SynchronizedBoolean startFlag) {
+ super();
+ this.stack = stack;
+ this.start = start;
+ this.stop = start + count;
+ this.startFlag = startFlag;
+ }
+
+ public void run() {
+ try {
+ this.run_();
+ } catch (InterruptedException ex) {
+ this.exceptions.add(ex);
+ }
+ }
+
+ private void run_() throws InterruptedException {
+ this.startFlag.waitUntilTrue();
+ for (int i = this.start; i < this.stop; i++) {
+ this.stack.push(Integer.valueOf(i));
+ if ((i % 20) == 0) {
+ Thread.sleep(0);
+ }
+ }
+ }
+ }
+
+ public static class PopRunnable
+ implements Runnable
+ {
+ private final Stack<Integer> stack;
+ private final int count;
+ final Integer[] elements;
+ private int elementsCount;
+ private final SynchronizedBoolean startFlag;
+ final List<InterruptedException> exceptions = new Vector<>();
+
+ public PopRunnable(Stack<Integer> stack, int count, SynchronizedBoolean startFlag) {
+ super();
+ this.stack = stack;
+ this.count = count;
+ this.elements = new Integer[count];
+ this.elementsCount = 0;
+ this.startFlag = startFlag;
+ }
+
+ public void run() {
+ try {
+ this.run_();
+ } catch (InterruptedException ex) {
+ this.exceptions.add(ex);
+ }
+ }
+
+ private void run_() throws InterruptedException {
+ this.startFlag.waitUntilTrue();
+ int i = 0;
+ while (true) {
+ Integer element = this.stack.peek(); // fiddle with peek also
+ element = this.stack.pop();
+ if (element != null) {
+ this.elements[this.elementsCount++] = element;
+ if (this.elementsCount == this.count) {
+ break;
+ }
+ }
+ if ((i % 20) == 0) {
+ Thread.sleep(0);
+ }
+ if (i == Integer.MAX_VALUE) {
+ i = 0;
+ } else {
+ i++;
+ }
+ }
+ Arrays.sort(this.elements);
+ }
+ }
+
public void testCache() {
Stack<String> stack = this.buildStack();
String first = "first";
@@ -43,7 +199,8 @@ public class CachingConcurrentStackTests
stack.push(fifth);
this.verifyNodeCache(0, stack);
Object headRef = ObjectTools.get(stack, "cacheHeadRef");
- assertNull(ObjectTools.get(headRef, "value"));
+ Object pair = ObjectTools.get(headRef, "pair");
+ assertNull(ObjectTools.get(pair, "reference"));
stack.pop();
this.verifyNodeCache(1, stack);
@@ -70,7 +227,8 @@ public class CachingConcurrentStackTests
public void verifyNodeCache(int size, Object stack) {
int nodeCount = 0;
Object headRef = ObjectTools.get(stack, "cacheHeadRef");
- for (Object node = ObjectTools.get(headRef, "value"); node != null; node = ObjectTools.get(node, "next")) {
+ Object pair = ObjectTools.get(headRef, "pair");
+ for (Object node = ObjectTools.get(pair, "reference"); node != null; node = ObjectTools.get(node, "next")) {
nodeCount++;
}
assertEquals(size, nodeCount);

Back to the top