View Javadoc

1   package org.apache.directmemory.ehcache;
2   
3   /*
4    * Licensed to the Apache Software Foundation (ASF) under one
5    * or more contributor license agreements.  See the NOTICE file
6    * distributed with this work for additional information
7    * regarding copyright ownership.  The ASF licenses this file
8    * to you under the Apache License, Version 2.0 (the
9    * "License"); you may not use this file except in compliance
10   * with the License.  You may obtain a copy of the License at
11   *
12   *  http://www.apache.org/licenses/LICENSE-2.0
13   *
14   * Unless required by applicable law or agreed to in writing,
15   * software distributed under the License is distributed on an
16   * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17   * KIND, either express or implied.  See the License for the
18   * specific language governing permissions and limitations
19   * under the License.
20   */
21  
22  import net.sf.ehcache.CacheEntry;
23  import net.sf.ehcache.CacheException;
24  import net.sf.ehcache.Ehcache;
25  import net.sf.ehcache.Element;
26  import net.sf.ehcache.Status;
27  import net.sf.ehcache.pool.Pool;
28  import net.sf.ehcache.pool.PoolableStore;
29  import net.sf.ehcache.store.AbstractStore;
30  import net.sf.ehcache.store.ElementValueComparator;
31  import net.sf.ehcache.store.Policy;
32  import net.sf.ehcache.store.TierableStore;
33  import net.sf.ehcache.store.disk.StoreUpdateException;
34  import net.sf.ehcache.writer.CacheWriterManager;
35  import org.apache.directmemory.cache.CacheServiceImpl;
36  import org.apache.directmemory.measures.Ram;
37  import org.apache.directmemory.memory.Pointer;
38  import org.slf4j.Logger;
39  import org.slf4j.LoggerFactory;
40  
41  import java.nio.BufferOverflowException;
42  import java.util.ArrayList;
43  import java.util.Collections;
44  import java.util.List;
45  import java.util.Set;
46  import java.util.concurrent.locks.Lock;
47  import java.util.concurrent.locks.ReentrantLock;
48  
49  import static java.lang.String.format;
50  
51  public class DirectMemoryStore
52      extends AbstractStore
53      implements TierableStore, PoolableStore
54  {
55  
56      private static Logger logger = LoggerFactory.getLogger( CacheServiceImpl.class );
57  
58      public static final int DEFAULT_NUMBER_BYTE_BUFFERS = 64;
59  
60      public static final int DEFAULT_BUFFER_SIZE = Ram.Mb( 40 );
61  
62      private List<ReentrantLock> bufferLocks;
63  
64      DirectMemoryCache<Object, Element> directMemoryCache;
65  
66      public DirectMemoryStore( Ehcache cache, Pool<PoolableStore> offHeapPool )
67      {
68          this( cache, offHeapPool, false );
69      }
70  
71      public DirectMemoryStore( Ehcache cache, Pool<PoolableStore> offHeapPool, boolean doNotifications )
72      {
73          long offHeapSizeBytes;
74          if ( cache == null || cache.getCacheConfiguration() == null )
75          {
76              offHeapSizeBytes = Ram.Mb( 64 );
77          }
78          else
79          {
80              offHeapSizeBytes = cache.getCacheConfiguration().getMaxMemoryOffHeapInBytes();
81          }
82          init( offHeapSizeBytes );
83      }
84  
85      public DirectMemoryStore( long offHeapSizeBytes )
86      {
87          init( offHeapSizeBytes );
88      }
89  
90      private void init( long offHeapSizeBytes )
91      {
92          logger.info( "	  ___   __  __ _   _                 ____  _                 " );
93          logger.info( "	 / _ \\ / _|/ _| | | | ___  __ _ _ __/ ___|| |_ ___  _ __ ___ " );
94          logger.info( "	| | | | |_| |_| |_| |/ _ \\/ _` | '_ \\___ \\| __/ _ \\| '__/ _ \\" );
95          logger.info( "	| |_| |  _|  _|  _  |  __/ (_| | |_) |__) | || (_) | | |  __/" );
96          logger.info( "	 \\___/|_| |_| |_| |_|\\___|\\__,_| .__/____/ \\__\\___/|_|  \\___|" );
97          logger.info( "	                               |_|                           " );
98  
99          logger.info( "default buffer size = " + DEFAULT_BUFFER_SIZE );
100         logger.info( "off heap size = " + offHeapSizeBytes );
101         int numberOfBuffers = (int) ( offHeapSizeBytes / DEFAULT_BUFFER_SIZE );
102 //        numberOfBuffers = DEFAULT_NUMBER_BYTE_BUFFERS;
103         logger.info( "no of buffers = " + numberOfBuffers );
104 
105         this.bufferLocks = new ArrayList<ReentrantLock>( numberOfBuffers );
106         for ( int i = 0; i < numberOfBuffers; i++ )
107         {
108             this.bufferLocks.add( new ReentrantLock() );
109         }
110 
111         directMemoryCache =
112             new DirectMemoryCache<Object, Element>( numberOfBuffers, (int) ( offHeapSizeBytes / numberOfBuffers ) );
113         
114     }
115 
116     @Override
117     public void unpinAll()
118     {
119         //no operation
120 
121     }
122 
123     @Override
124     public boolean isPinned( Object key )
125     {
126         return false;
127     }
128 
129     @Override
130     public void setPinned( Object key, boolean pinned )
131     {
132         //no operation
133 
134     }
135 
136     @Override
137     public boolean put( Element element )
138         throws CacheException
139     {
140         Pointer<Element> pointer = null;
141         try
142         {
143             pointer = directMemoryCache.put( element.getObjectKey(), element );
144         }
145         catch ( BufferOverflowException boe )
146         {
147             dump();
148             throw new CacheException( "DirectMemory OffHeap Memory Exceeded", boe );
149         }
150         return null == pointer ? false : true;
151     }
152 
153     @Override
154     public boolean putWithWriter( Element element, CacheWriterManager writerManager )
155         throws CacheException
156     {
157         boolean newPut = put( element );
158         if ( writerManager != null )
159         {
160             try
161             {
162                 writerManager.put( element );
163             }
164             catch ( RuntimeException e )
165             {
166                 throw new StoreUpdateException( e, !newPut );
167             }
168         }
169         return newPut;
170     }
171 
172     @Override
173     public Element get( Object key )
174     {
175         return directMemoryCache.retrieve( key );
176     }
177 
178     @Override
179     public Element getQuiet( Object key )
180     {
181         return get( key );
182     }
183 
184     @Override
185     public List<Object> getKeys()
186     {
187         return new ArrayList<Object>( directMemoryCache.getKeys() );
188     }
189 
190     @Override
191     public Element remove( Object key )
192     {
193         Element element = get( key );
194         directMemoryCache.free( key );
195         return element;
196 
197     }
198 
199     @Override
200     public Element removeWithWriter( Object key, CacheWriterManager writerManager )
201         throws CacheException
202     {
203         Element removed = remove( key );
204         if ( writerManager != null )
205         {
206             writerManager.remove( new CacheEntry( key, removed ) );
207         }
208         return removed;
209     }
210 
211     @Override
212     public void removeAll()
213         throws CacheException
214     {
215         directMemoryCache.clear();
216     }
217 
218     @Override
219     public Element putIfAbsent( Element element )
220         throws NullPointerException
221     {
222         Element returnElement = get( element.getObjectKey() );
223         if ( null == returnElement )
224         {
225             put( element );
226             returnElement = element;
227         }
228         return returnElement;
229     }
230 
231     @Override
232     public Element removeElement( Element element, ElementValueComparator comparator )
233         throws NullPointerException
234     {
235         if ( element == null || element.getObjectKey() == null )
236         {
237             return null;
238         }
239         Pointer<Element> pointer = directMemoryCache.getPointer( element.getObjectKey() );
240         if ( pointer == null )
241         {
242             return null;
243         }
244 
245         Lock lock = bufferLocks.get( pointer.getBufferNumber() );
246         lock.lock();
247         try
248         {
249             Element toRemove = directMemoryCache.retrieve( element.getObjectKey() );
250             if ( comparator.equals( element, toRemove ) )
251             {
252                 directMemoryCache.free( element.getObjectKey() );
253                 return toRemove;
254             }
255             else
256             {
257                 return null;
258             }
259         }
260         finally
261         {
262             lock.unlock();
263         }
264     }
265 
266     @Override
267     public boolean replace( Element old, Element element, ElementValueComparator comparator )
268         throws NullPointerException, IllegalArgumentException
269     {
270         if ( element == null || element.getObjectKey() == null )
271         {
272             return false;
273         }
274         Pointer<Element> pointer = directMemoryCache.getPointer( element.getObjectKey() );
275         if ( pointer == null )
276         {
277             return false;
278         }
279 
280         Lock lock = bufferLocks.get( pointer.getBufferNumber() );
281         lock.lock();
282         try
283         {
284             Element toUpdate = directMemoryCache.retrieve( element.getObjectKey() );
285             if ( comparator.equals( old, toUpdate ) )
286             {
287                 directMemoryCache.put( element.getObjectKey(), element );
288                 return true;
289             }
290             else
291             {
292                 return false;
293             }
294         }
295         catch ( BufferOverflowException boe )
296         {
297             dump();
298             throw new CacheException( "DirectMemory OffHeap Memory Exceeded", boe );
299         }
300         finally
301         {
302             lock.unlock();
303         }
304     }
305 
306     @Override
307     public Element replace( Element element )
308         throws NullPointerException
309     {
310         if ( element == null || element.getObjectKey() == null )
311         {
312             return null;
313         }
314         Pointer<Element> pointer = directMemoryCache.getPointer( element.getObjectKey() );
315         if ( pointer == null )
316         {
317             return null;
318         }
319 
320         Lock lock = bufferLocks.get( pointer.getBufferNumber() );
321         lock.lock();
322         try
323         {
324             Element toUpdate = directMemoryCache.retrieve( element.getObjectKey() );
325             if ( null != toUpdate )
326             {
327                 directMemoryCache.put( element.getObjectKey(), element );
328                 return toUpdate;
329             }
330             else
331             {
332                 return null;
333             }
334         }
335         catch ( BufferOverflowException boe )
336         {
337             dump();
338             throw new CacheException( "DirectMemory OffHeap Memory Exceeded", boe );
339         }
340         finally
341         {
342             lock.unlock();
343         }
344     }
345 
346     @Override
347     public synchronized void dispose()
348     {
349         flush();
350     }
351 
352     @Override
353     public int getSize()
354     {
355         return getOffHeapSize();
356     }
357 
358     @Override
359     public int getInMemorySize()
360     {
361         //no operation
362         return 0;
363     }
364 
365     @Override
366     public int getOffHeapSize()
367     {
368         long size = directMemoryCache.size();
369         if ( size > Integer.MAX_VALUE )
370         {
371             return Integer.MAX_VALUE;
372         }
373         else
374         {
375             return (int) size;
376         }
377     }
378 
379     @Override
380     public int getOnDiskSize()
381     {
382         //no operation
383         return 0;
384     }
385 
386     @Override
387     public int getTerracottaClusteredSize()
388     {
389         //no operation
390         return 0;
391     }
392 
393     @Override
394     public long getInMemorySizeInBytes()
395     {
396         //no operation
397         return 0;
398     }
399 
400     @Override
401     public long getOffHeapSizeInBytes()
402     {
403         return directMemoryCache.sizeInBytes();
404     }
405 
406     @Override
407     public long getOnDiskSizeInBytes()
408     {
409         //no operation
410         return 0;
411     }
412 
413     @Override
414     public Status getStatus()
415     {
416         //no operation
417         return null;
418     }
419 
420     @Override
421     public boolean containsKey( Object key )
422     {
423         return containsKeyOffHeap( key );
424     }
425 
426     @Override
427     public boolean containsKeyOnDisk( Object key )
428     {
429         //no operation
430         return false;
431     }
432 
433     @Override
434     public boolean containsKeyOffHeap( Object key )
435     {
436         return directMemoryCache.containsKey( key );
437     }
438 
439     @Override
440     public boolean containsKeyInMemory( Object key )
441     {
442         //no operation
443         return false;
444     }
445 
446     @Override
447     public void expireElements()
448     {
449         //no operation
450 
451     }
452 
453     @Override
454     public void flush()
455     {
456         directMemoryCache.clear();
457     }
458 
459     @Override
460     public boolean bufferFull()
461     {
462         //never backs up/ no buffer used.
463         return false;
464     }
465 
466     @Override
467     public Policy getInMemoryEvictionPolicy()
468     {
469         //no operation
470         return null;
471     }
472 
473     @Override
474     public void setInMemoryEvictionPolicy( Policy policy )
475     {
476         //no operation
477 
478     }
479 
480     @Override
481     public Object getInternalContext()
482     {
483         //no operation
484         return null;
485     }
486 
487     @Override
488     public Object getMBean()
489     {
490         //no operation
491         return null;
492     }
493 
494     @Override
495     public boolean evictFromOnHeap( int count, long size )
496     {
497         //no operation
498         return false;
499     }
500 
501     @Override
502     public boolean evictFromOnDisk( int count, long size )
503     {
504         //no operation
505         return false;
506     }
507 
508     @Override
509     public float getApproximateDiskHitRate()
510     {
511         //no operation
512         return 0;
513     }
514 
515     @Override
516     public float getApproximateDiskMissRate()
517     {
518         //no operation
519         return 0;
520     }
521 
522     @Override
523     public long getApproximateDiskCountSize()
524     {
525         //no operation
526         return 0;
527     }
528 
529     @Override
530     public long getApproximateDiskByteSize()
531     {
532         //no operation
533         return 0;
534     }
535 
536     @Override
537     public float getApproximateHeapHitRate()
538     {
539         //no operation
540         return 0;
541     }
542 
543     @Override
544     public float getApproximateHeapMissRate()
545     {
546         //no operation
547         return 0;
548     }
549 
550     @Override
551     public long getApproximateHeapCountSize()
552     {
553         //no operation
554         return 0;
555     }
556 
557     @Override
558     public long getApproximateHeapByteSize()
559     {
560         //no operation
561         return 0;
562     }
563 
564     @Override
565     public void fill( Element e )
566     {
567         put( e );
568     }
569 
570     @Override
571     public boolean removeIfNotPinned( Object key )
572     {
573         return false;
574     }
575 
576     @Override
577     public boolean isTierPinned()
578     {
579         return false;
580     }
581 
582     @Override
583     public Set getPresentPinnedKeys()
584     {
585         return Collections.emptySet();
586     }
587 
588     @Override
589     public boolean isPersistent()
590     {
591         return false;
592     }
593 
594 
595 
596     @Override
597     public void removeNoReturn( Object key )
598     {
599         //no operation
600 
601     }
602 
603     public void dump()
604     {
605         directMemoryCache.dump();
606     }
607 
608     public void dumpTotal()
609     {
610         long capacity = directMemoryCache.getMemoryManager().capacity();
611         long used = directMemoryCache.getMemoryManager().used();
612         
613         logger.info( "***Totals***************************************" );
614         logger.info( format( "off-heap - allocated: \t%1s", Ram.inMb( capacity ) ) );
615         logger.info( format( "off-heap - used:      \t%1s", Ram.inMb( used ) ) );
616         logger.info( format( "heap     - max: \t%1s", Ram.inMb( Runtime.getRuntime().maxMemory() ) ) );
617         logger.info( format( "heap     - allocated: \t%1s", Ram.inMb( Runtime.getRuntime().totalMemory() ) ) );
618         logger.info( format( "heap     - free : \t%1s", Ram.inMb( Runtime.getRuntime().freeMemory() ) ) );
619         logger.info( "************************************************" );
620     }
621 }