Skip to content

Commit

Permalink
Introduce cache.memory_ratio configuration for HPCache
Browse files Browse the repository at this point in the history
New set-and-forget configuration that specifies cache size as a ratio of the
old generation max size. Memory division across internal components of the cache
is handled by fixed ratios.

If any of the old config (now referred to as "advanced config") is set, it will
override the memory_ratio configuration.
  • Loading branch information
jakewins committed Sep 2, 2014
1 parent b477ff1 commit c17c287
Show file tree
Hide file tree
Showing 15 changed files with 723 additions and 69 deletions.
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ out
.mailmap
.java-version
community/server/data
enterprise/server-enterprise/data
27 changes: 25 additions & 2 deletions community/kernel/src/docs/ops/cache.asciidoc
Original file line number Diff line number Diff line change
Expand Up @@ -156,8 +156,31 @@ The available cache types are:

=== High-Performance Cache ===

Since the High-Performance Cache operates with a maximum size in the JVM it may be configured per use case for optimal performance.
There are two aspects of the cache size.
How much memory to allocate to the High Performance Cache can be fine tuned to suit your use case.
There are two ways to configure memory usage for it.

*Standard configuration*

For most use cases, simply specifying a percentage of the memory available for caching to use is enough to tune the High-Performance Cache.

Allocating more memory to the cache gives faster querying speed, but takes memory away from other components and may put strain on the JVM garbage collector.

The max amount of memory available for caching depends on which garbage collector you are using.
For CMS and G1 collectors (CMS is the Neo4j default), it will be equal to the max size of the old generation. How big
the old generation is is platform-dependent, but can for CMS and G1 be configured using the "NewRatio" JVM configuration
option.
For other collectors, it will be half of the total heap size.

[options="header",cols="<25m,<65,<10m"]
|==========================================
| `configuration option` | Description (what it controls) | Example value
| cache.memory_ratio | Percentage, 0-100, of memory available for caching to use for caching. Default is 50%. | 50.0
|==========================================

*Advanced configuration*

The advanced configuration gives more fine-grained control of how much memory to allocate specific parts of the cache.
There are two aspects to this configuration.

One is the size of the array referencing the objects that are put in the cache.
It is specified as a fraction of the heap, for example specifying +5+ will let that array itself take up 5% out of the entire heap.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/**
* Copyright (c) 2002-2014 "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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.graphdb.config;

/**
* Thrown when a configuration setting is, for one reason or another, invalid.
*/
public class InvalidSettingException extends RuntimeException
{
private final String name;

public InvalidSettingException( String name, String value, String message )
{
super(String.format( "Bad value '%s' for setting '%s': %s", value, name, message ));
this.name = name;
}

public InvalidSettingException( String name, String message )
{
super(message);
this.name = name;
}

public String settingName()
{
return name;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
import java.util.List;
import java.util.regex.Pattern;

import org.neo4j.graphdb.config.InvalidSettingException;
import org.neo4j.graphdb.config.Setting;
import org.neo4j.helpers.collection.Iterables;
import org.neo4j.kernel.configuration.Config;
Expand Down Expand Up @@ -804,7 +805,7 @@ public T apply( Function<String, String> settings )
}
catch ( IllegalArgumentException e )
{
throw new IllegalArgumentException( String.format( "Bad value '%s' for setting '%s': %s", value, name(), e.getMessage() ) );
throw new InvalidSettingException( name(), value, e.getMessage() );
}


Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
/**
* Copyright (c) 2002-2014 "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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.kernel.impl.util.function;

/**
* Represents a value that may or may not exist.
*/
public interface Optional<TYPE>
{
TYPE get();
boolean isPresent();

Optional<TYPE> or(Optional<TYPE> secondChoice);
Optional<TYPE> or(TYPE secondChoice);
}

Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
/**
* Copyright (c) 2002-2014 "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 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 General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.kernel.impl.util.function;

public class Optionals
{
public static final Optional NONE = new Optional(){

@Override
public Object get() {
throw new UnsupportedOperationException();
}

@Override
public boolean isPresent() {
return false;
}

@Override
public Optional or( Optional secondChoice ) {
return secondChoice;
}

@Override
public Optional or( Object secondChoice ) {
return some( secondChoice );
}
};

public static <TYPE> Optional<TYPE> none()
{
return NONE;
}

public static <TYPE> Optional<TYPE> some( final TYPE obj )
{
return new Optional<TYPE>(){

@Override
public TYPE get() {
return obj;
}

@Override
public boolean isPresent() {
return true;
}

@Override
public Optional<TYPE> or( Optional<TYPE> secondChoice ) {
return this;
}

@Override
public Optional<TYPE> or( TYPE secondChoice ) {
return this;
}
};
}

public static abstract class LazyOptional<TYPE> implements Optional<TYPE>
{
private TYPE value;
private boolean evaluated = false;

protected abstract TYPE evaluate();

@Override
public TYPE get()
{
if(!isPresent())
{
throw new UnsupportedOperationException();
}
return value();
}

@Override
public boolean isPresent()
{
return value() != null;
}

@Override
public Optional<TYPE> or( Optional<TYPE> secondChoice )
{
return isPresent() ? this : secondChoice;
}

@Override
public Optional<TYPE> or( TYPE secondChoice )
{
return isPresent() ? this : some(secondChoice);
}

private TYPE value()
{
if(!evaluated) value = evaluate();
return value;
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@

import org.junit.Test;

import org.neo4j.graphdb.config.InvalidSettingException;
import org.neo4j.graphdb.config.Setting;
import org.neo4j.graphdb.factory.GraphDatabaseSettings;

Expand Down Expand Up @@ -66,7 +67,7 @@ public void testInteger()
setting.apply( map( stringMap( "foo", "bar" ) ) );
fail();
}
catch ( IllegalArgumentException e )
catch ( InvalidSettingException e )
{
// Ok
}
Expand Down Expand Up @@ -99,7 +100,7 @@ public void testMin()
setting.apply( map( stringMap( "foo", "1" ) ) );
fail();
}
catch ( IllegalArgumentException e )
catch ( InvalidSettingException e )
{
// Ok
}
Expand All @@ -120,7 +121,7 @@ public void testMax()
setting.apply( map( stringMap( "foo", "7" ) ) );
fail();
}
catch ( IllegalArgumentException e )
catch ( InvalidSettingException e )
{
// Ok
}
Expand All @@ -140,7 +141,7 @@ public void testRange()
setting.apply( map( stringMap( "foo", "1" ) ) );
fail();
}
catch ( IllegalArgumentException e )
catch ( InvalidSettingException e )
{
// Ok
}
Expand All @@ -150,7 +151,7 @@ public void testRange()
setting.apply( map( stringMap( "foo", "6" ) ) );
fail();
}
catch ( IllegalArgumentException e )
catch ( InvalidSettingException e )
{
// Ok
}
Expand All @@ -170,21 +171,21 @@ public void testMatches()
setting.apply( map( stringMap( "foo", "cba" ) ) );
fail();
}
catch ( IllegalArgumentException e )
catch ( InvalidSettingException e )
{
// Ok
}
}

@Test( expected = IllegalArgumentException.class )
@Test( expected = InvalidSettingException.class )
public void testDurationWithBrokenDefault()
{
// Notice that the default value is less that the minimum
Setting<Long> setting = setting( "foo.bar", DURATION, "1s", min( DURATION.apply( "3s" ) ) );
setting.apply( map( stringMap() ) );
}

@Test( expected = IllegalArgumentException.class )
@Test( expected = InvalidSettingException.class )
public void testDurationWithValueNotWithinConstraint()
{
Setting<Long> setting = setting( "foo.bar", DURATION, "3s", min( DURATION.apply( "3s" ) ) );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.Map;

import org.junit.Test;
import org.neo4j.graphdb.config.InvalidSettingException;
import org.neo4j.graphdb.config.Setting;
import org.neo4j.helpers.Settings;

Expand Down Expand Up @@ -99,7 +100,7 @@ public void shouldNotAllowSettingInvalidValues()

fail( "Expected validation to fail." );
}
catch ( IllegalArgumentException e )
catch ( InvalidSettingException e )
{
}
}
Expand All @@ -113,7 +114,7 @@ public void shouldNotAllowInvalidValuesInConstructor()

fail( "Expected validation to fail." );
}
catch ( IllegalArgumentException e )
catch ( InvalidSettingException e )
{
}
}
Expand Down
Loading

0 comments on commit c17c287

Please sign in to comment.