Skip to content

Commit

Permalink
Added stack multi-threaded test; extracted common thread code for reuse
Browse files Browse the repository at this point in the history
  • Loading branch information
ben-manes committed Apr 18, 2015
1 parent 7772145 commit 2de80ef
Show file tree
Hide file tree
Showing 32 changed files with 351 additions and 272 deletions.
12 changes: 8 additions & 4 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ buildscript {
apply from: "${rootDir}/gradle/dependencies.gradle"

repositories {
mavenCentral()
jcenter()
}

Expand All @@ -26,6 +27,13 @@ task testReport(type: TestReport, group: 'Build') {
destinationDir = file("${buildDir}/reports/allTests")
}

allprojects {
repositories {
mavenCentral()
jcenter()
}
}

subprojects { proj ->
if (proj.name == 'tracing') {
return
Expand All @@ -51,10 +59,6 @@ subprojects { proj ->
}
archivesBaseName = path[1..-1].replaceAll(':', '-').toLowerCase()

repositories {
jcenter()
}

configurations {
testArtifacts
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,10 @@
* This implementation employs elimination and combination to transfer elements between threads that
* are pushing and popping concurrently. This technique avoids contention on the stack by attempting
* to cancel opposing operations and merge additive operations if an immediate update to the stack
* is not successful. When a pair of operations collide, the task of performing the combined set of
* operations is delegated to one of the threads and the other thread optionally waits for its
* operation to be completed. This decision of whether to wait for completion is determined by
* constructing either a <em>linearizable</em> or <em>optimistic</em> stack.
* is not successful. When a pair of additive operations collide, the task of performing the
* combined set of operations is delegated to one of the threads and the other thread optionally
* waits for its operation to be completed. This decision of whether to wait for completion is
* determined by constructing either a <em>linearizable</em> or <em>optimistic</em> stack.
* <p>
* Iterators are <i>weakly consistent</i>, returning elements reflecting the state of the stack at
* some point at or since the creation of the iterator. They do <em>not</em> throw
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -446,7 +446,7 @@ Object readResolve() {
}

static class Node<E> {
final static long NEXT_OFFSET = UnsafeAccess.objectFieldOffset(Node.class, "next");
static final long NEXT_OFFSET = UnsafeAccess.objectFieldOffset(Node.class, "next");

E value;
volatile Node<E> next;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@
import com.github.benmanes.caffeine.ConcurrentLinkedStack.Node;
import com.github.benmanes.caffeine.ConcurrentLinkedStackTest.ValidatingStackListener;
import com.github.benmanes.caffeine.base.UnsafeAccess;
import com.github.benmanes.caffeine.testing.Awaits;
import com.google.common.collect.Iterables;
import com.google.common.testing.SerializableTester;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/
package com.github.benmanes.caffeine;

import static com.github.benmanes.caffeine.matchers.IsEmptyIterable.deeplyEmpty;
import static com.github.benmanes.caffeine.testing.IsEmptyIterable.deeplyEmpty;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.nullValue;
Expand All @@ -29,7 +29,7 @@
import org.hamcrest.TypeSafeDiagnosingMatcher;

import com.github.benmanes.caffeine.ConcurrentLinkedStack.Node;
import com.github.benmanes.caffeine.matchers.DescriptionBuilder;
import com.github.benmanes.caffeine.testing.DescriptionBuilder;
import com.google.common.collect.Sets;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/
package com.github.benmanes.caffeine;

import static com.github.benmanes.caffeine.matchers.IsEmptyIterable.deeplyEmpty;
import static com.github.benmanes.caffeine.testing.IsEmptyIterable.deeplyEmpty;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
Expand All @@ -30,7 +30,7 @@
import org.hamcrest.TypeSafeDiagnosingMatcher;

import com.github.benmanes.caffeine.SingleConsumerQueue.Node;
import com.github.benmanes.caffeine.matchers.DescriptionBuilder;
import com.github.benmanes.caffeine.testing.DescriptionBuilder;
import com.google.common.collect.Sets;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
package com.github.benmanes.caffeine;

import static com.github.benmanes.caffeine.IsValidSingleConsumerQueue.validate;
import static com.github.benmanes.caffeine.matchers.IsEmptyIterable.deeplyEmpty;
import static com.github.benmanes.caffeine.testing.IsEmptyIterable.deeplyEmpty;
import static com.google.common.collect.Iterators.elementsEqual;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.arrayContaining;
Expand Down Expand Up @@ -46,6 +46,7 @@

import com.github.benmanes.caffeine.SingleConsumerQueue.LinearizableNode;
import com.github.benmanes.caffeine.SingleConsumerQueueTest.ValidatingQueueListener;
import com.github.benmanes.caffeine.testing.Awaits;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Iterables;
import com.google.common.testing.SerializableTester;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* Copyright 2015 Ben Manes. All Rights Reserved.
*
* Licensed 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 com.github.benmanes.caffeine;

import java.util.List;
import java.util.function.BiConsumer;

import org.testng.annotations.DataProvider;
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;

import com.github.benmanes.caffeine.ConcurrentLinkedStackTest.ValidatingStackListener;
import com.github.benmanes.caffeine.testing.Threads;
import com.google.common.collect.ImmutableList;
import com.google.common.testing.SerializableTester;

import scala.concurrent.forkjoin.ThreadLocalRandom;

/**
* @author ben.manes@gmail.com (Ben Manes)
*/
@Listeners(ValidatingStackListener.class)
public final class StackMultiThreadedTest {

@Test(dataProvider = "queues")
public void thrash(ConcurrentLinkedStack<Integer> stack) {
Threads.runTest(stack, operations);
}

@DataProvider(name = "queues")
public Object[][] providesQueues() {
return new Object[][] {
{ ConcurrentLinkedStack.optimistic() },
{ ConcurrentLinkedStack.linearizable() }};
}

@SuppressWarnings({"unchecked", "rawtypes"})
List<BiConsumer<ConcurrentLinkedStack<Integer>, Integer>> operations = ImmutableList.of(
// Stack
(c, e) -> c.push(e),
(c, e) -> c.pop(),
(c, e) -> c.peek(),

// Queue
(c, e) -> c.asLifoQueue().offer(e),
(c, e) -> c.asLifoQueue().poll(),
(c, e) -> c.asLifoQueue().peek(),

// Collection
(c, e) -> c.size(),
(c, e) -> c.isEmpty(),
(c, e) -> c.contains(e),
(c, e) -> c.containsAll(ImmutableList.of(e, e)),
(c, e) -> c.add(e),
(c, e) -> c.addAll(ImmutableList.of(e, e)),
(c, e) -> c.remove(e),
(c, e) -> c.removeAll(ImmutableList.of(e, e)),
(c, e) -> { // expensive so do it less frequently
int random = ThreadLocalRandom.current().nextInt();
if ((random & 255) == 0) {
c.retainAll(ImmutableList.of(e, e));
}
},
(c, e) -> { // expensive so do it less frequently
int random = ThreadLocalRandom.current().nextInt();
if ((random & 255) == 0) {
c.clear();
}
},
(c, e) -> { // expensive so do it less frequently
int random = ThreadLocalRandom.current().nextInt();
if ((random & 255) == 0) {
SerializableTester.reserialize(c);
}
});
}
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
import static com.github.benmanes.caffeine.cache.testing.HasStats.hasLoadFailureCount;
import static com.github.benmanes.caffeine.cache.testing.HasStats.hasLoadSuccessCount;
import static com.github.benmanes.caffeine.cache.testing.HasStats.hasMissCount;
import static com.github.benmanes.caffeine.matchers.IsEmptyIterable.deeplyEmpty;
import static com.github.benmanes.caffeine.matchers.IsEmptyMap.emptyMap;
import static com.github.benmanes.caffeine.testing.IsEmptyIterable.deeplyEmpty;
import static com.github.benmanes.caffeine.testing.IsEmptyMap.emptyMap;
import static com.google.common.collect.Maps.immutableEntry;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.both;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
import static com.github.benmanes.caffeine.cache.testing.HasStats.hasLoadFailureCount;
import static com.github.benmanes.caffeine.cache.testing.HasStats.hasLoadSuccessCount;
import static com.github.benmanes.caffeine.cache.testing.HasStats.hasMissCount;
import static com.github.benmanes.caffeine.matchers.IsFutureValue.futureOf;
import static com.github.benmanes.caffeine.testing.IsFutureValue.futureOf;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.both;
import static org.hamcrest.Matchers.equalTo;
Expand All @@ -46,7 +46,6 @@
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;

import com.github.benmanes.caffeine.Awaits;
import com.github.benmanes.caffeine.cache.testing.CacheContext;
import com.github.benmanes.caffeine.cache.testing.CacheProvider;
import com.github.benmanes.caffeine.cache.testing.CacheSpec;
Expand All @@ -56,6 +55,7 @@
import com.github.benmanes.caffeine.cache.testing.CacheSpec.Loader;
import com.github.benmanes.caffeine.cache.testing.CacheSpec.MaximumSize;
import com.github.benmanes.caffeine.cache.testing.CacheSpec.Population;
import com.github.benmanes.caffeine.testing.Awaits;
import com.github.benmanes.caffeine.cache.testing.CacheValidationListener;
import com.github.benmanes.caffeine.cache.testing.CheckNoStats;
import com.google.common.collect.ImmutableList;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
import org.testng.annotations.DataProvider;
import org.testng.annotations.Test;

import com.github.benmanes.caffeine.Awaits;
import com.github.benmanes.caffeine.testing.Awaits;

/**
* @author ben.manes@gmail.com (Ben Manes)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;

import com.github.benmanes.caffeine.Awaits;
import com.github.benmanes.caffeine.ConcurrentTestHarness;
import com.github.benmanes.caffeine.cache.BoundedLocalCache.DrainStatus;
import com.github.benmanes.caffeine.cache.Policy.Eviction;
Expand All @@ -50,6 +49,7 @@
import com.github.benmanes.caffeine.cache.testing.CacheSpec.Population;
import com.github.benmanes.caffeine.cache.testing.CacheValidationListener;
import com.github.benmanes.caffeine.locks.NonReentrantLock;
import com.github.benmanes.caffeine.testing.Awaits;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@

import static com.github.benmanes.caffeine.cache.testing.HasRemovalNotifications.hasRemovalNotifications;
import static com.github.benmanes.caffeine.cache.testing.HasStats.hasEvictionCount;
import static com.github.benmanes.caffeine.matchers.IsEmptyMap.emptyMap;
import static com.github.benmanes.caffeine.testing.IsEmptyMap.emptyMap;
import static java.util.Arrays.asList;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
Expand All @@ -37,7 +37,6 @@
import org.testng.annotations.Listeners;
import org.testng.annotations.Test;

import com.github.benmanes.caffeine.Awaits;
import com.github.benmanes.caffeine.cache.Policy.Eviction;
import com.github.benmanes.caffeine.cache.simulator.generator.IntegerGenerator;
import com.github.benmanes.caffeine.cache.simulator.generator.ScrambledZipfianGenerator;
Expand All @@ -52,6 +51,7 @@
import com.github.benmanes.caffeine.cache.testing.CacheSpec.ReferenceType;
import com.github.benmanes.caffeine.cache.testing.CacheValidationListener;
import com.github.benmanes.caffeine.cache.testing.RemovalListeners.RejectingRemovalListener;
import com.github.benmanes.caffeine.testing.Awaits;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.Iterables;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
package com.github.benmanes.caffeine.cache;

import static com.github.benmanes.caffeine.cache.testing.HasRemovalNotifications.hasRemovalNotifications;
import static com.github.benmanes.caffeine.matchers.IsEmptyMap.emptyMap;
import static com.github.benmanes.caffeine.testing.IsEmptyMap.emptyMap;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@
package com.github.benmanes.caffeine.cache;

import static com.github.benmanes.caffeine.cache.testing.HasRemovalNotifications.hasRemovalNotifications;
import static com.github.benmanes.caffeine.matchers.IsEmptyMap.emptyMap;
import static com.github.benmanes.caffeine.testing.IsEmptyMap.emptyMap;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,7 @@
import org.hamcrest.TypeSafeDiagnosingMatcher;

import com.github.benmanes.caffeine.cache.Async.AsyncWeigher;
import com.github.benmanes.caffeine.matchers.DescriptionBuilder;
import com.github.benmanes.caffeine.testing.DescriptionBuilder;
import com.google.common.testing.SerializableTester;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/
package com.github.benmanes.caffeine.cache;

import static com.github.benmanes.caffeine.matchers.IsEmptyMap.emptyMap;
import static com.github.benmanes.caffeine.testing.IsEmptyMap.emptyMap;
import static org.hamcrest.Matchers.greaterThanOrEqualTo;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
Expand All @@ -30,7 +30,7 @@
import org.hamcrest.Factory;
import org.hamcrest.TypeSafeDiagnosingMatcher;

import com.github.benmanes.caffeine.matchers.DescriptionBuilder;
import com.github.benmanes.caffeine.testing.DescriptionBuilder;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/
package com.github.benmanes.caffeine.cache;

import static com.github.benmanes.caffeine.matchers.IsEmptyIterable.deeplyEmpty;
import static com.github.benmanes.caffeine.testing.IsEmptyIterable.deeplyEmpty;
import static org.hamcrest.Matchers.hasSize;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
Expand All @@ -29,7 +29,7 @@
import org.hamcrest.Factory;
import org.hamcrest.TypeSafeDiagnosingMatcher;

import com.github.benmanes.caffeine.matchers.DescriptionBuilder;
import com.github.benmanes.caffeine.testing.DescriptionBuilder;
import com.google.common.collect.Sets;

/**
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/
package com.github.benmanes.caffeine.cache;

import static com.github.benmanes.caffeine.matchers.IsEmptyMap.emptyMap;
import static com.github.benmanes.caffeine.testing.IsEmptyMap.emptyMap;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.not;
import static org.hamcrest.Matchers.nullValue;
Expand All @@ -27,7 +27,7 @@
import org.hamcrest.Factory;
import org.hamcrest.TypeSafeDiagnosingMatcher;

import com.github.benmanes.caffeine.matchers.DescriptionBuilder;
import com.github.benmanes.caffeine.testing.DescriptionBuilder;

/**
* A matcher that evaluates a {@link UnboundedLocalCache} to determine if it is in a valid state.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
*/
package com.github.benmanes.caffeine.cache;

import static com.github.benmanes.caffeine.matchers.IsEmptyIterable.deeplyEmpty;
import static com.github.benmanes.caffeine.testing.IsEmptyIterable.deeplyEmpty;
import static com.google.common.collect.Iterators.elementsEqual;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.Matchers.hasSize;
Expand Down
Loading

0 comments on commit 2de80ef

Please sign in to comment.