/**
* Copyright (c) 2002-2012 "Neo Technology,"
* Network Engine for Objects in Lund AB [http://neotechnology.com]
*
* This file is part of Neo4j.
*
* Neo4j is free software: you can redistribute it and/or modify
* it under the terms of the GNU Affero General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.kernel.impl.cache;
import static org.neo4j.graphdb.factory.GraphDatabaseSetting.FloatSetting;
import static org.neo4j.graphdb.factory.GraphDatabaseSetting.NumberOfBytesSetting;
import static org.neo4j.graphdb.factory.GraphDatabaseSetting.TimeSpanSetting;
import org.neo4j.graphdb.factory.Default;
import org.neo4j.graphdb.factory.GraphDatabaseSetting;
import org.neo4j.helpers.Service;
import org.neo4j.kernel.configuration.Config;
import org.neo4j.kernel.impl.core.NodeImpl;
import org.neo4j.kernel.impl.core.RelationshipImpl;
import org.neo4j.kernel.impl.util.StringLogger;
@Service.Implementation( CacheProvider.class )
public class GCResistantCacheProvider extends CacheProvider
{
public static final String NAME = "gcr";
public static class Configuration
{
public static GraphDatabaseSetting<Long> node_cache_size = new GCRMemoryUsageSetting("node_cache_size");
public static GraphDatabaseSetting<Long> relationship_cache_size = new GCRMemoryUsageSetting("relationship_cache_size");
@Default( "1.0" )
public static GraphDatabaseSetting<Float> node_cache_array_fraction = new FloatSetting( "node_cache_array_fraction", "Must be a valid floating point number.", 1.0f, 10.0f );
@Default( "1.0" )
public static GraphDatabaseSetting<Float> relationship_cache_array_fraction = new FloatSetting( "relationship_cache_array_fraction", "Must be a valid floating point number.", 1.0f, 10.0f );
@Default( "60s" )
public static GraphDatabaseSetting<Long> log_interval = new TimeSpanSetting( "gcr_cache_min_log_interval" );
private static final class GCRMemoryUsageSetting extends NumberOfBytesSetting implements org.neo4j.graphdb.factory.GraphDatabaseSetting.DefaultValue
{
public GCRMemoryUsageSetting(String name) {
super(name);
}
@Override
public String getDefaultValue() {
long available = Runtime.getRuntime().maxMemory();
long defaultMem = ( available / 4);
return ""+defaultMem;
}
}
}
public GCResistantCacheProvider()
{
super( NAME, "GC resistant cache" );
}
@Override
public Cache<NodeImpl> newNodeCache( StringLogger logger, Config config )
{
long node = config.get( Configuration.node_cache_size );
long rel = config.get( Configuration.relationship_cache_size );
checkMemToUse( logger, node, rel, Runtime.getRuntime().maxMemory() );
return new GCResistantCache<NodeImpl>( node, config.get( Configuration.node_cache_array_fraction ), config.get( Configuration.log_interval ),
NODE_CACHE_NAME, logger );
}
@Override
public Cache<RelationshipImpl> newRelationshipCache( StringLogger logger, Config config )
{
long node = config.get( Configuration.node_cache_size );
long rel = config.get( Configuration.relationship_cache_size );
checkMemToUse( logger, node, rel, Runtime.getRuntime().maxMemory() );
return new GCResistantCache<RelationshipImpl>( rel, config.get( Configuration.relationship_cache_array_fraction ), config.get( Configuration.log_interval ),
RELATIONSHIP_CACHE_NAME, logger );
}
// TODO: Move into validation method of config setting?
@SuppressWarnings( "boxing" )
private void checkMemToUse( StringLogger logger, long node, long rel, long available )
{
long advicedMax = available / 2;
long total = 0;
node = Math.max( GCResistantCache.MIN_SIZE, node );
total += node;
rel = Math.max( GCResistantCache.MIN_SIZE, rel );
total += rel;
if ( total > available )
{
throw new IllegalArgumentException(
String.format( "Configured cache memory limits (node=%s, relationship=%s, " +
"total=%s) exceeds available heap space (%s)",
node, rel, total, available ) );
}
if ( total > advicedMax )
{
logger.logMessage( String.format( "Configured cache memory limits(node=%s, relationship=%s, " +
"total=%s) exceeds recommended limit (%s)",
node, rel, total, advicedMax ) );
}
}
@Override
public Class getSettingsClass()
{
return Configuration.class;
}
}