1 package org.apache.jcs;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 import java.util.ArrayList;
23 import java.util.List;
24
25 import junit.framework.TestCase;
26
27 import org.apache.commons.logging.Log;
28 import org.apache.commons.logging.LogFactory;
29 import org.apache.jcs.engine.stats.behavior.IStatElement;
30 import org.apache.jcs.engine.stats.behavior.IStats;
31
32 /***
33 * This is based on a test that was posted to the user's list:
34 *
35 * http://www.opensubscriber.com/message/jcs-users@jakarta.apache.org/2435965.html
36 *
37 */
38 public class JCSThrashTest
39 extends TestCase
40 {
41
42 private static final Log LOG = LogFactory.getLog( JCSThrashTest.class.getName() );
43
44 /***
45 * the cache instance
46 */
47 protected JCS jcs;
48
49 /***
50 * @param args
51 */
52 public static void main( String[] args )
53 {
54 junit.textui.TestRunner.run( JCSThrashTest.class );
55 }
56
57 /***
58 * @param arg0
59 */
60 public JCSThrashTest( String arg0 )
61 {
62 super( arg0 );
63 }
64
65 protected void setUp()
66 throws Exception
67 {
68 super.setUp();
69 JCS.setConfigFilename( "/TestThrash.ccf" );
70 jcs = JCS.getInstance( "testcache" );
71 }
72
73 protected void tearDown()
74 throws Exception
75 {
76 super.tearDown();
77 jcs.clear();
78 jcs.dispose();
79 }
80
81 /***
82 * Tests adding an entry.
83 * @throws Exception
84 */
85 public void testPut()
86 throws Exception
87 {
88 final String value = "value";
89 final String key = "key";
90
91
92 assertEquals( 0, getListSize() );
93
94 assertNull( jcs.get( key ) );
95
96 jcs.put( key, value );
97
98
99 LOG.info( "jcs.getStats(): " + jcs.getStatistics() );
100 assertEquals( 1, getListSize() );
101 assertNotNull( jcs.get( key ) );
102 assertEquals( value, jcs.get( key ) );
103 }
104
105 /***
106 * Test elements can be removed from the store
107 * @throws Exception
108 */
109 public void testRemove()
110 throws Exception
111 {
112 jcs.put( "key1", "value1" );
113 assertEquals( 1, getListSize() );
114
115 jcs.remove( "key1" );
116 assertEquals( 0, getListSize() );
117
118 jcs.put( "key2", "value2" );
119 jcs.put( "key3", "value3" );
120 assertEquals( 2, getListSize() );
121
122 jcs.remove( "key2" );
123 assertEquals( 1, getListSize() );
124
125
126 jcs.remove( "key4" );
127 assertEquals( 1, getListSize() );
128 }
129
130 /***
131 * This does a bunch of work and then verifies that the memory has not grown by much.
132 * Most of the time the amount of memory used after the test is less.
133 *
134 * @throws Exception
135 */
136 public void testForMemoryLeaks()
137 throws Exception
138 {
139 long differenceMemoryCache = thrashCache();
140 LOG.info( "Memory Difference is: " + differenceMemoryCache );
141 assertTrue( differenceMemoryCache < 500000 );
142
143
144 }
145
146 /***
147 * @return
148 * @throws Exception
149 */
150 protected long thrashCache()
151 throws Exception
152 {
153
154 long startingSize = measureMemoryUse();
155 LOG.info( "Memory Used is: " + startingSize );
156
157 final String value = "value";
158 final String key = "key";
159
160
161 jcs.put( key, value );
162
163
164 final List executables = new ArrayList();
165 for ( int i = 0; i < 15; i++ )
166 {
167 final JCSThrashTest.Executable executable = new JCSThrashTest.Executable()
168 {
169 public void execute()
170 throws Exception
171 {
172 for ( int i = 0; i < 500; i++ )
173 {
174 final String key = "key" + i;
175 jcs.get( key );
176 }
177 jcs.get( "key" );
178 }
179 };
180 executables.add( executable );
181 }
182
183
184
185 for ( int i = 0; i < 15; i++ )
186 {
187 final JCSThrashTest.Executable executable = new JCSThrashTest.Executable()
188 {
189 public void execute()
190 throws Exception
191 {
192
193
194 for ( int i = 0; i < 500; i++ )
195 {
196
197 final String key = "key" + i;
198 byte[] value = new byte[10000];
199 jcs.put( key, value );
200 }
201 }
202 };
203 executables.add( executable );
204 }
205
206 runThreads( executables );
207 jcs.clear();
208
209 long finishingSize = measureMemoryUse();
210 LOG.info( "Memory Used is: " + finishingSize );
211 return finishingSize - startingSize;
212 }
213
214 /***
215 * Runs a set of threads, for a fixed amount of time.
216 * @param executables
217 * @throws Exception
218 */
219 protected void runThreads( final List executables )
220 throws Exception
221 {
222
223 final long endTime = System.currentTimeMillis() + 10000;
224 final Throwable[] errors = new Throwable[1];
225
226
227 final Thread[] threads = new Thread[executables.size()];
228 for ( int i = 0; i < threads.length; i++ )
229 {
230 final JCSThrashTest.Executable executable = (JCSThrashTest.Executable) executables.get( i );
231 threads[i] = new Thread()
232 {
233 public void run()
234 {
235 try
236 {
237
238 while ( System.currentTimeMillis() < endTime )
239 {
240 executable.execute();
241 }
242 }
243 catch ( Throwable t )
244 {
245
246 errors[0] = t;
247 }
248 }
249 };
250 threads[i].start();
251 }
252
253
254 for ( int i = 0; i < threads.length; i++ )
255 {
256 threads[i].join();
257 }
258
259
260 if ( errors[0] != null )
261 {
262 throw new Exception( "Test thread failed.", errors[0] );
263 }
264 }
265
266 /***
267 * Measure memory used by the VM.
268 *
269 * @return
270 * @throws InterruptedException
271 */
272 protected long measureMemoryUse()
273 throws InterruptedException
274 {
275 System.gc();
276 Thread.sleep( 3000 );
277 System.gc();
278 return Runtime.getRuntime().totalMemory() - Runtime.getRuntime().freeMemory();
279 }
280
281 /***
282 * A runnable, that can throw an exception.
283 */
284 protected interface Executable
285 {
286 /***
287 * Executes this object.
288 *
289 * @throws Exception
290 */
291 void execute()
292 throws Exception;
293 }
294
295 /***
296 *
297 * @return
298 */
299 private int getListSize()
300 {
301 final String listSize = "List Size";
302 final String lruMemoryCache = "LRU Memory Cache";
303 String result = "0";
304 IStats istats[] = jcs.getStatistics().getAuxiliaryCacheStats();
305 for ( int i = 0; i < istats.length; i++ )
306 {
307 IStatElement statElements[] = istats[i].getStatElements();
308 if ( lruMemoryCache.equals( istats[i].getTypeName() ) )
309 {
310 for ( int j = 0; j < statElements.length; j++ )
311 {
312 if ( listSize.equals( statElements[j].getName() ) )
313 {
314 result = statElements[j].getData();
315 }
316 }
317 }
318
319 }
320 return Integer.parseInt( result );
321 }
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337 }