View Javadoc

1   package net.sf.ehcache.store;
2   
3   import net.sf.ehcache.Cache;
4   import net.sf.ehcache.CacheException;
5   import net.sf.ehcache.Ehcache;
6   import net.sf.ehcache.Element;
7   import net.sf.ehcache.config.CacheConfiguration;
8   import net.sf.ehcache.event.CacheEventListener;
9   import net.sf.ehcache.pool.Pool;
10  import net.sf.ehcache.pool.impl.ConstantSizeOfEngine;
11  import net.sf.ehcache.pool.impl.FromLargestCacheOnHeapPoolEvictor;
12  import net.sf.ehcache.pool.impl.StrictlyBoundedPool;
13  import org.junit.After;
14  import org.junit.Before;
15  import org.junit.Test;
16  
17  import java.util.concurrent.ConcurrentLinkedQueue;
18  import java.util.concurrent.ExecutorService;
19  import java.util.concurrent.Executors;
20  import java.util.concurrent.Future;
21  
22  import static org.junit.Assert.assertEquals;
23  import static org.junit.Assert.assertFalse;
24  import static org.junit.Assert.assertNotNull;
25  import static org.junit.Assert.assertNull;
26  import static org.junit.Assert.assertTrue;
27  import static org.junit.Assert.fail;
28  
29  /***
30   * @author Ludovic Orban
31   */
32  public class MemoryStorePoolingTest {
33  
34      private static final int ITERATIONS = 10000;
35      private volatile Cache cache;
36      private volatile Pool onHeapPool;
37      private volatile MemoryStore memoryStore;
38      private volatile Element lastEvicted;
39  
40      private void dump() {
41          System.out.println("# # # # # #");
42          System.out.println(memoryStore.getSize() + " elements in cache");
43          System.out.println("on heap: " + memoryStore.getKeys());
44          System.out.println("on heap size: " + onHeapPool.getSize());
45          System.out.println("# # # # # #");
46      }
47  
48      @Before
49      public void setUp() {
50          cache = new Cache(new CacheConfiguration("myCache1", 0).eternal(true));
51  
52          lastEvicted = null;
53          cache.getCacheEventNotificationService().registerListener(new CacheEventListener() {
54              public void notifyElementRemoved(Ehcache cache, Element element) throws CacheException { }
55  
56              public void notifyElementPut(Ehcache cache, Element element) throws CacheException { }
57  
58              public void notifyElementUpdated(Ehcache cache, Element element) throws CacheException { }
59  
60              public void notifyElementExpired(Ehcache cache, Element element) { }
61  
62              public void notifyElementEvicted(Ehcache cache, Element element) {
63                  lastEvicted = element;
64              }
65  
66              public void notifyRemoveAll(Ehcache cache) { }
67  
68              public void dispose() { }
69  
70              @Override
71              public Object clone() throws CloneNotSupportedException {
72                  return super.clone();
73              }
74          });
75  
76          onHeapPool = new StrictlyBoundedPool(
77                  16384 * 2, // == 2 elements
78                  new FromLargestCacheOnHeapPoolEvictor(),
79                  new ConstantSizeOfEngine(
80                          1536,  /* 1.5 KB*/
81                          14336, /* 14 KB */
82                          512    /* 0.5 KB */
83                  )
84          );
85  
86          memoryStore = MemoryStore.create(cache, onHeapPool);
87      }
88  
89      @After
90      public void tearDown() {
91          cache.dispose();
92          memoryStore.dispose();
93      }
94  
95  
96      @Test
97      public void testElementPinning() throws Exception {
98          Cache cache2 = new Cache(new CacheConfiguration("myCache2", 0).eternal(true));
99          MemoryStore memoryOnlyStore2 = MemoryStore.create(cache2, onHeapPool);
100 
101         for (int i = 0; i < 100; i++) {
102             memoryStore.put(new Element(i, i));
103         }
104 
105         assertEquals(0, memoryOnlyStore2.getSize());
106         assertEquals(0, memoryOnlyStore2.getInMemorySizeInBytes());
107         assertEquals(2, memoryStore.getSize());
108         assertEquals(16384 * 2, memoryStore.getInMemorySizeInBytes());
109 
110         for (int i = 0; i < 100; i++) {
111             Element element = new Element(i, i);
112             element.setTimeToIdle(1);
113             element.setTimeToLive(1);
114             element.setPinned(true);
115 
116             memoryOnlyStore2.put(element);
117         }
118 
119         assertEquals(0, memoryStore.getSize());
120         assertEquals(0, memoryStore.getInMemorySizeInBytes());
121         assertEquals(100, memoryOnlyStore2.getSize());
122         assertEquals(16384 * 100, memoryOnlyStore2.getInMemorySizeInBytes());
123 
124         // wait until the elements expired
125         Thread.sleep(1200);
126 
127         for (int i = 0; i < 100; i++) {
128             memoryStore.put(new Element(i, i));
129         }
130 
131         assertEquals(1, memoryOnlyStore2.getSize());
132         assertEquals(16384, memoryOnlyStore2.getInMemorySizeInBytes());
133         assertEquals(1, memoryStore.getSize());
134         assertEquals(16384, memoryStore.getInMemorySizeInBytes());
135         assertEquals(16384 * 2, onHeapPool.getSize());
136     }
137 
138     @Test
139     public void testPutNew() throws Exception {
140         for (int i = 0; i < ITERATIONS; i++) {
141             putNew();
142 
143             tearDown();
144             setUp();
145         }
146     }
147 
148     public void putNew() throws Exception {
149         // put 20 new elements in, making sure eviction is working
150         for (int i = 0; i < 20; i++) {
151             Element e = new Element(i, "" + i);
152             memoryStore.put(e);
153             assertTrue("#" + i, memoryStore.getInMemorySize() <= 2);
154         }
155 
156         assertEquals(2, memoryStore.getInMemorySize());
157         assertEquals(16384 * 2, onHeapPool.getSize());
158 
159         // get an on-heap element
160         Object key = memoryStore.getKeys().iterator().next();
161         memoryStore.get(key);
162 
163         assertEquals(2, memoryStore.getInMemorySize());
164         assertEquals(16384 * 2, onHeapPool.getSize());
165 
166         // put a new element on-heap
167         memoryStore.put(new Element(-1, "-1"));
168 
169         assertEquals(2, memoryStore.getInMemorySize());
170         assertEquals(16384 * 2, onHeapPool.getSize());
171     }
172 
173     @Test
174     public void testPutThenRemove() throws Exception {
175         for (int i = 0; i < ITERATIONS; i++) {
176             putThenRemove();
177 
178             tearDown();
179             setUp();
180         }
181     }
182 
183     public void putThenRemove() throws Exception {
184         for (int i = 0; i < 20; i++) {
185             memoryStore.put(new Element(i, "" + i));
186             assertTrue(memoryStore.getSize() <= 2);
187 
188             if (i % 2 == 1) {
189                 memoryStore.remove(i);
190             }
191             assertTrue(memoryStore.getSize() <= 2);
192         }
193 
194         assertTrue(memoryStore.getSize() >= 1);
195         assertTrue(memoryStore.getSize() <= 2);
196         assertTrue(onHeapPool.getSize() >= 16384);
197         assertTrue(onHeapPool.getSize() <= 16384 * 2);
198 
199         for (int i = 0; i < 20; i++) {
200             if (i % 2 == 0) {
201                 memoryStore.remove(i);
202             }
203         }
204 
205         assertEquals(0, memoryStore.getSize());
206         assertEquals(0, onHeapPool.getSize());
207     }
208 
209     @Test
210     public void testPutIfAbsentNew() throws Exception {
211         for (int i = 0; i < ITERATIONS; i++) {
212             putIfAbsentNew();
213 
214             tearDown();
215             setUp();
216         }
217     }
218 
219     public void putIfAbsentNew() throws Exception {
220         // put 20 new elements in, making sure eviction is working
221         for (int i = 0; i < 20; i++) {
222             Element e = new Element(i, "" + i);
223             assertNull(memoryStore.putIfAbsent(e));
224             assertTrue("#" + i, memoryStore.getInMemorySize() <= 2);
225         }
226 
227         assertEquals(2, memoryStore.getInMemorySize());
228         assertEquals(16384 * 2, onHeapPool.getSize());
229 
230         // get an on-heap element
231         Object key = memoryStore.getKeys().iterator().next();
232         memoryStore.get(key);
233 
234         assertEquals(2, memoryStore.getInMemorySize());
235         assertEquals(16384 * 2, onHeapPool.getSize());
236 
237 
238         // put a new element on-heap
239         assertNull(memoryStore.putIfAbsent(new Element(-1, "-1")));
240 
241         assertEquals(2, memoryStore.getInMemorySize());
242         assertEquals(16384 * 2, onHeapPool.getSize());
243     }
244 
245     @Test
246     public void testPutUpdate() throws Exception {
247         for (int i = 0; i < ITERATIONS; i++) {
248             putUpdate();
249 
250             tearDown();
251             setUp();
252         }
253     }
254 
255     public void putUpdate() throws Exception {
256         // warm up
257         memoryStore.put(new Element(1, "1"));
258         memoryStore.put(new Element(2, "2"));
259         memoryStore.put(new Element(3, "3"));
260 
261         assertEquals(2, memoryStore.getSize());
262         assertEquals(16384 * 2, onHeapPool.getSize());
263 
264         // update element in memory
265         Object key = memoryStore.getKeys().iterator().next();
266         memoryStore.put(new Element(key, key.toString()));
267 
268         // size can be 1 or 2, depending if the evicted element is the updated one or not
269         if (memoryStore.getSize() == 2) {
270             assertEquals(16384 * 2, onHeapPool.getSize());
271         } else if (memoryStore.getSize() == 1) {
272             assertEquals(16384, onHeapPool.getSize());
273         } else {
274             fail();
275         }
276     }
277 
278     @Test
279     public void testPutIfAbsentUpdate() throws Exception {
280         for (int i = 0; i < ITERATIONS; i++) {
281             putIfAbsentUpdate();
282 
283             tearDown();
284             setUp();
285         }
286     }
287 
288     public void putIfAbsentUpdate() throws Exception {
289         // warm up
290         Element element;
291         assertNull(memoryStore.putIfAbsent(new Element(1, "1#1")));
292         assertNotNull(memoryStore.putIfAbsent(new Element(1, "1#2")));
293         assertNull(memoryStore.putIfAbsent(new Element(2, "2#1")));
294         element = memoryStore.putIfAbsent(new Element(2, "2#2"));
295         if (lastEvicted.getObjectKey().equals(2)) {
296             assertNull(element);
297         } else {
298             assertNotNull(element);
299         }
300         assertNull(memoryStore.putIfAbsent(new Element(3, "3#1")));
301         element = memoryStore.putIfAbsent(new Element(3, "3#2"));
302         if (lastEvicted.getObjectKey().equals(3)) {
303             assertNull(element);
304             assertEquals(2, memoryStore.getSize());
305             assertEquals(16384 * 2, onHeapPool.getSize());
306         } else {
307             assertNotNull(element);
308             assertEquals(1, memoryStore.getSize());
309             assertEquals(16384, onHeapPool.getSize());
310         }
311 
312         Object key;
313 
314         // try to update element in memory
315         key = memoryStore.getKeys().iterator().next();
316         element = memoryStore.putIfAbsent(new Element(key, key.toString()));
317 
318         if (lastEvicted.getObjectKey().equals(key)) {
319             assertNull(element);
320             assertEquals(2, memoryStore.getSize());
321             assertEquals(16384 * 2, onHeapPool.getSize());
322         } else {
323             assertNotNull(element);
324             assertEquals(1, memoryStore.getSize());
325             assertEquals(16384, onHeapPool.getSize());
326         }
327     }
328 
329     @Test
330     public void testRemove() throws Exception {
331         for (int i = 0; i < ITERATIONS; i++) {
332             remove();
333 
334             tearDown();
335             setUp();
336         }
337     }
338 
339     public void remove() throws Exception {
340         // warm up
341         memoryStore.put(new Element(1, "1"));
342         memoryStore.put(new Element(2, "2"));
343         memoryStore.put(new Element(3, "3"));
344 
345         assertEquals(2, memoryStore.getSize());
346         assertEquals(16384 * 2, onHeapPool.getSize());
347 
348         // remove element on heap
349         Object key = memoryStore.getKeys().iterator().next();
350         memoryStore.remove(key);
351 
352         assertEquals(1, memoryStore.getSize());
353         assertEquals(16384, onHeapPool.getSize());
354     }
355 
356     @Test
357     public void testReplace1Arg() throws Exception {
358         for (int i = 0; i < ITERATIONS; i++) {
359             replace1Arg();
360 
361             tearDown();
362             setUp();
363         }
364     }
365 
366     public void replace1Arg() throws Exception {
367         // warm up
368         memoryStore.put(new Element(1, "1#1"));
369         memoryStore.put(new Element(2, "2#1"));
370         memoryStore.put(new Element(3, "3#1"));
371 
372         assertEquals(2, memoryStore.getSize());
373         assertEquals(16384 * 2, onHeapPool.getSize());
374 
375         // replace element on heap
376         Object key = memoryStore.getKeys().iterator().next();
377         Element element = memoryStore.replace(new Element(key, key + "#2"));
378 
379         if (lastEvicted.getObjectKey().equals(key)) {
380             assertNull(element);
381         } else {
382             assertEquals(new Element(key, key + "#1"), element);
383         }
384         assertEquals(1, memoryStore.getSize());
385         assertEquals(16384, onHeapPool.getSize());
386 
387         // replace non-existent key
388         assertNull(memoryStore.replace(new Element(-1, -1 + "#2")));
389 
390         assertEquals(1, memoryStore.getSize());
391         assertEquals(16384, onHeapPool.getSize());
392     }
393 
394     @Test
395     public void testReplace3Args() throws Exception {
396         for (int i = 0; i < ITERATIONS; i++) {
397             replace3Arg();
398 
399             tearDown();
400             setUp();
401         }
402     }
403 
404     public void replace3Arg() throws Exception {
405         // warm up
406         memoryStore.put(new Element(1, "1#1"));
407         memoryStore.put(new Element(2, "2#1"));
408         memoryStore.put(new Element(3, "3#1"));
409 
410         assertEquals(2, memoryStore.getSize());
411         assertEquals(16384 * 2, onHeapPool.getSize());
412 
413         // replace element on heap
414         Object key = memoryStore.getKeys().iterator().next();
415         boolean replaced = memoryStore.replace(new Element(key, key + "#1"), new Element(key, key + "#2"), new DefaultElementValueComparator());
416 
417         if (lastEvicted.getObjectKey().equals(key)) {
418             assertFalse(replaced);
419         } else {
420             assertTrue(replaced);
421         }
422         assertEquals(1, memoryStore.getSize());
423         assertEquals(16384, onHeapPool.getSize());
424 
425         memoryStore.put(new Element(4, "4#1"));
426 
427         // replace non-existent key
428         assertFalse(memoryStore.replace(new Element(-1, -1 + "#2"), new Element(-1, -1 + "#2"), new DefaultElementValueComparator()));
429 
430         assertEquals(1, memoryStore.getSize());
431         assertEquals(16384, onHeapPool.getSize());
432     }
433 
434     @Test
435     public void testRemoveElement() throws Exception {
436         for (int i = 0; i < ITERATIONS; i++) {
437             removeElement();
438 
439             tearDown();
440             setUp();
441         }
442     }
443 
444     public void removeElement() throws Exception {
445         // warm up
446         memoryStore.put(new Element(1, "1"));
447         memoryStore.put(new Element(2, "2"));
448         memoryStore.put(new Element(3, "3"));
449 
450         assertEquals(2, memoryStore.getSize());
451         assertEquals(16384 * 2, onHeapPool.getSize());
452 
453         // remove non-existent element
454         assertNull(memoryStore.removeElement(new Element(-1, -1 + ""), new DefaultElementValueComparator()));
455 
456         assertEquals(2, memoryStore.getSize());
457         assertEquals(16384 * 2, onHeapPool.getSize());
458 
459         // remove element on heap
460         Object key = memoryStore.getKeys().iterator().next();
461         assertEquals(new Element(key, key + ""), memoryStore.removeElement(new Element(key, key + ""), new DefaultElementValueComparator()));
462 
463         assertEquals(1, memoryStore.getSize());
464         assertEquals(16384, onHeapPool.getSize());
465     }
466 
467     @Test
468     public void testRemoveAll() throws Exception {
469         for (int i = 0; i < ITERATIONS; i++) {
470             removeAll();
471 
472             tearDown();
473             setUp();
474         }
475     }
476 
477     public void removeAll() throws Exception {
478         // warm up
479         memoryStore.put(new Element(1, "1"));
480         memoryStore.put(new Element(2, "2"));
481         memoryStore.put(new Element(3, "3"));
482 
483         assertEquals(2, memoryStore.getSize());
484         assertEquals(16384 * 2, onHeapPool.getSize());
485 
486         memoryStore.removeAll();
487 
488         assertEquals(0, memoryStore.getSize());
489         assertEquals(0, onHeapPool.getSize());
490     }
491 
492     @Test
493     public void testMultithreaded() throws Exception {
494         final int nThreads = 1;
495 
496         final ExecutorService executor = Executors.newFixedThreadPool(nThreads);
497         final ConcurrentLinkedQueue<Future<?>> queue = new ConcurrentLinkedQueue<Future<?>>();
498 
499         for (int i = 0; i < nThreads; i++) {
500             Future<?> f = executor.submit(new Runnable() {
501                 public void run() {
502                     for (int i = 0; i < 100000; i++) {
503                         Element e = new Element(i, "" + i);
504                         memoryStore.put(e);
505 
506                         memoryStore.replace(new Element(i, "2#" + i));
507 
508                         Thread.yield();
509                     }
510                 }
511             });
512             queue.add(f);
513         }
514 
515         while (!queue.isEmpty()) {
516             Future<?> f = queue.poll();
517             f.get();
518         }
519 
520         assertEquals(16384, onHeapPool.getSize());
521         assertEquals(1, memoryStore.getSize());
522     }
523 
524 }