blob: ac648f19de1ec360d460f4f940e70245e87a9066 [file] [log] [blame]
package org.apache.directmemory.ehcache;
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
import net.sf.ehcache.CacheEntry;
import net.sf.ehcache.CacheException;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
import net.sf.ehcache.Status;
import net.sf.ehcache.pool.Pool;
import net.sf.ehcache.pool.PoolableStore;
import net.sf.ehcache.store.AbstractStore;
import net.sf.ehcache.store.ElementValueComparator;
import net.sf.ehcache.store.Policy;
import net.sf.ehcache.store.TierableStore;
import net.sf.ehcache.store.disk.StoreUpdateException;
import net.sf.ehcache.writer.CacheWriterManager;
import org.apache.directmemory.cache.CacheServiceImpl;
import org.apache.directmemory.measures.Ram;
import org.apache.directmemory.memory.Pointer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.BufferOverflowException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import static java.lang.String.format;
public class DirectMemoryStore
extends AbstractStore
implements TierableStore, PoolableStore
{
private static Logger logger = LoggerFactory.getLogger( CacheServiceImpl.class );
public static final int DEFAULT_NUMBER_BYTE_BUFFERS = 64;
public static final int DEFAULT_BUFFER_SIZE = Ram.Mb( 40 );
private List<ReentrantLock> bufferLocks;
DirectMemoryCache<Object, Element> directMemoryCache;
public DirectMemoryStore( Ehcache cache, Pool<PoolableStore> offHeapPool )
{
this( cache, offHeapPool, false );
}
public DirectMemoryStore( Ehcache cache, Pool<PoolableStore> offHeapPool, boolean doNotifications )
{
long offHeapSizeBytes;
if ( cache == null || cache.getCacheConfiguration() == null )
{
offHeapSizeBytes = Ram.Mb( 64 );
}
else
{
offHeapSizeBytes = cache.getCacheConfiguration().getMaxMemoryOffHeapInBytes();
}
init( offHeapSizeBytes );
}
public DirectMemoryStore( long offHeapSizeBytes )
{
init( offHeapSizeBytes );
}
private void init( long offHeapSizeBytes )
{
logger.info( " ___ __ __ _ _ ____ _ " );
logger.info( " / _ \\ / _|/ _| | | | ___ __ _ _ __/ ___|| |_ ___ _ __ ___ " );
logger.info( " | | | | |_| |_| |_| |/ _ \\/ _` | '_ \\___ \\| __/ _ \\| '__/ _ \\" );
logger.info( " | |_| | _| _| _ | __/ (_| | |_) |__) | || (_) | | | __/" );
logger.info( " \\___/|_| |_| |_| |_|\\___|\\__,_| .__/____/ \\__\\___/|_| \\___|" );
logger.info( " |_| " );
logger.info( "default buffer size = " + DEFAULT_BUFFER_SIZE );
logger.info( "off heap size = " + offHeapSizeBytes );
int numberOfBuffers = (int) ( offHeapSizeBytes / DEFAULT_BUFFER_SIZE );
// numberOfBuffers = DEFAULT_NUMBER_BYTE_BUFFERS;
logger.info( "no of buffers = " + numberOfBuffers );
this.bufferLocks = new ArrayList<ReentrantLock>( numberOfBuffers );
for ( int i = 0; i < numberOfBuffers; i++ )
{
this.bufferLocks.add( new ReentrantLock() );
}
directMemoryCache =
new DirectMemoryCache<Object, Element>( numberOfBuffers, (int) ( offHeapSizeBytes / numberOfBuffers ) );
}
@Override
public void unpinAll()
{
//no operation
}
@Override
public boolean isPinned( Object key )
{
return false;
}
@Override
public void setPinned( Object key, boolean pinned )
{
//no operation
}
@Override
public boolean put( Element element )
throws CacheException
{
Pointer<Element> pointer = null;
try
{
pointer = directMemoryCache.put( element.getObjectKey(), element );
}
catch ( BufferOverflowException boe )
{
dump();
throw new CacheException( "DirectMemory OffHeap Memory Exceeded", boe );
}
return null == pointer ? false : true;
}
@Override
public boolean putWithWriter( Element element, CacheWriterManager writerManager )
throws CacheException
{
boolean newPut = put( element );
if ( writerManager != null )
{
try
{
writerManager.put( element );
}
catch ( RuntimeException e )
{
throw new StoreUpdateException( e, !newPut );
}
}
return newPut;
}
@Override
public Element get( Object key )
{
return directMemoryCache.retrieve( key );
}
@Override
public Element getQuiet( Object key )
{
return get( key );
}
@Override
public List<Object> getKeys()
{
return new ArrayList<Object>( directMemoryCache.getKeys() );
}
@Override
public Element remove( Object key )
{
Element element = get( key );
directMemoryCache.free( key );
return element;
}
@Override
public Element removeWithWriter( Object key, CacheWriterManager writerManager )
throws CacheException
{
Element removed = remove( key );
if ( writerManager != null )
{
writerManager.remove( new CacheEntry( key, removed ) );
}
return removed;
}
@Override
public void removeAll()
throws CacheException
{
directMemoryCache.clear();
}
@Override
public Element putIfAbsent( Element element )
throws NullPointerException
{
Element returnElement = get( element.getObjectKey() );
if ( null == returnElement )
{
put( element );
returnElement = element;
}
return returnElement;
}
@Override
public Element removeElement( Element element, ElementValueComparator comparator )
throws NullPointerException
{
if ( element == null || element.getObjectKey() == null )
{
return null;
}
Pointer<Element> pointer = directMemoryCache.getPointer( element.getObjectKey() );
if ( pointer == null )
{
return null;
}
Lock lock = bufferLocks.get( pointer.getBufferNumber() );
lock.lock();
try
{
Element toRemove = directMemoryCache.retrieve( element.getObjectKey() );
if ( comparator.equals( element, toRemove ) )
{
directMemoryCache.free( element.getObjectKey() );
return toRemove;
}
else
{
return null;
}
}
finally
{
lock.unlock();
}
}
@Override
public boolean replace( Element old, Element element, ElementValueComparator comparator )
throws NullPointerException, IllegalArgumentException
{
if ( element == null || element.getObjectKey() == null )
{
return false;
}
Pointer<Element> pointer = directMemoryCache.getPointer( element.getObjectKey() );
if ( pointer == null )
{
return false;
}
Lock lock = bufferLocks.get( pointer.getBufferNumber() );
lock.lock();
try
{
Element toUpdate = directMemoryCache.retrieve( element.getObjectKey() );
if ( comparator.equals( old, toUpdate ) )
{
directMemoryCache.put( element.getObjectKey(), element );
return true;
}
else
{
return false;
}
}
catch ( BufferOverflowException boe )
{
dump();
throw new CacheException( "DirectMemory OffHeap Memory Exceeded", boe );
}
finally
{
lock.unlock();
}
}
@Override
public Element replace( Element element )
throws NullPointerException
{
if ( element == null || element.getObjectKey() == null )
{
return null;
}
Pointer<Element> pointer = directMemoryCache.getPointer( element.getObjectKey() );
if ( pointer == null )
{
return null;
}
Lock lock = bufferLocks.get( pointer.getBufferNumber() );
lock.lock();
try
{
Element toUpdate = directMemoryCache.retrieve( element.getObjectKey() );
if ( null != toUpdate )
{
directMemoryCache.put( element.getObjectKey(), element );
return toUpdate;
}
else
{
return null;
}
}
catch ( BufferOverflowException boe )
{
dump();
throw new CacheException( "DirectMemory OffHeap Memory Exceeded", boe );
}
finally
{
lock.unlock();
}
}
@Override
public synchronized void dispose()
{
flush();
}
@Override
public int getSize()
{
return getOffHeapSize();
}
@Override
public int getInMemorySize()
{
//no operation
return 0;
}
@Override
public int getOffHeapSize()
{
long size = directMemoryCache.size();
if ( size > Integer.MAX_VALUE )
{
return Integer.MAX_VALUE;
}
else
{
return (int) size;
}
}
@Override
public int getOnDiskSize()
{
//no operation
return 0;
}
@Override
public int getTerracottaClusteredSize()
{
//no operation
return 0;
}
@Override
public long getInMemorySizeInBytes()
{
//no operation
return 0;
}
@Override
public long getOffHeapSizeInBytes()
{
return directMemoryCache.sizeInBytes();
}
@Override
public long getOnDiskSizeInBytes()
{
//no operation
return 0;
}
@Override
public Status getStatus()
{
//no operation
return null;
}
@Override
public boolean containsKey( Object key )
{
return containsKeyOffHeap( key );
}
@Override
public boolean containsKeyOnDisk( Object key )
{
//no operation
return false;
}
@Override
public boolean containsKeyOffHeap( Object key )
{
return directMemoryCache.containsKey( key );
}
@Override
public boolean containsKeyInMemory( Object key )
{
//no operation
return false;
}
@Override
public void expireElements()
{
//no operation
}
@Override
public void flush()
{
directMemoryCache.clear();
}
@Override
public boolean bufferFull()
{
//never backs up/ no buffer used.
return false;
}
@Override
public Policy getInMemoryEvictionPolicy()
{
//no operation
return null;
}
@Override
public void setInMemoryEvictionPolicy( Policy policy )
{
//no operation
}
@Override
public Object getInternalContext()
{
//no operation
return null;
}
@Override
public Object getMBean()
{
//no operation
return null;
}
@Override
public boolean evictFromOnHeap( int count, long size )
{
//no operation
return false;
}
@Override
public boolean evictFromOnDisk( int count, long size )
{
//no operation
return false;
}
@Override
public float getApproximateDiskHitRate()
{
//no operation
return 0;
}
@Override
public float getApproximateDiskMissRate()
{
//no operation
return 0;
}
@Override
public long getApproximateDiskCountSize()
{
//no operation
return 0;
}
@Override
public long getApproximateDiskByteSize()
{
//no operation
return 0;
}
@Override
public float getApproximateHeapHitRate()
{
//no operation
return 0;
}
@Override
public float getApproximateHeapMissRate()
{
//no operation
return 0;
}
@Override
public long getApproximateHeapCountSize()
{
//no operation
return 0;
}
@Override
public long getApproximateHeapByteSize()
{
//no operation
return 0;
}
@Override
public void fill( Element e )
{
put( e );
}
@Override
public boolean removeIfTierNotPinned( Object key )
{
//no operation
return false;
}
@Override
public void removeNoReturn( Object key )
{
//no operation
}
public void dump()
{
directMemoryCache.dump();
}
public void dumpTotal()
{
long capacity = directMemoryCache.getMemoryManager().capacity();
long used = directMemoryCache.getMemoryManager().used();
logger.info( "***Totals***************************************" );
logger.info( format( "off-heap - allocated: \t%1s", Ram.inMb( capacity ) ) );
logger.info( format( "off-heap - used: \t%1s", Ram.inMb( used ) ) );
logger.info( format( "heap - max: \t%1s", Ram.inMb( Runtime.getRuntime().maxMemory() ) ) );
logger.info( format( "heap - allocated: \t%1s", Ram.inMb( Runtime.getRuntime().totalMemory() ) ) );
logger.info( format( "heap - free : \t%1s", Ram.inMb( Runtime.getRuntime().freeMemory() ) ) );
logger.info( "************************************************" );
}
}