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  
18  package net.sf.ehcache;
19  
20  import org.junit.After;
21  import static org.junit.Assert.assertTrue;
22  import org.junit.Before;
23  import org.junit.Test;
24  
25  import java.io.Serializable;
26  import java.util.ArrayList;
27  import java.util.List;
28  
29  import org.slf4j.Logger;
30  import org.slf4j.LoggerFactory;
31  
32  
33  /***
34   * Demonstrates a problem with Ben Manes' ConcurrentLinkedHashmap. This was used in beta4 but was found not to be
35   * threadsafe. After a few days of work isolating the issue to ConcurrentLinkedHashmap, this test pinpoints the problem
36   * in about 30 seconds.
37   *
38   * Though ConcurrentLinkedHashmap is no longer used, leave this test here so that we can retest new versions that
39   * may come out.
40   *
41   * @author Greg Luck
42   */
43  public class ConcurrencyProblemCacheTest extends AbstractCacheTest {
44  
45      private static final Logger LOG = LoggerFactory.getLogger(ConcurrencyProblemCacheTest.class.getName());
46  
47      private CacheManager manager;
48  
49      private Cache cache;
50  
51      @Before
52      public void setUp() throws Exception {
53          super.setUp();
54          manager = new CacheManager();
55      }
56  
57      /***
58       * teardown
59       */
60      @After
61      public void tearDown() throws Exception {
62          manager.shutdown();
63          super.tearDown();
64      }
65  
66      @Test
67      public void testContinuousThrashConfiguration() throws Exception {
68          cache = manager.getCache("sampleIdlingExpiringCache");
69          for (int i = 0; i < 5; i++) {
70              thrashCache(cache, 1500L);
71              LOG.info("Finished run.");
72          }
73      }
74  
75      @Test
76      public void testContinuousThrashProgrammatic() throws Exception {
77          cache = new Cache("thrashcache", 5, false, false, 2, 5);
78          manager.addCache(cache);
79          for (int i = 0; i < 5; i++) {
80              thrashCache(cache, 1500L);
81              LOG.info("Finished run.");
82  
83          }
84      }
85  
86      /***
87       * This method tries to get the cache to slow up.
88       * It creates 10 threads, does gets and puts.
89       */
90      private long thrashCache(final Cache cache, final long retrievalTime)
91              throws Exception {
92          StopWatch stopWatch = new StopWatch();
93  
94          // Create threads that do gets
95          final List executables = new ArrayList();
96          for (int i = 0; i < 10; i++) {
97              final Executable executable = new Executable() {
98                  public void execute() throws Exception {
99                      for (int i = 0; i < 10; i++) {
100                         final String key = "key" + i;
101                         Object value = cache.get(key);
102                         if (value == null) {
103                             cache.put(new Element(key, "value" + i));
104                         }
105                         //The key will be in. Now check we can get it quickly
106                         checkRetrievalOnKnownKey(cache, retrievalTime, key);
107                     }
108                 }
109             };
110             executables.add(executable);
111         }
112 
113         runThreads(executables);
114         cache.removeAll();
115         return stopWatch.getElapsedTime();
116     }
117 
118 
119     /***
120      * Checks that the liveness method returns in less than a given amount of time.
121      * liveness() is a method that simply returns a String. It should be very fast. It can be
122      * delayed because it is a synchronized method, and must acquire
123      * an object lock before continuing. The old blocking cache was taking up to several minutes in production
124      *
125      * @param cache a BlockingCache
126      */
127     private void checkRetrievalOnKnownKey(Cache cache, long requiredRetrievalTime, Serializable key) {
128         StopWatch stopWatch = new StopWatch();
129         cache.get(key);
130         long measuredRetrievalTime = stopWatch.getElapsedTime();
131         assertTrue("Retrieval time on known key is " + measuredRetrievalTime
132                 + " but should be less than " + requiredRetrievalTime + "ms",
133                 measuredRetrievalTime < requiredRetrievalTime);
134     }
135 }