• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2011 The Guava Authors
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package com.google.common.util.concurrent;
18 
19 import static com.google.common.collect.Iterables.concat;
20 
21 import com.google.common.base.Functions;
22 import com.google.common.base.Supplier;
23 import com.google.common.collect.ImmutableList;
24 import com.google.common.collect.Lists;
25 import com.google.common.collect.Maps;
26 import com.google.common.collect.Ordering;
27 import com.google.common.collect.Sets;
28 import com.google.common.testing.GcFinalization;
29 import com.google.common.testing.NullPointerTester;
30 
31 import junit.framework.TestCase;
32 
33 import java.lang.ref.WeakReference;
34 import java.util.List;
35 import java.util.Map;
36 import java.util.Set;
37 import java.util.concurrent.Semaphore;
38 import java.util.concurrent.locks.Lock;
39 import java.util.concurrent.locks.ReadWriteLock;
40 import java.util.concurrent.locks.ReentrantLock;
41 import java.util.concurrent.locks.ReentrantReadWriteLock;
42 
43 /**
44  * Tests for Striped.
45  *
46  * @author Dimitris Andreou
47  */
48 public class StripedTest extends TestCase {
strongImplementations()49   private static List<Striped<?>> strongImplementations() {
50     return ImmutableList.of(
51         Striped.readWriteLock(100),
52         Striped.readWriteLock(256),
53         Striped.lock(100),
54         Striped.lock(256),
55         Striped.semaphore(100, 1),
56         Striped.semaphore(256, 1));
57   }
58 
59   private static final Supplier<ReadWriteLock> READ_WRITE_LOCK_SUPPLIER =
60       new Supplier<ReadWriteLock>() {
61     @Override public ReadWriteLock get() {
62       return new ReentrantReadWriteLock();
63     }
64   };
65 
66   private static final Supplier<Lock> LOCK_SUPPLER = new Supplier<Lock>() {
67     @Override public Lock get() {
68       return new ReentrantLock();
69     }
70   };
71 
72   private static final Supplier<Semaphore> SEMAPHORE_SUPPLER = new Supplier<Semaphore>() {
73     @Override public Semaphore get() {
74       return new Semaphore(1, false);
75     }
76   };
77 
weakImplementations()78   private static List<Striped<?>> weakImplementations() {
79     return ImmutableList.<Striped<?>>builder()
80         .add(new Striped.SmallLazyStriped<ReadWriteLock>(50, READ_WRITE_LOCK_SUPPLIER))
81         .add(new Striped.SmallLazyStriped<ReadWriteLock>(64, READ_WRITE_LOCK_SUPPLIER))
82         .add(new Striped.LargeLazyStriped<ReadWriteLock>(50, READ_WRITE_LOCK_SUPPLIER))
83         .add(new Striped.LargeLazyStriped<ReadWriteLock>(64, READ_WRITE_LOCK_SUPPLIER))
84         .add(new Striped.SmallLazyStriped<Lock>(50, LOCK_SUPPLER))
85         .add(new Striped.SmallLazyStriped<Lock>(64, LOCK_SUPPLER))
86         .add(new Striped.LargeLazyStriped<Lock>(50, LOCK_SUPPLER))
87         .add(new Striped.LargeLazyStriped<Lock>(64, LOCK_SUPPLER))
88         .add(new Striped.SmallLazyStriped<Semaphore>(50, SEMAPHORE_SUPPLER))
89         .add(new Striped.SmallLazyStriped<Semaphore>(64, SEMAPHORE_SUPPLER))
90         .add(new Striped.LargeLazyStriped<Semaphore>(50, SEMAPHORE_SUPPLER))
91         .add(new Striped.LargeLazyStriped<Semaphore>(64, SEMAPHORE_SUPPLER))
92         .build();
93   }
94 
allImplementations()95   private static Iterable<Striped<?>> allImplementations() {
96     return concat(strongImplementations(), weakImplementations());
97   }
98 
testNull()99   public void testNull() throws Exception {
100     for (Striped<?> striped : allImplementations()) {
101       new NullPointerTester().testAllPublicInstanceMethods(striped);
102     }
103   }
104 
testSizes()105   public void testSizes() {
106     // not bothering testing all variations, since we know they share implementations
107     assertTrue(Striped.lock(100).size() >= 100);
108     assertTrue(Striped.lock(256).size() == 256);
109     assertTrue(Striped.lazyWeakLock(100).size() >= 100);
110     assertTrue(Striped.lazyWeakLock(256).size() == 256);
111   }
112 
testWeakImplementations()113   public void testWeakImplementations() {
114     for (Striped<?> striped : weakImplementations()) {
115       WeakReference<Object> weakRef = new WeakReference<Object>(striped.get(new Object()));
116       GcFinalization.awaitClear(weakRef);
117     }
118   }
119 
testStrongImplementations()120   public void testStrongImplementations() {
121     for (Striped<?> striped : strongImplementations()) {
122       WeakReference<Object> weakRef = new WeakReference<Object>(striped.get(new Object()));
123       WeakReference<Object> garbage = new WeakReference<Object>(new Object());
124       GcFinalization.awaitClear(garbage);
125       assertNotNull(weakRef.get());
126     }
127   }
128 
testMaximalWeakStripedLock()129   public void testMaximalWeakStripedLock() {
130     Striped<Lock> stripedLock = Striped.lazyWeakLock(Integer.MAX_VALUE);
131     for (int i = 0; i < 10000; i++) {
132       stripedLock.get(new Object()).lock();
133       // nothing special (e.g. an exception) happens
134     }
135   }
136 
testBulkGetReturnsSorted()137   public void testBulkGetReturnsSorted() {
138     for (Striped<?> striped : allImplementations()) {
139       Map<Object, Integer> indexByLock = Maps.newHashMap();
140       for (int i = 0; i < striped.size(); i++) {
141         indexByLock.put(striped.getAt(i), i);
142       }
143 
144       // ensure that bulkGet returns locks in monotonically increasing order
145       for (int objectsNum = 1; objectsNum <= striped.size() * 2; objectsNum++) {
146         Set<Object> objects = Sets.newHashSetWithExpectedSize(objectsNum);
147         for (int i = 0; i < objectsNum; i++) {
148           objects.add(new Object());
149         }
150 
151         Iterable<?> locks = striped.bulkGet(objects);
152         assertTrue(Ordering.natural().onResultOf(Functions.forMap(indexByLock)).isOrdered(locks));
153 
154         // check idempotency
155         Iterable<?> locks2 = striped.bulkGet(objects);
156         assertEquals(Lists.newArrayList(locks), Lists.newArrayList(locks2));
157       }
158     }
159   }
160 
161   /**
162    * Checks idempotency, and that we observe the promised number of stripes.
163    */
testBasicInvariants()164   public void testBasicInvariants() {
165     for (Striped<?> striped : allImplementations()) {
166       assertBasicInvariants(striped);
167     }
168   }
169 
assertBasicInvariants(Striped<?> striped)170   private static void assertBasicInvariants(Striped<?> striped) {
171     Set<Object> observed = Sets.newIdentityHashSet(); // for the sake of weakly referenced locks.
172     // this gets the stripes with #getAt(index)
173     for (int i = 0; i < striped.size(); i++) {
174       Object object = striped.getAt(i);
175       assertNotNull(object);
176       assertSame(object, striped.getAt(i)); // idempotent
177       observed.add(object);
178     }
179     assertTrue("All stripes observed", observed.size() == striped.size());
180 
181     // this uses #get(key), makes sure an already observed stripe is returned
182     for (int i = 0; i < striped.size() * 100; i++) {
183       assertTrue(observed.contains(striped.get(new Object())));
184     }
185 
186     try {
187       striped.getAt(-1);
188       fail();
189     } catch (RuntimeException expected) {}
190 
191     try {
192       striped.getAt(striped.size());
193       fail();
194     } catch (RuntimeException expected) {}
195   }
196 
testMaxSize()197   public void testMaxSize() {
198     for (Striped<?> striped : ImmutableList.of(
199         Striped.lazyWeakLock(Integer.MAX_VALUE),
200         Striped.lazyWeakSemaphore(Integer.MAX_VALUE, Integer.MAX_VALUE),
201         Striped.lazyWeakReadWriteLock(Integer.MAX_VALUE))) {
202       for (int i = 0; i < 3; i++) {
203         // doesn't throw exception
204         striped.getAt(Integer.MAX_VALUE - i);
205       }
206     }
207   }
208 }
209