/* * Copyright (c) 2002-2010 "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; import java.io.File; import java.lang.management.ManagementFactory; import java.lang.management.OperatingSystemMXBean; import java.lang.reflect.Method; import java.util.Map; public class AutoConfigurator { private final int totalPhysicalMemMb; private final int maxVmUsageMb; private final String dbPath; private final boolean useMemoryMapped; public AutoConfigurator( String dbPath, boolean useMemoryMapped, boolean dump ) { this.dbPath = dbPath; this.useMemoryMapped = useMemoryMapped; OperatingSystemMXBean osBean = ManagementFactory.getOperatingSystemMXBean(); long mem = -1; try { Class<?> beanClass = Class.forName( "com.sun.management.OperatingSystemMXBean" ); Method method = beanClass.getMethod( "getTotalPhysicalMemorySize" ); mem = (Long) method.invoke( osBean ); } catch ( Exception e ) { // ok we tried but probably 1.5 JVM or other class library implementation } if ( mem != -1 ) { totalPhysicalMemMb = (int) (mem / 1024 / 1024 ); } else { totalPhysicalMemMb = -1; } mem = Runtime.getRuntime().maxMemory(); maxVmUsageMb = (int) ( mem / 1024 / 1024 ); if ( dump ) { System.out.println( "Physical mem: " + totalPhysicalMemMb + "MB" ); System.out.println( "Heap size: " + maxVmUsageMb + "MB" ); } } public void configure( Map<Object,Object> config ) { if ( totalPhysicalMemMb > 0 ) { if ( useMemoryMapped ) { int availableMem = (totalPhysicalMemMb - maxVmUsageMb ); // leave 15% for OS and other progs availableMem -= (int) ( availableMem * 0.15f ); assignMemory( config, availableMem ); } else { // use half of heap (if needed) for buffers assignMemory( config, maxVmUsageMb / 2 ); } } } private int calculate( int memLeft, int storeSize, float use, float expand, boolean canExpand ) { int size = memLeft; if ( storeSize > (memLeft * use) ) { size = (int) (memLeft * use); } else if ( canExpand ) { if ( (storeSize * expand * 5 < memLeft * use ) ) { size = (int) (memLeft * use / 5); } else { size = (int) (memLeft * use); } } else { size = storeSize; } return size; } private void assignMemory( Map<Object, Object> config, int availableMem ) { int nodeStore = getFileSizeMb( "nodestore.db" ); int relStore = getFileSizeMb( "relationshipstore.db" ); int propStore = getFileSizeMb( "propertystore.db" ); int stringStore = getFileSizeMb( "propertystore.db.strings" ); int arrayStore = getFileSizeMb( "propertyStore.db.arrays" ); int totalSize = nodeStore + relStore + propStore + stringStore + arrayStore; boolean expand = false; if ( totalSize * 1.15f < availableMem ) { expand = true; } int memLeft = availableMem; relStore = calculate( memLeft, relStore, 0.75f, 1.1f, expand ); memLeft -= relStore; nodeStore = calculate( memLeft, nodeStore, 0.2f, 1.1f, expand ); memLeft -= nodeStore; propStore = calculate( memLeft, propStore, 0.75f, 1.1f, expand ); memLeft -= propStore; stringStore = calculate( memLeft, stringStore, 0.75f, 1.1f, expand ); memLeft -= stringStore; arrayStore = calculate( memLeft, arrayStore, 1.0f, 1.1f, expand ); memLeft -= arrayStore; configPut( config, "nodestore.db", nodeStore ); configPut( config, "relationshipstore.db", relStore ); configPut( config, "propertystore.db", propStore ); configPut( config, "propertystore.db.strings", stringStore ); configPut( config, "propertystore.db.arrays", arrayStore ); } private void configPut( Map<Object, Object> config, String store, int size ) { config.put( "neostore." + store + ".mapped_memory", size + "M" ); } private int getFileSizeMb( String file ) { long length = new File( dbPath + "/neostore." + file ).length(); int mb = (int) ( length / 1024 / 1024 ); if ( mb > 0 ) { return mb; } // default return 1MB if small or empty file return 1; } }