1 package org.apache.directmemory.ehcache;
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
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
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
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
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
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
383 return 0;
384 }
385
386 @Override
387 public int getTerracottaClusteredSize()
388 {
389
390 return 0;
391 }
392
393 @Override
394 public long getInMemorySizeInBytes()
395 {
396
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
410 return 0;
411 }
412
413 @Override
414 public Status getStatus()
415 {
416
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
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
443 return false;
444 }
445
446 @Override
447 public void expireElements()
448 {
449
450
451 }
452
453 @Override
454 public void flush()
455 {
456 directMemoryCache.clear();
457 }
458
459 @Override
460 public boolean bufferFull()
461 {
462
463 return false;
464 }
465
466 @Override
467 public Policy getInMemoryEvictionPolicy()
468 {
469
470 return null;
471 }
472
473 @Override
474 public void setInMemoryEvictionPolicy( Policy policy )
475 {
476
477
478 }
479
480 @Override
481 public Object getInternalContext()
482 {
483
484 return null;
485 }
486
487 @Override
488 public Object getMBean()
489 {
490
491 return null;
492 }
493
494 @Override
495 public boolean evictFromOnHeap( int count, long size )
496 {
497
498 return false;
499 }
500
501 @Override
502 public boolean evictFromOnDisk( int count, long size )
503 {
504
505 return false;
506 }
507
508 @Override
509 public float getApproximateDiskHitRate()
510 {
511
512 return 0;
513 }
514
515 @Override
516 public float getApproximateDiskMissRate()
517 {
518
519 return 0;
520 }
521
522 @Override
523 public long getApproximateDiskCountSize()
524 {
525
526 return 0;
527 }
528
529 @Override
530 public long getApproximateDiskByteSize()
531 {
532
533 return 0;
534 }
535
536 @Override
537 public float getApproximateHeapHitRate()
538 {
539
540 return 0;
541 }
542
543 @Override
544 public float getApproximateHeapMissRate()
545 {
546
547 return 0;
548 }
549
550 @Override
551 public long getApproximateHeapCountSize()
552 {
553
554 return 0;
555 }
556
557 @Override
558 public long getApproximateHeapByteSize()
559 {
560
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
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 }