View Javadoc

1   /***
2    *  Copyright 2003-2010 Terracotta, Inc.
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 net.sf.ehcache.constructs.blocking;
18  
19  import net.sf.ehcache.Cache;
20  import net.sf.ehcache.CacheException;
21  import net.sf.ehcache.CacheTest;
22  import net.sf.ehcache.Ehcache;
23  import net.sf.ehcache.Element;
24  import net.sf.ehcache.Status;
25  import net.sf.ehcache.config.CacheConfiguration;
26  import net.sf.ehcache.statistics.LiveCacheStatistics;
27  import org.junit.After;
28  import org.junit.Before;
29  import org.junit.Test;
30  
31  import java.io.Serializable;
32  import java.util.ArrayList;
33  import java.util.HashMap;
34  import java.util.List;
35  import java.util.Map;
36  import java.util.concurrent.BrokenBarrierException;
37  import java.util.concurrent.CyclicBarrier;
38  
39  import static org.junit.Assert.assertEquals;
40  import static org.junit.Assert.assertNotNull;
41  import static org.junit.Assert.assertNull;
42  import static org.junit.Assert.assertTrue;
43  import static org.junit.Assert.fail;
44  
45  /***
46   * Test cases for the {@link BlockingCache}.
47   *
48   * @author Adam Murdoch
49   * @author Greg Luck
50   * @version $Id: BlockingCacheTest.java 2539 2010-07-02 10:58:13Z alexsnaps $
51   */
52  public class BlockingCacheTest extends CacheTest {
53  
54      private BlockingCache blockingCache;
55  
56      /***
57       * Load up the test cache
58       */
59      @Override
60      @Before
61      public void setUp() throws Exception {
62          super.setUp();
63          Ehcache cache = manager.getCache("sampleIdlingExpiringCache");
64          blockingCache = new BlockingCache(cache);
65      }
66  
67      /***
68       * teardown
69       */
70      @Override
71      @After
72      public void tearDown() throws Exception {
73          if (manager.getStatus() == Status.STATUS_ALIVE) {
74              blockingCache.removeAll();
75          }
76          super.tearDown();
77      }
78  
79      @Test
80      public void testSupportsStatsCorrectly() {
81          blockingCache.setStatisticsEnabled(true);
82          LiveCacheStatistics statistics = blockingCache.getLiveCacheStatistics();
83          long cacheMisses = statistics.getCacheMissCount();
84          long cacheHits = statistics.getCacheHitCount();
85          String key = "123451234";
86          blockingCache.get(key);
87          assertEquals("Misses stat should have incremented by one", cacheMisses + 1, statistics.getCacheMissCount());
88          assertEquals("Hits stat should have remain the same", cacheHits, statistics.getCacheHitCount());
89          blockingCache.put(new Element(key, "value"));
90          assertEquals("Misses stat should have incremented by one", cacheMisses + 1, statistics.getCacheMissCount());
91          assertEquals("Hits stat should have remain the same", cacheHits, statistics.getCacheHitCount());
92          assertNotNull(blockingCache.get(key));
93          assertEquals("Hits stat should have incremented by one", cacheHits + 1, statistics.getCacheHitCount());
94          blockingCache.setStatisticsEnabled(false);
95          blockingCache.remove(key);
96      }
97  
98      /***
99       * Tests adding and looking up an entry.
100      */
101     @Test
102     public void testAddEntry() throws Exception {
103         //some other test was leaving this non-empty
104         blockingCache.removeAll();
105 
106         final String key = "key";
107         final String value = "value";
108         Element element = new Element(key, value);
109 
110         // Check the cache is empty
111         assertEquals(0, blockingCache.getKeys().size());
112 
113         // Put the entry
114         blockingCache.put(new Element(key, value));
115 
116         // Check there is a single entry
117         assertEquals(1, blockingCache.getKeys().size());
118         assertTrue(blockingCache.getKeys().contains(key));
119         final Element returnedElement = blockingCache.get(key);
120         assertEquals(element, returnedElement);
121 
122     }
123 
124     /***
125      * Tests that getting entries matches a list of known entries
126      */
127     @Test
128     public void testGetEntries() throws Exception {
129         Ehcache cache = blockingCache.getCache();
130         for (int i = 0; i < 100; i++) {
131             cache.put(new Element(Integer.valueOf(i), "value" + i));
132         }
133         List keys = blockingCache.getKeys();
134         List elements = new ArrayList();
135         for (int i = 0; i < keys.size(); i++) {
136             Object key = keys.get(i);
137             elements.add(blockingCache.get(key));
138         }
139         assertEquals(100, elements.size());
140         Map map = new HashMap();
141         for (int i = 0; i < elements.size(); i++) {
142             Element element = (Element)elements.get(i);
143             map.put(element.getObjectKey(), element.getObjectValue());
144         }
145         for (int i = 0; i < 100; i++) {
146             Serializable value = (Serializable)map.get(Integer.valueOf(i));
147             assertEquals("value" + i, value);
148         }
149     }
150 
151     /***
152      * Tests looking up a missing entry, then adding it.
153      */
154     @Test
155     public void testAddMissingEntry() throws Exception {
156         Element element = new Element("key", "value");
157 
158         // Make sure the entry does not exist
159         assertNull(blockingCache.get("key"));
160 
161         // Put the entry
162         blockingCache.put(element);
163 
164         // Check the entry is in the cache
165         assertEquals(1, blockingCache.getKeys().size());
166         assertEquals(element, blockingCache.get("key"));
167 
168     }
169 
170 
171     /***
172      * Does a second tread block until the first thread puts the entry?
173      */
174     @Test
175     public void testSecondThreadActuallyBlocks() throws Exception {
176         Element element = new Element("key", "value");
177         final List threadResults = new ArrayList();
178 
179         // Make sure the entry does not exist
180         assertNull(blockingCache.get("key"));
181 
182         Thread secondThread = new Thread() {
183             @Override
184             public void run() {
185                 threadResults.add(blockingCache.get("key"));
186             }
187         };
188         secondThread.start();
189         assertEquals(0, threadResults.size());
190 
191         // Put the entry
192         blockingCache.put(element);
193         Thread.sleep(30);
194         assertEquals(1, threadResults.size());
195         assertEquals(element, threadResults.get(0));
196 
197         // Check the entry is in the cache
198         assertEquals(1, blockingCache.getKeys().size());
199         assertEquals(element, blockingCache.get("key"));
200     }
201 
202     /***
203      * Elements with null valuea are not stored in the blocking cache
204      */
205     @Test
206     public void testUnknownEntry() throws Exception {
207         // Make sure the entry does not exist
208         assertNull(blockingCache.get("key"));
209         // Put the entry
210         blockingCache.put(new Element("key", null));
211         assertEquals(0, blockingCache.getKeys().size());
212     }
213 
214     /***
215      * Overwriting an Element with an element with a null value effectively removes it from the cache
216      */
217     @Test
218     public void testRemoveEntry() throws Exception {
219         Element element = new Element("key", "value");
220 
221         // Add entry and make sure it's there
222         blockingCache.put(element);
223         assertEquals(element, blockingCache.get("key"));
224 
225         // Remove the entry and make sure its gone
226         blockingCache.put(new Element("key", null));
227         assertEquals(0, blockingCache.getKeys().size());
228 
229     }
230 
231     /***
232      * Tests clearing the cache
233      */
234     @Test
235     public void testClear() throws Exception {
236         Ehcache cache = manager.getCache("sampleCacheNotEternalButNoIdleOrExpiry");
237         blockingCache = new BlockingCache(cache);
238         // Add some entries
239         blockingCache.put(new Element("key1", "value1"));
240         blockingCache.put(new Element("key2", "value2"));
241         blockingCache.put(new Element("key3", "value2"));
242         assertEquals(3, blockingCache.getKeys().size());
243 
244         // Clear the cache
245         blockingCache.removeAll();
246         assertEquals(0, blockingCache.getKeys().size());
247     }
248 
249 
250     /***
251      * Creates a blocking test cache
252      */
253     @Override
254     protected Ehcache createTestCache() {
255         Ehcache cache = super.createTestCache();
256         return new BlockingCache(cache);
257     }
258 
259     /***
260      * Gets the sample cache 1
261      */
262     @Override
263     protected Ehcache getSampleCache1() {
264         Cache cache = manager.getCache("sampleCache1");
265         manager.replaceCacheWithDecoratedCache(cache, new BlockingCache(cache));
266         return manager.getEhcache("sampleCache1");
267     }
268 
269     /***
270      * Use to manually test super class tests
271      */
272     @Test
273     public void testInstrumented() throws Exception {
274         super.testSizes();
275     }
276 
277     @Override
278     @Test
279     public void testGetWithLoader() {
280         super.testGetWithLoader();
281     }
282 
283 
284     @Override
285     @Test
286     public void testFlushWhenOverflowToDisk() throws Exception {
287         super.testFlushWhenOverflowToDisk();
288     }
289 
290     @Override
291     @Test
292     public void testConcurrentPutsAreConsistentRepeatedly() throws InterruptedException {
293         //do nothing
294     }
295 
296     @Override
297     @Test
298     public void testConcurrentPutsAreConsistent() throws InterruptedException {
299         //do nothing
300     }
301 
302     @Test
303     public void testInlineEviction() throws InterruptedException {
304 
305         final Serializable KEY = "DUH";
306         Cache cache = new Cache(new CacheConfiguration("fastExpiry", 1000).timeToIdleSeconds(2).timeToLiveSeconds(2));
307         manager.addCache(cache);
308         manager.replaceCacheWithDecoratedCache(cache, new BlockingCache(cache));
309 
310         Ehcache blockingCache = manager.getEhcache("fastExpiry");
311         blockingCache.put(new Element(KEY, "VALUE"));
312         assertNotNull(blockingCache.get(KEY));
313         // This tests inline eviction (EHC-420)
314         Thread.sleep(3000);
315         assertNull(blockingCache.get(KEY));
316     }
317 
318     @Test
319     public void testTimeout() throws BrokenBarrierException, InterruptedException {
320         final CyclicBarrier barrier = new CyclicBarrier(2);
321         final String KEY = "BLOCKING_KEY";
322         blockingCache.setTimeoutMillis(1000);
323         Thread thread = new Thread(new Runnable() {
324             public void run() {
325                 assertNull(blockingCache.get(KEY));
326                 try {
327                     barrier.await();
328                     Thread.sleep(5000);
329                 } catch (Exception e) {
330                     throw new RuntimeException(e);
331                 }
332                 blockingCache.put(new Element(KEY, "VALUE"));
333             }
334         });
335         thread.start();
336         barrier.await();
337         try {
338             blockingCache.get(KEY);
339             fail("BlockingCache.get should have not returned!");
340         } catch (CacheException e) {
341             // Expected
342         }
343     }
344 }
345