diff --git a/community/configuration/src/main/java/org/neo4j/configuration/Dynamic.java b/community/configuration/src/main/java/org/neo4j/configuration/Dynamic.java new file mode 100644 index 0000000000000..df72093d999d9 --- /dev/null +++ b/community/configuration/src/main/java/org/neo4j/configuration/Dynamic.java @@ -0,0 +1,34 @@ +/* + * Copyright (c) 2002-2017 "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 . + */ +package org.neo4j.configuration; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Dynamic properties can be changed at runtime. + */ +@Retention( RetentionPolicy.RUNTIME ) +@Target( {ElementType.TYPE, ElementType.FIELD} ) +public @interface Dynamic +{ +} diff --git a/community/configuration/src/main/java/org/neo4j/configuration/LoadableConfig.java b/community/configuration/src/main/java/org/neo4j/configuration/LoadableConfig.java index 77f9c6e0da3f3..4ced5466a7f5b 100644 --- a/community/configuration/src/main/java/org/neo4j/configuration/LoadableConfig.java +++ b/community/configuration/src/main/java/org/neo4j/configuration/LoadableConfig.java @@ -75,6 +75,9 @@ default List getConfigOptions() final Internal internalAnnotation = f.getAnnotation( Internal.class ); setting.setInternal( internalAnnotation != null ); + + final Dynamic dynamicAnnotation = f.getAnnotation( Dynamic.class ); + setting.setDynamic( dynamicAnnotation != null ); } if ( publicSetting instanceof SettingGroup ) diff --git a/community/configuration/src/test/java/org/neo4j/configuration/LoadableConfigTest.java b/community/configuration/src/test/java/org/neo4j/configuration/LoadableConfigTest.java index 3365e3584dba0..a8619c08c85c6 100644 --- a/community/configuration/src/test/java/org/neo4j/configuration/LoadableConfigTest.java +++ b/community/configuration/src/test/java/org/neo4j/configuration/LoadableConfigTest.java @@ -29,48 +29,66 @@ import org.neo4j.graphdb.config.BaseSetting; import org.neo4j.graphdb.config.Configuration; import org.neo4j.graphdb.config.Setting; -import org.neo4j.helpers.collection.MapUtil; +import org.neo4j.graphdb.config.SettingGroup; import static java.util.Collections.emptyMap; import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.neo4j.helpers.collection.MapUtil.stringMap; public class LoadableConfigTest { @Test public void getConfigOptions() throws Exception { - Map config = MapUtil.stringMap( "myInt", "123", "myString", "bah", "myOldString", "moo" ); + Map config = stringMap( + TestConfig.integer.name(), "123", + TestConfig.string.name(), "bah", + TestConfig.oldString.name(), "moo", + TestConfig.dynamic.name(), "foo" ); TestConfig testSettings = new TestConfig(); List options = testSettings.getConfigOptions(); - assertEquals( 3, options.size() ); - - assertEquals( 1, options.get( 0 ).settingGroup().values( emptyMap() ).get( "myInt" ) ); - assertEquals( 123, options.get( 0 ).settingGroup().values( config ).get( "myInt" ) ); - assertEquals( Optional.empty(), options.get( 0 ).settingGroup().description() ); - assertFalse( options.get(0).settingGroup().deprecated() ); - assertEquals( Optional.empty(), options.get( 0 ).settingGroup().replacement() ); - - assertEquals( "bob", options.get( 1 ).settingGroup().values( emptyMap() ).get( "myString" ) ); - assertEquals( "bah", options.get( 1 ).settingGroup().values( config ).get( "myString" ) ); - assertEquals( "A string setting", options.get( 1 ).settingGroup().description().get() ); - assertFalse( options.get(1).settingGroup().deprecated() ); - assertEquals( Optional.empty(), options.get( 1 ).settingGroup().replacement() ); - - assertEquals( "tim", options.get( 2 ).settingGroup().values( emptyMap() ).get( "myOldString" ) ); - assertEquals( "moo", options.get( 2 ).settingGroup().values( config ).get( "myOldString" ) ); - assertEquals( "A deprecated string setting", options.get( 2 ).settingGroup().description().get() ); - assertTrue( options.get(2).settingGroup().deprecated() ); - assertEquals( "myString", options.get( 2 ).settingGroup().replacement().get() ); + assertEquals( 4, options.size() ); + + SettingGroup integerSetting = options.get( 0 ).settingGroup(); + assertEquals( 1, integerSetting.values( emptyMap() ).get( TestConfig.integer.name() ) ); + assertEquals( 123, integerSetting.values( config ).get( TestConfig.integer.name() ) ); + assertEquals( Optional.empty(), integerSetting.description() ); + assertFalse( integerSetting.deprecated() ); + assertFalse( integerSetting.dynamic() ); + assertEquals( Optional.empty(), integerSetting.replacement() ); + + SettingGroup stringSetting = options.get( 1 ).settingGroup(); + assertEquals( "bob", stringSetting.values( emptyMap() ).get( TestConfig.string.name() ) ); + assertEquals( "bah", stringSetting.values( config ).get( TestConfig.string.name() ) ); + assertEquals( "A string setting", stringSetting.description().get() ); + assertFalse( stringSetting.deprecated() ); + assertFalse( stringSetting.dynamic() ); + assertEquals( Optional.empty(), stringSetting.replacement() ); + + SettingGroup oldStringSetting = options.get( 2 ).settingGroup(); + assertEquals( "tim", oldStringSetting.values( emptyMap() ).get( TestConfig.oldString.name() ) ); + assertEquals( "moo", oldStringSetting.values( config ).get( TestConfig.oldString.name() ) ); + assertEquals( "A deprecated string setting", oldStringSetting.description().get() ); + assertTrue( oldStringSetting.deprecated() ); + assertFalse( oldStringSetting.dynamic() ); + assertEquals( TestConfig.string.name(), oldStringSetting.replacement().get() ); + + SettingGroup dynamicSetting = options.get( 3 ).settingGroup(); + assertEquals( "defaultDynamic", dynamicSetting.values( emptyMap() ).get( TestConfig.dynamic.name() ) ); + assertEquals( "foo", dynamicSetting.values( config ).get( TestConfig.dynamic.name() ) ); + assertEquals( "A dynamic string setting", dynamicSetting.description().get() ); + assertFalse( dynamicSetting.deprecated() ); + assertTrue( dynamicSetting.dynamic() ); + assertEquals( Optional.empty(), dynamicSetting.replacement() ); } private static class TestConfig implements LoadableConfig { - @SuppressWarnings( "unused" ) public static final Setting integer = new BaseSetting() { @Override @@ -116,7 +134,6 @@ public Integer apply( Function provider ) }; - @SuppressWarnings( "unused" ) @Description( "A string setting" ) public static final Setting string = new StringSetting() { @@ -156,7 +173,6 @@ public String from( Configuration configuration ) } }; - @SuppressWarnings( "unused" ) @Description( "A deprecated string setting" ) @Deprecated @ReplacedBy( "myString" ) @@ -232,16 +248,50 @@ public String from( Configuration configuration ) return configuration.get( this ); } }; + + @Description( "A dynamic string setting" ) + @Dynamic + public static final Setting dynamic = new StringSetting() + { + @Override + public String apply( Function provider ) + { + String val = provider.apply( name() ); + if ( val == null ) + { + val = getDefaultValue(); + } + return val; + } + + @Override + public String name() + { + return "myDynamicProperty"; + } + + @Override + public void withScope( Function scopingRule ) + { + + } + + @Override + public String getDefaultValue() + { + return "defaultDynamic"; + } + + @Override + public String from( Configuration configuration ) + { + return configuration.get( this ); + } + }; } private abstract static class StringSetting extends BaseSetting { - @Override - public boolean isReloadable() - { - return false; - } - @Override public String valueDescription() { diff --git a/community/graphdb-api/src/main/java/org/neo4j/graphdb/config/BaseSetting.java b/community/graphdb-api/src/main/java/org/neo4j/graphdb/config/BaseSetting.java index 0fb3b2dee6ec9..86a08b3f072c2 100644 --- a/community/graphdb-api/src/main/java/org/neo4j/graphdb/config/BaseSetting.java +++ b/community/graphdb-api/src/main/java/org/neo4j/graphdb/config/BaseSetting.java @@ -24,12 +24,15 @@ /** * All fields specified here are set via annotations when loaded + * @deprecated The settings API will be completely rewritten in 4.0 */ +@Deprecated public abstract class BaseSetting implements Setting { private boolean deprecated; private String replacement; private boolean internal; + private boolean dynamic; private String documentedDefaultValue; private String description; @@ -93,4 +96,21 @@ public String toString() { return valueDescription(); } + + /** + * Checks whether this setting is dynamic or not. Dynamic properties are allowed to be changed at runtime without + * restarting the server. + * + * @return {@code true} if this setting can be changed at runtime. + */ + @Override + public boolean dynamic() + { + return dynamic; + } + + public void setDynamic( boolean dynamic ) + { + this.dynamic = dynamic; + } } diff --git a/community/graphdb-api/src/main/java/org/neo4j/graphdb/config/Configuration.java b/community/graphdb-api/src/main/java/org/neo4j/graphdb/config/Configuration.java index f7f7a69766f5b..78cd4c7146d0a 100644 --- a/community/graphdb-api/src/main/java/org/neo4j/graphdb/config/Configuration.java +++ b/community/graphdb-api/src/main/java/org/neo4j/graphdb/config/Configuration.java @@ -21,7 +21,9 @@ /** * Provide the basic operation that one could perform on a set of configurations. + * @deprecated The settings API will be completely rewritten in 4.0 */ +@Deprecated public interface Configuration { /** diff --git a/community/graphdb-api/src/main/java/org/neo4j/graphdb/config/InvalidSettingException.java b/community/graphdb-api/src/main/java/org/neo4j/graphdb/config/InvalidSettingException.java index 2696dadf1da5e..7ec8212757dc3 100644 --- a/community/graphdb-api/src/main/java/org/neo4j/graphdb/config/InvalidSettingException.java +++ b/community/graphdb-api/src/main/java/org/neo4j/graphdb/config/InvalidSettingException.java @@ -21,7 +21,9 @@ /** * Thrown when a configuration setting is, for one reason or another, invalid. + * @deprecated The settings API will be completely rewritten in 4.0 */ +@Deprecated public class InvalidSettingException extends RuntimeException { diff --git a/community/graphdb-api/src/main/java/org/neo4j/graphdb/config/ScopeAwareSetting.java b/community/graphdb-api/src/main/java/org/neo4j/graphdb/config/ScopeAwareSetting.java index 46ebbe137fbd7..1839029560a1a 100644 --- a/community/graphdb-api/src/main/java/org/neo4j/graphdb/config/ScopeAwareSetting.java +++ b/community/graphdb-api/src/main/java/org/neo4j/graphdb/config/ScopeAwareSetting.java @@ -21,6 +21,10 @@ import java.util.function.Function; +/** + * @deprecated The settings API will be completely rewritten in 4.0 + */ +@Deprecated public abstract class ScopeAwareSetting extends BaseSetting { private Function scopingRule = Function.identity(); diff --git a/community/graphdb-api/src/main/java/org/neo4j/graphdb/config/Setting.java b/community/graphdb-api/src/main/java/org/neo4j/graphdb/config/Setting.java index cf2652280d0bd..741ede7a98455 100644 --- a/community/graphdb-api/src/main/java/org/neo4j/graphdb/config/Setting.java +++ b/community/graphdb-api/src/main/java/org/neo4j/graphdb/config/Setting.java @@ -33,12 +33,14 @@ /** * Settings that can be provided in configurations are represented by instances of this interface, and are available * as static fields in various *Settings classes. - * + *

* This interface is available only for use, not for implementing. Implementing this interface is not expected, and * backwards compatibility is not guaranteed for implementors. * * @param type of value this setting will parse input string into and return. + * @deprecated The settings API will be completely rewritten in 4.0 */ +@Deprecated public interface Setting extends Function,T>, SettingValidator, SettingGroup { /** @@ -106,13 +108,8 @@ default List> settings( Map params ) * * @return the parser function */ - default Optional> getParser() + default Optional> getParser() { return Optional.empty(); } - - default boolean isReloadable() - { - return false; - } } diff --git a/community/graphdb-api/src/main/java/org/neo4j/graphdb/config/SettingGroup.java b/community/graphdb-api/src/main/java/org/neo4j/graphdb/config/SettingGroup.java index c197f0fe4a754..741932f1022ac 100644 --- a/community/graphdb-api/src/main/java/org/neo4j/graphdb/config/SettingGroup.java +++ b/community/graphdb-api/src/main/java/org/neo4j/graphdb/config/SettingGroup.java @@ -26,55 +26,60 @@ /** * This interface represents a setting group. One example can be group defined by a common prefix, such as * `dbms.connector.*`. The important aspect is that config keys can only be known after a config has been parsed. + * + * @deprecated The settings API will be completely rewritten in 4.0 */ +@Deprecated public interface SettingGroup extends SettingValidator { /** * Apply this setting group to the config and return all of its configured keys and their corresponding values. * - * @param validConfig which can be examined - * @return the map of this group's configured keys and values + * @param validConfig which can be examined. + * @return the map of this group's configured keys and values. */ Map values( Map validConfig ); /** - * @return a list of the settings this group contains + * @return a list of the settings this group contains. */ List> settings( Map params ); /** - * - * @return true if this setting is deprecated, false otherwise + * @return {@code true} if this setting is deprecated, false otherwise. */ boolean deprecated(); /** - * - * @return the key of the setting which replaces this when its deprecated, empty if not depricated + * @return the key of the setting which replaces this when its deprecated, empty if not deprecated. */ Optional replacement(); /** - * - * @return true if internal setting, false otherwise + * @return {@code true} if internal setting, false otherwise. */ boolean internal(); /** - * - * @return the documented default value if it needs special documentation, empty if default value is good as is + * @return the documented default value if it needs special documentation, empty if default value is good as is. */ Optional documentedDefaultValue(); /** - * * @return description of which values are good */ String valueDescription(); /** - * - * @return description of setting, empty in case no description exists + * @return description of setting, empty in case no description exists. */ Optional description(); + + /** + * @return {@code true} if the setting can be changed at runtime. + */ + default boolean dynamic() + { + return false; + } } diff --git a/community/graphdb-api/src/main/java/org/neo4j/graphdb/config/SettingValidator.java b/community/graphdb-api/src/main/java/org/neo4j/graphdb/config/SettingValidator.java index 3c5397eb90283..515f7eb484818 100644 --- a/community/graphdb-api/src/main/java/org/neo4j/graphdb/config/SettingValidator.java +++ b/community/graphdb-api/src/main/java/org/neo4j/graphdb/config/SettingValidator.java @@ -22,6 +22,10 @@ import java.util.Map; import java.util.function.Consumer; +/** + * @deprecated The settings API will be completely rewritten in 4.0 + */ +@Deprecated public interface SettingValidator { /** diff --git a/community/kernel/src/main/java/org/neo4j/graphdb/factory/GraphDatabaseSettings.java b/community/kernel/src/main/java/org/neo4j/graphdb/factory/GraphDatabaseSettings.java index c4a58f1df7ef6..c414e8c78c226 100644 --- a/community/kernel/src/main/java/org/neo4j/graphdb/factory/GraphDatabaseSettings.java +++ b/community/kernel/src/main/java/org/neo4j/graphdb/factory/GraphDatabaseSettings.java @@ -24,6 +24,7 @@ import java.util.List; import org.neo4j.configuration.Description; +import org.neo4j.configuration.Dynamic; import org.neo4j.configuration.Internal; import org.neo4j.configuration.LoadableConfig; import org.neo4j.configuration.ReplacedBy; @@ -250,8 +251,9 @@ public class GraphDatabaseSettings implements LoadableConfig setting( "unsupported.dbms.executiontime_limit.enabled", BOOLEAN, FALSE ).build(); @Description( "The maximum time interval of a transaction within which it should be completed." ) + @Dynamic public static final Setting transaction_timeout = setting( "dbms.transaction.timeout", DURATION, String - .valueOf( UNSPECIFIED_TIMEOUT ) ).isReloadable().build(); + .valueOf( UNSPECIFIED_TIMEOUT ) ).build(); @Description( "The maximum time interval within which lock should be acquired." ) public static final Setting lock_acquisition_timeout = setting( "dbms.lock.acquisition.timeout", DURATION, @@ -498,8 +500,9 @@ public class GraphDatabaseSettings implements LoadableConfig "Log entries are by default written to the file _query.log_ located in the Logs directory. " + "For location of the Logs directory, see <>. " + "This feature is available in the Neo4j Enterprise Edition." ) + @Dynamic public static final Setting log_queries = - setting( "dbms.logs.query.enabled", BOOLEAN, FALSE ).isReloadable().build(); + setting( "dbms.logs.query.enabled", BOOLEAN, FALSE ).build(); @Description( "Path of the logs directory." ) public static final Setting logs_directory = pathSetting( "dbms.directories.logs", "logs" ); @@ -534,8 +537,9 @@ public class GraphDatabaseSettings implements LoadableConfig @Description( "If the execution of query takes more time than this threshold, the query is logged - " + "provided query logging is enabled. Defaults to 0 seconds, that is all queries are logged." ) + @Dynamic public static final Setting log_queries_threshold = - setting( "dbms.logs.query.threshold", DURATION, "0s" ).isReloadable().build(); + setting( "dbms.logs.query.threshold", DURATION, "0s" ).build(); @Description( "The file size in bytes at which the query log will auto-rotate. If set to zero then no rotation " + "will occur. Accepts a binary suffix `k`, `m` or `g`." ) diff --git a/community/kernel/src/main/java/org/neo4j/kernel/configuration/ConnectorValidator.java b/community/kernel/src/main/java/org/neo4j/kernel/configuration/ConnectorValidator.java index 11e6c03689b53..bdaf022974131 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/configuration/ConnectorValidator.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/configuration/ConnectorValidator.java @@ -246,4 +246,10 @@ public Optional description() { return Optional.empty(); } + + @Override + public boolean dynamic() + { + return false; + } } diff --git a/community/kernel/src/main/java/org/neo4j/kernel/configuration/Settings.java b/community/kernel/src/main/java/org/neo4j/kernel/configuration/Settings.java index 0435c09ca99c2..d826ba44c1935 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/configuration/Settings.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/configuration/Settings.java @@ -120,7 +120,6 @@ public static final class SettingBuilder private final String defaultValue; private Setting inheritedSetting; private List,T>> valueConstraints; - private boolean isReloadable; private SettingBuilder( @Nonnull final String name, @Nonnull final Function parser, @Nullable final String defaultValue ) { @@ -167,19 +166,6 @@ public SettingBuilder constraint( @Nonnull final BiFunction isReloadable() - { - isReloadable = true; - return this; - } - @Nonnull public Setting build() { @@ -191,7 +177,7 @@ public Setting build() defaultLookup = inheritedDefault( defaultLookup, inheritedSetting ); } - return new DefaultSetting<>( name, parser, valueLookup, defaultLookup, isReloadable, valueConstraints ); + return new DefaultSetting<>( name, parser, valueLookup, defaultLookup, valueConstraints ); } } @@ -1157,6 +1143,12 @@ public Optional description() return newSetting.description(); } + @Override + public boolean dynamic() + { + return newSetting.dynamic(); + } + @Override public boolean deprecated() { @@ -1194,20 +1186,17 @@ public static class DefaultSetting extends ScopeAwareSetting implements Se private final Function parser; private final BiFunction,String> valueLookup; private final BiFunction,String> defaultLookup; - private final boolean isReloadable; private final List,T>> valueConverters; protected DefaultSetting( String name, Function parser, BiFunction,String> valueLookup, BiFunction,String> defaultLookup, - boolean isReloadable, List,T>> valueConverters ) { this.name = name; this.parser = parser; this.valueLookup = valueLookup; this.defaultLookup = defaultLookup; - this.isReloadable = isReloadable; this.valueConverters = valueConverters; } @@ -1247,12 +1236,6 @@ public String defaultLookup( Function settings ) return defaultLookup.apply( name(), settings ); } - @Override - public boolean isReloadable() - { - return isReloadable; - } - @Override public T apply( Function settings ) { diff --git a/community/kernel/src/main/java/org/neo4j/kernel/configuration/ssl/SslPolicyConfigValidator.java b/community/kernel/src/main/java/org/neo4j/kernel/configuration/ssl/SslPolicyConfigValidator.java index 81455770d2566..ac0e2e7d752c5 100644 --- a/community/kernel/src/main/java/org/neo4j/kernel/configuration/ssl/SslPolicyConfigValidator.java +++ b/community/kernel/src/main/java/org/neo4j/kernel/configuration/ssl/SslPolicyConfigValidator.java @@ -173,4 +173,10 @@ public Optional description() { return empty(); } + + @Override + public boolean dynamic() + { + return false; + } } diff --git a/community/kernel/src/test/java/org/neo4j/kernel/configuration/SettingsTest.java b/community/kernel/src/test/java/org/neo4j/kernel/configuration/SettingsTest.java index 696447b4d76ad..5724ad358219a 100644 --- a/community/kernel/src/test/java/org/neo4j/kernel/configuration/SettingsTest.java +++ b/community/kernel/src/test/java/org/neo4j/kernel/configuration/SettingsTest.java @@ -41,9 +41,7 @@ import static org.hamcrest.Matchers.is; import static org.hamcrest.Matchers.nullValue; import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertThat; -import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; import static org.neo4j.helpers.collection.MapUtil.stringMap; import static org.neo4j.kernel.configuration.Settings.DURATION; @@ -346,15 +344,6 @@ public void testNormalizedRelativeURI() throws Exception assertThat( uri.apply( always -> null ).toString(), equalTo( "/db/data" ) ); } - @Test - public void settingsShouldNotBeReloadableByDefault() throws Exception - { - Setting notReloadable = setting( "mySetting", STRING, "d" ).build(); - assertFalse( notReloadable.isReloadable() ); - Setting reloadable = setting( "mySetting", STRING, "d" ).isReloadable().build(); - assertTrue( reloadable.isReloadable() ); - } - @Test public void onlySingleInheritanceShouldBeAllowed() throws Exception { diff --git a/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/CausalClusteringSettings.java b/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/CausalClusteringSettings.java index 4bcfb14eac6f6..c1a261f97b8b3 100644 --- a/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/CausalClusteringSettings.java +++ b/enterprise/causal-clustering/src/main/java/org/neo4j/causalclustering/core/CausalClusteringSettings.java @@ -371,7 +371,7 @@ static BaseSetting prefixSetting( final String name, final Function, String> defaultLookup = determineDefaultLookup( defaultValue, valueLookup ); - return new Settings.DefaultSetting( name, parser, valueLookup, defaultLookup, false, Collections.emptyList() ) + return new Settings.DefaultSetting( name, parser, valueLookup, defaultLookup, Collections.emptyList() ) { @Override public Map validate( Map rawConfig, Consumer warningConsumer )