Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with
or
.
Download ZIP
Browse files

Refactored the server startup healtchecks, combining it with the PreS…

…tartupStoreUpgrader code. Checks and tasks performed before proper server

start are now uniformly called PreFlightTasks. These can take arbitrary time to perform (eg. upgrades, recovery).

After the preflight checks, the main server startup uses a timer thread to keep track of startup time. If startup takes longer than the configured timeout,
the startup process is interrupted.

This is all done within the main server process, which means we can remove the code in startup scripts that start a bootstrap JVM separately, as well
as the code that keeps track of startup timeouts.
  • Loading branch information...
commit bd81d793936f707aa142bfb5b2c09bf753f8514c 1 parent 54d4173
@jakewins jakewins authored committed
Showing with 1,099 additions and 444 deletions.
  1. +117 −0 kernel/src/main/java/org/neo4j/kernel/impl/recovery/StoreRecoverer.java
  2. +6 −4 kernel/src/main/java/org/neo4j/kernel/impl/transaction/xaframework/XaLogicalLog.java
  3. +119 −0 kernel/src/test/java/org/neo4j/kernel/impl/recovery/TestStoreRecoverer.java
  4. +5 −7 ...test/java/org/neo4j/server/{StartupHealthcheckFunctionalTest.java → PreflightTasksFunctionalTest.java}
  5. +149 −0 server/src/functionaltest/java/org/neo4j/server/TestStartupTimeout.java
  6. +12 −6 server/src/functionaltest/java/org/neo4j/server/{webadmin → web}/logging/HTTPLoggingFunctionalTest.java
  7. +42 −17 server/src/main/java/org/neo4j/server/AbstractNeoServer.java
  8. +3 −1 server/src/main/java/org/neo4j/server/Bootstrapper.java
  9. +13 −9 server/src/main/java/org/neo4j/server/CommunityNeoServer.java
  10. +136 −0 server/src/main/java/org/neo4j/server/InterruptThreadTimer.java
  11. +1 −1  server/src/main/java/org/neo4j/server/ServerStartupException.java
  12. +3 −3 server/src/main/java/org/neo4j/server/WrappingNeoServer.java
  13. +4 −0 server/src/main/java/org/neo4j/server/configuration/Configurator.java
  14. +5 −0 server/src/main/java/org/neo4j/server/configuration/ServerConfigurator.java
  15. +20 −5 ...er/{startup/healthcheck/Neo4jPropertiesMustExistRule.java → preflight/EnsureNeo4jPropertiesExist.java}
  16. +12 −8 ...r/{startup/healthcheck/HTTPLoggingPreparednessRule.java → preflight/EnsurePreparedForHttpLogging.java}
  17. +75 −0 server/src/main/java/org/neo4j/server/preflight/PerformRecoveryIfNecessary.java
  18. +36 −54 .../neo4j/server/{storemigration/PreStartupStoreUpgrader.java → preflight/PerformUpgradeIfNecessary.java}
  19. +85 −0 server/src/main/java/org/neo4j/server/preflight/PreFlightTasks.java
  20. +6 −8 ...edAsASystemPropertyRuleTest.java → main/java/org/neo4j/server/preflight/PreflightFailedException.java}
  21. +3 −4 ...java/org/neo4j/server/{startup/healthcheck/StartupHealthCheckRule.java → preflight/PreflightTask.java}
  22. +0 −74 server/src/main/java/org/neo4j/server/startup/healthcheck/ConfigFileMustBePresentRule.java
  23. +0 −70 server/src/main/java/org/neo4j/server/startup/healthcheck/StartupHealthCheck.java
  24. +36 −9 ...eck/StartupHealthCheckFailedException.java → test/java/org/neo4j/server/TestInterruptThreadTimer.java}
  25. +14 −14 server/src/test/java/org/neo4j/server/helpers/ServerBuilder.java
  26. +21 −22 .../src/test/java/org/neo4j/server/{startup/healthcheck → preflight}/HTTPLoggingPreparednessRuleTest.java
  27. +113 −0 server/src/test/java/org/neo4j/server/preflight/TestPerformRecoveryIfNecessary.java
  28. +42 −33 ...erver/{storemigration/PreStartupStoreUpgraderTest.java → preflight/TestPerformUpgradeIfNecessary.java}
  29. +21 −21 ...org/neo4j/server/{startup/healthcheck/StartupHealthCheckTest.java → preflight/TestPreflightTasks.java}
  30. +0 −74 server/src/test/java/org/neo4j/server/startup/healthcheck/ConfigFileMustBePresentRuleTest.java
  31. 0  ...r/src/test/resources/org/neo4j/server/{storemigration → preflight}/legacystore/exampledb/active_tx_log
  32. 0  ...st/resources/org/neo4j/server/{storemigration → preflight}/legacystore/exampledb/index/lucene-store.db
  33. 0  .../resources/org/neo4j/server/{storemigration → preflight}/legacystore/exampledb/index/lucene.log.active
  34. 0  ...er/src/test/resources/org/neo4j/server/{storemigration → preflight}/legacystore/exampledb/messages.log
  35. 0  server/src/test/resources/org/neo4j/server/{storemigration → preflight}/legacystore/exampledb/neostore
  36. 0  server/src/test/resources/org/neo4j/server/{storemigration → preflight}/legacystore/exampledb/neostore.id
  37. 0  ...st/resources/org/neo4j/server/{storemigration → preflight}/legacystore/exampledb/neostore.nodestore.db
  38. 0  ...resources/org/neo4j/server/{storemigration → preflight}/legacystore/exampledb/neostore.nodestore.db.id
  39. 0  ...esources/org/neo4j/server/{storemigration → preflight}/legacystore/exampledb/neostore.propertystore.db
  40. 0  ...s/org/neo4j/server/{storemigration → preflight}/legacystore/exampledb/neostore.propertystore.db.arrays
  41. 0  ...rg/neo4j/server/{storemigration → preflight}/legacystore/exampledb/neostore.propertystore.db.arrays.id
  42. 0  ...urces/org/neo4j/server/{storemigration → preflight}/legacystore/exampledb/neostore.propertystore.db.id
  43. 0  ...es/org/neo4j/server/{storemigration → preflight}/legacystore/exampledb/neostore.propertystore.db.index
  44. 0  ...org/neo4j/server/{storemigration → preflight}/legacystore/exampledb/neostore.propertystore.db.index.id
  45. 0  ...g/neo4j/server/{storemigration → preflight}/legacystore/exampledb/neostore.propertystore.db.index.keys
  46. 0  ...eo4j/server/{storemigration → preflight}/legacystore/exampledb/neostore.propertystore.db.index.keys.id
  47. 0  .../org/neo4j/server/{storemigration → preflight}/legacystore/exampledb/neostore.propertystore.db.strings
  48. 0  ...g/neo4j/server/{storemigration → preflight}/legacystore/exampledb/neostore.propertystore.db.strings.id
  49. 0  ...rces/org/neo4j/server/{storemigration → preflight}/legacystore/exampledb/neostore.relationshipstore.db
  50. 0  ...s/org/neo4j/server/{storemigration → preflight}/legacystore/exampledb/neostore.relationshipstore.db.id
  51. 0  .../org/neo4j/server/{storemigration → preflight}/legacystore/exampledb/neostore.relationshiptypestore.db
  52. 0  ...g/neo4j/server/{storemigration → preflight}/legacystore/exampledb/neostore.relationshiptypestore.db.id
  53. 0  ...eo4j/server/{storemigration → preflight}/legacystore/exampledb/neostore.relationshiptypestore.db.names
  54. 0  ...j/server/{storemigration → preflight}/legacystore/exampledb/neostore.relationshiptypestore.db.names.id
  55. 0  ...esources/org/neo4j/server/{storemigration → preflight}/legacystore/exampledb/nioneo_logical.log.active
  56. 0  server/src/test/resources/org/neo4j/server/{storemigration → preflight}/legacystore/exampledb/tm_tx_log.1
  57. 0  server/src/test/resources/org/neo4j/server/{storemigration → preflight}/legacystore/exampledb/tm_tx_log.2
View
117 kernel/src/main/java/org/neo4j/kernel/impl/recovery/StoreRecoverer.java
@@ -0,0 +1,117 @@
+/**
+ * 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 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.recovery;
+
+import java.io.File;
+import java.io.IOException;
+import java.nio.channels.FileChannel;
+import java.util.Map;
+
+import org.neo4j.graphdb.GraphDatabaseService;
+import org.neo4j.graphdb.factory.GraphDatabaseFactory;
+import org.neo4j.graphdb.factory.GraphDatabaseSettings;
+import org.neo4j.kernel.DefaultFileSystemAbstraction;
+import org.neo4j.kernel.configuration.Config;
+import org.neo4j.kernel.impl.nioneo.store.FileSystemAbstraction;
+import org.neo4j.kernel.impl.transaction.xaframework.XaLogicalLogFiles;
+import org.neo4j.kernel.impl.transaction.xaframework.XaLogicalLogRecoveryCheck;
+
+/**
+ * For now, an external tool that can determine if a given store
+ * will need recovery, and perform recovery on given stores.
+ */
+public class StoreRecoverer {
+
+ private FileSystemAbstraction fs;
+
+ public StoreRecoverer()
+ {
+ this(new DefaultFileSystemAbstraction());
+ }
+
+ public StoreRecoverer(FileSystemAbstraction fs)
+ {
+ this.fs = fs;
+ }
+
+ public boolean recoveryNeededAt(File dataDir, Map<String,String> params) throws IOException
+ {
+ // We need config to determine where the logical log files are
+ params.put(GraphDatabaseSettings.store_dir.name(), dataDir.getAbsolutePath());
+ Config config = new Config(params, GraphDatabaseSettings.class);
+
+ String baseLogPath = config.get(GraphDatabaseSettings.logical_log);
+ XaLogicalLogFiles logFiles = new XaLogicalLogFiles(baseLogPath, fs);
+
+ String log;
+ switch(logFiles.determineState())
+ {
+ case CLEAN:
+ return false;
+
+ case NO_ACTIVE_FILE:
+ case DUAL_LOGS_LOG_1_ACTIVE:
+ case DUAL_LOGS_LOG_2_ACTIVE:
+ return true;
+
+ case LEGACY_WITHOUT_LOG_ROTATION:
+ log = baseLogPath;
+ break;
+
+ case LOG_1_ACTIVE:
+ log = logFiles.getLog1FileName();
+ break;
+
+ case LOG_2_ACTIVE:
+ log = logFiles.getLog2FileName();
+ break;
+
+ default:
+ return true;
+ }
+
+ FileChannel logChannel = null;
+ try
+ {
+ logChannel = fs.open(log, "r");
+ return new XaLogicalLogRecoveryCheck(logChannel).recoveryRequired();
+ } finally
+ {
+ if(logChannel != null)
+ {
+ logChannel.close();
+ }
+ }
+ }
+
+ public void recover(File dataDir, Map<String,String> params) throws IOException
+ {
+ // For now, just launch a full embedded database on top of the directory.
+ // In a perfect world, to be expanded to only do recovery, and to be used
+ // as a component of the database, rather than something that is bolted
+ // on outside it like this.
+ GraphDatabaseService db =
+ new GraphDatabaseFactory().newEmbeddedDatabaseBuilder(dataDir.getCanonicalPath())
+ .setConfig(params).newGraphDatabase();
+
+ db.shutdown();
+ }
+
+}
View
10 kernel/src/main/java/org/neo4j/kernel/impl/transaction/xaframework/XaLogicalLog.java
@@ -133,7 +133,6 @@ public XaLogicalLog( String fileName, XaResourceManager xaRm, XaCommandFactory c
synchronized void open() throws IOException
{
-
switch(logFiles.determineState())
{
case LEGACY_WITHOUT_LOG_ROTATION:
@@ -1009,7 +1008,8 @@ public LogExtractor getLogExtractor( long startTxId, long endTxIdHint ) throws I
* @return The channel
* @throws IOException If an IO error occurs when reading the log file
*/
- public ReadableByteChannel getLogicalLogOrMyselfCommitted( long version, long position )
+ @Override
+ public ReadableByteChannel getLogicalLogOrMyselfCommitted( long version, long position )
throws IOException
{
synchronized ( this )
@@ -1582,7 +1582,8 @@ public long getLogicalLogTargetSize()
return this.rotateAtSize;
}
- public String getFileName( long version )
+ @Override
+ public String getFileName( long version )
{
return fileName + ".v" + version;
}
@@ -1630,7 +1631,8 @@ public boolean wasNonClean()
return nonCleanShutdown;
}
- public long getHighestLogVersion()
+ @Override
+ public long getHighestLogVersion()
{
return logVersion;
}
View
119 kernel/src/test/java/org/neo4j/kernel/impl/recovery/TestStoreRecoverer.java
@@ -0,0 +1,119 @@
+/**
+ * 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 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.recovery;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.HashMap;
+
+import org.junit.Test;
+import org.neo4j.graphdb.GraphDatabaseService;
+import org.neo4j.graphdb.factory.GraphDatabaseFactory;
+import org.neo4j.kernel.impl.util.FileUtils;
+
+
+public class TestStoreRecoverer {
+
+ @Test
+ public void shouldNotWantToRecoverIntactStore() throws Exception
+ {
+ File store = null;
+ try
+ {
+ store = createIntactStore();
+
+ StoreRecoverer recoverer = new StoreRecoverer();
+
+ assertThat(recoverer.recoveryNeededAt(store, new HashMap<String,String>()), is(false));
+
+ } finally
+ {
+ if(store != null)
+ {
+ FileUtils.deleteRecursively(store);
+ }
+ }
+
+ }
+
+ @Test
+ public void shouldWantToRecoverBrokenStore() throws Exception
+ {
+ File store = null;
+ try
+ {
+ store = createIntactStore();
+ new File(store,"nioneo_logical.log.active").delete();
+
+ StoreRecoverer recoverer = new StoreRecoverer();
+
+ assertThat(recoverer.recoveryNeededAt(store, new HashMap<String,String>()), is(true));
+
+ } finally
+ {
+ if(store != null)
+ {
+ FileUtils.deleteRecursively(store);
+ }
+ }
+
+ }
+
+ @Test
+ public void shouldBeAbleToRecoverBrokenStore() throws Exception
+ {
+ File store = null;
+ try
+ {
+ store = createIntactStore();
+ new File(store,"nioneo_logical.log.active").delete();
+
+ StoreRecoverer recoverer = new StoreRecoverer();
+
+ assertThat(recoverer.recoveryNeededAt(store, new HashMap<String,String>()), is(true));
+
+ recoverer.recover(store, new HashMap<String,String>());
+
+ assertThat(recoverer.recoveryNeededAt(store, new HashMap<String,String>()), is(false));
+
+ } finally
+ {
+ if(store != null)
+ {
+ FileUtils.deleteRecursively(store);
+ }
+ }
+
+ }
+
+ private File createIntactStore() throws IOException {
+ File tmpFile = File.createTempFile( "neo4j-test", "" );
+ tmpFile.delete();
+ GraphDatabaseService db =
+ new GraphDatabaseFactory().newEmbeddedDatabase(tmpFile.getCanonicalPath());
+
+ db.shutdown();
+ return tmpFile;
+ }
+
+}
View
12 ...ver/StartupHealthcheckFunctionalTest.java → .../server/PreflightTasksFunctionalTest.java
@@ -19,23 +19,21 @@
*/
package org.neo4j.server;
-import java.io.IOException;
-
import org.junit.Test;
import org.neo4j.server.helpers.ServerBuilder;
-import org.neo4j.server.startup.healthcheck.StartupHealthCheckFailedException;
+import org.neo4j.server.preflight.PreflightFailedException;
import org.neo4j.test.server.ExclusiveServerTestBase;
-public class StartupHealthcheckFunctionalTest extends ExclusiveServerTestBase
+public class PreflightTasksFunctionalTest extends ExclusiveServerTestBase
{
private NeoServer server;
- @Test( expected = StartupHealthCheckFailedException.class )
- public void shouldExitWhenFailedStartupHealthCheck() throws IOException
+ @Test( expected = PreflightFailedException.class )
+ public void shouldExitWhenFailedStartupHealthCheck() throws Throwable
{
server = ServerBuilder.server()
- .withFailingStartupHealthcheck()
+ .withFailingPreflightTasks()
.build();
server.start();
}
View
149 server/src/functionaltest/java/org/neo4j/server/TestStartupTimeout.java
@@ -0,0 +1,149 @@
+/**
+ * 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 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.server;
+
+import static org.junit.Assert.fail;
+
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.util.Arrays;
+import java.util.Properties;
+
+import org.junit.After;
+import org.junit.Test;
+import org.neo4j.kernel.impl.util.FileUtils;
+import org.neo4j.kernel.impl.util.StringLogger;
+import org.neo4j.server.configuration.Configurator;
+import org.neo4j.server.configuration.PropertyFileConfigurator;
+import org.neo4j.server.modules.ServerModule;
+
+public class TestStartupTimeout {
+
+ public static final String HOME_DIRECTORY = "target/" + TestStartupTimeout.class.getSimpleName();
+ public static final String STORE_DIRECTORY = HOME_DIRECTORY + "/data/graph.db";
+
+ public CommunityNeoServer server;
+
+ @After
+ public void stopServer()
+ {
+ if(server != null)
+ {
+ server.stop();
+ server = null;
+ }
+ }
+
+ @Test
+ public void shouldTimeoutIfStartupTakesLongerThanTimeout() throws IOException
+ {
+ Configurator configurator = buildProperties();
+ configurator.configuration().setProperty(Configurator.STARTUP_TIMEOUT, 1);
+ server = createSlowServer(configurator);
+
+ try {
+ server.start();
+ fail("Should have been interrupted.");
+ } catch(ServerStartupException e) {
+ // ok!
+ }
+
+ }
+
+ @Test
+ public void shouldNotFailIfStartupTakesLessTimeThanTimeout() throws IOException
+ {
+ Configurator configurator = buildProperties();
+ configurator.configuration().setProperty(Configurator.STARTUP_TIMEOUT, 5);
+ server = new CommunityNeoServer(configurator){
+ @Override
+ protected Iterable<ServerModule> createServerModules(){
+ return Arrays.asList();
+ }
+ };
+
+ try {
+ server.start();
+ Thread.sleep(1000 * 6);
+ } catch(ServerStartupException e) {
+ fail("Should not have been interupted.");
+ } catch (InterruptedException e) {
+ fail("Should not have been interupted.");
+ }
+ }
+
+ @Test
+ public void shouldNotTimeOutIfTimeoutDisabled() throws IOException
+ {
+ Configurator configurator = buildProperties();
+ configurator.configuration().setProperty(Configurator.STARTUP_TIMEOUT, 0);
+ server = createSlowServer(configurator);
+
+ try {
+ server.start();
+ } catch(ServerStartupException e) {
+ fail("Should not have been interupted.");
+ }
+ }
+
+ private CommunityNeoServer createSlowServer(Configurator configurator) {
+ CommunityNeoServer server = new CommunityNeoServer(configurator){
+ @Override
+ protected Iterable<ServerModule> createServerModules(){
+ ServerModule slowModule = new ServerModule() {
+ @Override
+ public void start(StringLogger logger) {
+ try {
+ Thread.sleep(1000 * 5);
+ } catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ @Override
+ public void stop() { }
+ };
+ return Arrays.asList(slowModule);
+ }
+ };
+ return server;
+ }
+
+ private Configurator buildProperties() throws IOException
+ {
+ FileUtils.deleteRecursively( new File( HOME_DIRECTORY ) );
+ new File( HOME_DIRECTORY + "/conf" ).mkdirs();
+
+ Properties databaseProperties = new Properties();
+ String databasePropertiesFileName = HOME_DIRECTORY + "/conf/neo4j.properties";
+ databaseProperties.store( new FileWriter( databasePropertiesFileName ), null );
+
+ Properties serverProperties = new Properties();
+ String serverPropertiesFilename = HOME_DIRECTORY + "/conf/neo4j-server.properties";
+ serverProperties.setProperty( Configurator.DATABASE_LOCATION_PROPERTY_KEY, STORE_DIRECTORY );
+ serverProperties.setProperty( Configurator.DB_TUNING_PROPERTY_FILE_KEY, databasePropertiesFileName );
+ serverProperties.setProperty( Configurator.NEO_SERVER_CONFIG_FILE_KEY, serverPropertiesFilename );
+ serverProperties.store( new FileWriter(serverPropertiesFilename), null);
+
+ return new PropertyFileConfigurator(new File(serverPropertiesFilename));
+ }
+
+}
View
18 ...in/logging/HTTPLoggingFunctionalTest.java → ...eb/logging/HTTPLoggingFunctionalTest.java
@@ -17,7 +17,7 @@
* 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.server.webadmin.logging;
+package org.neo4j.server.web.logging;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -33,20 +33,22 @@
import java.util.Scanner;
import java.util.UUID;
+import org.apache.commons.configuration.Configuration;
import org.apache.commons.io.FileUtils;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.neo4j.server.NeoServer;
import org.neo4j.server.configuration.Configurator;
+import org.neo4j.server.configuration.MapBasedConfiguration;
import org.neo4j.server.helpers.FunctionalTestHelper;
import org.neo4j.server.helpers.ServerBuilder;
import org.neo4j.server.helpers.ServerHelper;
+import org.neo4j.server.preflight.EnsurePreparedForHttpLogging;
+import org.neo4j.server.preflight.HTTPLoggingPreparednessRuleTest;
+import org.neo4j.server.preflight.PreflightFailedException;
import org.neo4j.server.rest.JaxRsResponse;
import org.neo4j.server.rest.RestRequest;
-import org.neo4j.server.startup.healthcheck.HTTPLoggingPreparednessRule;
-import org.neo4j.server.startup.healthcheck.HTTPLoggingPreparednessRuleTest;
-import org.neo4j.server.startup.healthcheck.StartupHealthCheckFailedException;
import org.neo4j.test.TargetDirectory;
import org.neo4j.test.server.ExclusiveServerTestBase;
@@ -141,8 +143,12 @@ public void givenConfigurationWithUnwritableLogDirectoryShouldFailToStartServer(
final File configFile = HTTPLoggingPreparednessRuleTest.createConfigFile(
HTTPLoggingPreparednessRuleTest.createLogbackConfigXml( unwritableLogDir ), confDir );
+ Configuration config = new MapBasedConfiguration();
+ config.setProperty(Configurator.HTTP_LOGGING, "true");
+ config.setProperty(Configurator.HTTP_LOG_CONFIG_LOCATION, configFile.getPath());
+
server = ServerBuilder.server().withDefaultDatabaseTuning()
- .withStartupHealthCheckRules( new HTTPLoggingPreparednessRule() )
+ .withPreflightTasks( new EnsurePreparedForHttpLogging(config) )
.withProperty( Configurator.HTTP_LOGGING, "true" )
.withProperty( Configurator.HTTP_LOG_CONFIG_LOCATION, configFile.getPath() )
.build();
@@ -153,7 +159,7 @@ public void givenConfigurationWithUnwritableLogDirectoryShouldFailToStartServer(
server.start();
fail( "should have thrown exception" );
}
- catch ( StartupHealthCheckFailedException e )
+ catch ( PreflightFailedException e )
{
// then
assertThat( e.getMessage(),
View
59 server/src/main/java/org/neo4j/server/AbstractNeoServer.java
@@ -36,11 +36,11 @@
import org.neo4j.server.modules.ServerModule;
import org.neo4j.server.plugins.Injectable;
import org.neo4j.server.plugins.PluginManager;
+import org.neo4j.server.preflight.PreFlightTasks;
+import org.neo4j.server.preflight.PreflightFailedException;
import org.neo4j.server.security.KeyStoreFactory;
import org.neo4j.server.security.KeyStoreInformation;
import org.neo4j.server.security.SslCertificateFactory;
-import org.neo4j.server.startup.healthcheck.StartupHealthCheck;
-import org.neo4j.server.startup.healthcheck.StartupHealthCheckFailedException;
import org.neo4j.server.statistic.StatisticCollector;
import org.neo4j.server.web.SimpleUriBuilder;
import org.neo4j.server.web.WebServer;
@@ -55,15 +55,13 @@
protected final StatisticCollector statisticsCollector = new StatisticCollector();
- private StartupHealthCheck startupHealthCheck;
+ private PreFlightTasks preflight;
private PluginInitializer pluginInitializer;
private final List<ServerModule> serverModules = new ArrayList<ServerModule>();
-
private final SimpleUriBuilder uriBuilder = new SimpleUriBuilder();
-
- protected abstract StartupHealthCheck createHealthCheck();
+ protected abstract PreFlightTasks createPreflightTasks();
protected abstract Iterable<ServerModule> createServerModules();
@@ -75,7 +73,7 @@
@Override
public void init()
{
- this.startupHealthCheck = createHealthCheck();
+ this.preflight = createPreflightTasks();
this.database = createDatabase();
this.webServer = createWebServer();
@@ -90,14 +88,17 @@ public void init()
}
@Override
- public void start()
+ public void start() throws ServerStartupException
{
+ InterruptThreadTimer interruptStartupTimer = createInterruptStartupTimer();
+
try
{
- // Start at the bottom of the stack and work upwards to the Web
- // container
- startupHealthCheck();
-
+ // Pre-flight tasks run outside the boot timeout limit
+ runPreflightTasks();
+
+ interruptStartupTimer.startCountdown();
+
configureWebServer();
database.start();
@@ -114,8 +115,18 @@ public void start()
startWebServer( logger );
logger.logMessage( "--- SERVER STARTUP END ---", true );
- } catch(Throwable t)
+
+ interruptStartupTimer.stopCountdown();
+
+ }catch(Throwable t)
{
+ if(interruptStartupTimer.wasTriggered())
+ {
+ throw new ServerStartupException(
+ "Startup took longer than "+interruptStartupTimer.getTimeoutMillis()+"ms, and was stopped. You can disable this behavior by setting '" + Configurator.STARTUP_TIMEOUT + "' to 0.",
+ 1);
+ }
+
if(t instanceof RuntimeException)
{
throw (RuntimeException)t;
@@ -126,7 +137,21 @@ public void start()
}
}
- /**
+ protected InterruptThreadTimer createInterruptStartupTimer() {
+ long startupTimeout = getConfiguration().getInt(Configurator.STARTUP_TIMEOUT, Configurator.DEFAULT_STARTUP_TIMEOUT) * 1000;
+ InterruptThreadTimer stopStartupTimer;
+ if(startupTimeout > 0)
+ {
+ stopStartupTimer = InterruptThreadTimer.createTimer(
+ startupTimeout,
+ Thread.currentThread());
+ } else {
+ stopStartupTimer = InterruptThreadTimer.createNoOpTimer();
+ }
+ return stopStartupTimer;
+ }
+
+ /**
* Use this method to register server modules from subclasses
*
* @param clazz
@@ -160,11 +185,11 @@ private void stopModules()
}
}
- private void startupHealthCheck()
+ private void runPreflightTasks()
{
- if ( !startupHealthCheck.run() )
+ if ( !preflight.run() )
{
- throw new StartupHealthCheckFailedException( startupHealthCheck.failedRule() );
+ throw new PreflightFailedException( preflight.failedTask() );
}
}
View
4 server/src/main/java/org/neo4j/server/Bootstrapper.java
@@ -70,11 +70,13 @@ public Integer start()
return start( new String[0] );
}
+ // TODO: This does not use args, check if it is safe to remove them
public Integer start( String[] args )
{
try
{
configurator = createConfigurator();
+
server = createNeoServer();
server.start();
@@ -100,7 +102,7 @@ public Integer start( String[] args )
}
}
- protected abstract NeoServer createNeoServer();
+ protected abstract NeoServer createNeoServer();
public void stop()
{
View
22 server/src/main/java/org/neo4j/server/CommunityNeoServer.java
@@ -32,10 +32,10 @@
import org.neo4j.server.modules.StatisticModule;
import org.neo4j.server.modules.ThirdPartyJAXRSModule;
import org.neo4j.server.modules.WebAdminModule;
-import org.neo4j.server.startup.healthcheck.ConfigFileMustBePresentRule;
-import org.neo4j.server.startup.healthcheck.HTTPLoggingPreparednessRule;
-import org.neo4j.server.startup.healthcheck.Neo4jPropertiesMustExistRule;
-import org.neo4j.server.startup.healthcheck.StartupHealthCheck;
+import org.neo4j.server.preflight.EnsurePreparedForHttpLogging;
+import org.neo4j.server.preflight.PerformRecoveryIfNecessary;
+import org.neo4j.server.preflight.PerformUpgradeIfNecessary;
+import org.neo4j.server.preflight.PreFlightTasks;
import org.neo4j.server.web.Jetty6WebServer;
import org.neo4j.server.web.WebServer;
@@ -54,11 +54,15 @@ public CommunityNeoServer( Configurator configurator )
}
@Override
- protected StartupHealthCheck createHealthCheck() {
- return new StartupHealthCheck(
- new ConfigFileMustBePresentRule(),
- new Neo4jPropertiesMustExistRule(),
- new HTTPLoggingPreparednessRule() );
+ protected PreFlightTasks createPreflightTasks() {
+ return new PreFlightTasks(
+ // TODO: Move the config check into bootstrapper
+ //new EnsureNeo4jPropertiesExist(configurator.configuration()),
+ new EnsurePreparedForHttpLogging(configurator.configuration()),
+ new PerformUpgradeIfNecessary(getConfiguration(),
+ configurator.getDatabaseTuningProperties(), System.out),
+ new PerformRecoveryIfNecessary(getConfiguration(),
+ configurator.getDatabaseTuningProperties(), System.out));
}
@Override
View
136 server/src/main/java/org/neo4j/server/InterruptThreadTimer.java
@@ -0,0 +1,136 @@
+/**
+ * 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 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.server;
+
+import java.util.Timer;
+import java.util.TimerTask;
+
+
+/**
+ * Interrupts a thread after a given timeout, can be cancelled if needed.
+ */
+public abstract class InterruptThreadTimer
+{
+
+ public static class InterruptThreadTask extends TimerTask
+ {
+ private Thread threadToInterrupt;
+ private boolean wasExecuted = false;
+
+ public InterruptThreadTask(Thread threadToInterrupt)
+ {
+ this.threadToInterrupt = threadToInterrupt;
+ }
+
+ @Override
+ public void run() {
+ wasExecuted = true;
+ threadToInterrupt.interrupt();
+ }
+
+ public boolean wasExecuted()
+ {
+ return this.wasExecuted;
+ }
+ }
+
+ public static InterruptThreadTimer createTimer(long timeoutMillis, Thread threadToInterrupt)
+ {
+ return new ActualInterruptThreadTimer(timeoutMillis, threadToInterrupt);
+ }
+
+ public static InterruptThreadTimer createNoOpTimer()
+ {
+ return new NoOpInterruptThreadTimer();
+ }
+
+ private static class ActualInterruptThreadTimer extends InterruptThreadTimer
+ {
+ private Timer timer = new Timer();
+ private final InterruptThreadTask task;
+ private long timeout;
+
+ public ActualInterruptThreadTimer(long timeoutMillis, Thread threadToInterrupt)
+ {
+ this.task = new InterruptThreadTask(threadToInterrupt);
+ this.timeout = timeoutMillis;
+ }
+
+ @Override
+ public void startCountdown()
+ {
+ timer.schedule(task, timeout);
+ }
+
+ @Override
+ public void stopCountdown()
+ {
+ timer.cancel();
+ }
+
+ @Override
+ public boolean wasTriggered()
+ {
+ return task.wasExecuted();
+ }
+
+ @Override
+ public long getTimeoutMillis() {
+ return timeout;
+ }
+ }
+
+ private static class NoOpInterruptThreadTimer extends InterruptThreadTimer
+ {
+
+ public NoOpInterruptThreadTimer()
+ {
+ }
+
+ @Override
+ public void startCountdown()
+ {
+
+ }
+
+ @Override
+ public void stopCountdown()
+ {
+
+ }
+
+ @Override
+ public boolean wasTriggered()
+ {
+ return false;
+ }
+
+ @Override
+ public long getTimeoutMillis() {
+ return 0;
+ }
+ }
+
+ public abstract void startCountdown();
+ public abstract void stopCountdown();
+ public abstract boolean wasTriggered();
+ public abstract long getTimeoutMillis();
+
+}
View
2  server/src/main/java/org/neo4j/server/ServerStartupException.java
@@ -23,7 +23,7 @@
* Thrown during start-up of the server, with an explicit error code.
*/
@SuppressWarnings( "serial" )
-public class ServerStartupException extends Exception
+public class ServerStartupException extends RuntimeException
{
private Integer errorCode;
View
6 server/src/main/java/org/neo4j/server/WrappingNeoServer.java
@@ -25,7 +25,7 @@
import org.neo4j.server.configuration.ServerConfigurator;
import org.neo4j.server.database.Database;
import org.neo4j.server.database.WrappedDatabase;
-import org.neo4j.server.startup.healthcheck.StartupHealthCheck;
+import org.neo4j.server.preflight.PreFlightTasks;
public class WrappingNeoServer extends CommunityNeoServer {
@@ -45,8 +45,8 @@ public WrappingNeoServer(GraphDatabaseAPI db, Configurator configurator)
}
@Override
- protected StartupHealthCheck createHealthCheck() {
- return new StartupHealthCheck();
+ protected PreFlightTasks createPreflightTasks() {
+ return new PreFlightTasks();
}
@Override
View
4 server/src/main/java/org/neo4j/server/configuration/Configurator.java
@@ -92,8 +92,12 @@
String DEFAULT_WEBSERVER_HTTPS_KEY_PATH = "neo4j-home/ssl/snakeoil.key";
String HTTP_LOGGING = "org.neo4j.server.http.log.enabled";
+ boolean DEFAULT_HTTP_LOGGING = false;
String HTTP_LOG_CONFIG_LOCATION = "org.neo4j.server.http.log.config";
String WADL_ENABLED = "unsupported_wadl_generation_enabled";
+
+ String STARTUP_TIMEOUT = "org.neo4j.server.startup_timeout";
+ int DEFAULT_STARTUP_TIMEOUT = 120;
Configuration configuration();
View
5 server/src/main/java/org/neo4j/server/configuration/ServerConfigurator.java
@@ -56,6 +56,11 @@ public ServerConfigurator( GraphDatabaseAPI db )
{
config.addProperty( DATABASE_LOCATION_PROPERTY_KEY, db.getStoreDir() );
}
+
+ public ServerConfigurator( String dbDir )
+ {
+ config.addProperty( DATABASE_LOCATION_PROPERTY_KEY, dbDir );
+ }
@Override
public Configuration configuration()
View
25 ...thcheck/Neo4jPropertiesMustExistRule.java → ...preflight/EnsureNeo4jPropertiesExist.java
@@ -17,27 +17,41 @@
* 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.server.startup.healthcheck;
+package org.neo4j.server.preflight;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.Properties;
+import org.apache.commons.configuration.Configuration;
import org.neo4j.server.configuration.Configurator;
-public class Neo4jPropertiesMustExistRule implements StartupHealthCheckRule
+public class EnsureNeo4jPropertiesExist implements PreflightTask
{
private static final String EMPTY_STRING = "";
private boolean passed = false;
private boolean ran = false;
protected String failureMessage = EMPTY_STRING;
+ private Configuration config;
+
+ public EnsureNeo4jPropertiesExist(Configuration config)
+ {
+ this.config = config;
+ }
- public boolean execute( Properties properties )
+ @Override
+ public boolean run()
{
ran = true;
- String configFilename = properties.getProperty( Configurator.NEO_SERVER_CONFIG_FILE_KEY );
+ String configFilename = config.getString( Configurator.NEO_SERVER_CONFIG_FILE_KEY );
+ if(configFilename == null)
+ {
+ failureMessage = String.format( "No server configuration file set, unable to load configuration. Expected system property '%s' to point to config file.", Configurator.NEO_SERVER_CONFIG_FILE_KEY );
+ return false;
+ }
+
Properties configProperties = new Properties();
FileInputStream inputStream = null;
try
@@ -74,7 +88,8 @@ protected boolean validateProperties( Properties configProperties )
return true;
}
- public String getFailureMessage()
+ @Override
+ public String getFailureMessage()
{
if ( passed )
{
View
20 ...lthcheck/HTTPLoggingPreparednessRule.java → ...eflight/EnsurePreparedForHttpLogging.java
@@ -17,37 +17,41 @@
* 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.server.startup.healthcheck;
+package org.neo4j.server.preflight;
import java.io.File;
import java.io.IOException;
-import java.util.Properties;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
+import org.apache.commons.configuration.Configuration;
import org.apache.commons.io.FileUtils;
import org.neo4j.server.configuration.Configurator;
import org.w3c.dom.Document;
import org.w3c.dom.Node;
-public class HTTPLoggingPreparednessRule implements StartupHealthCheckRule
+public class EnsurePreparedForHttpLogging implements PreflightTask
{
private String failureMessage = "";
+ private Configuration config;
+ public EnsurePreparedForHttpLogging(Configuration config)
+ {
+ this.config = config;
+ }
+
@Override
- public boolean execute( Properties properties )
+ public boolean run()
{
- boolean enabled = new Boolean( String.valueOf( properties.getProperty( Configurator.HTTP_LOGGING ) ) )
- .booleanValue();
+ boolean enabled = config.getBoolean( Configurator.HTTP_LOGGING, Configurator.DEFAULT_HTTP_LOGGING );
if ( !enabled )
{
return true;
}
- File logLocation = extractLogLocationFromConfig(
- String.valueOf( properties.get( Configurator.HTTP_LOG_CONFIG_LOCATION ) ) );
+ File logLocation = extractLogLocationFromConfig(config.getString( Configurator.HTTP_LOG_CONFIG_LOCATION ) );
if ( logLocation != null )
View
75 server/src/main/java/org/neo4j/server/preflight/PerformRecoveryIfNecessary.java
@@ -0,0 +1,75 @@
+/**
+ * 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 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.server.preflight;
+
+import java.io.File;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.Map;
+
+import org.apache.commons.configuration.Configuration;
+import org.neo4j.kernel.impl.recovery.StoreRecoverer;
+import org.neo4j.server.configuration.Configurator;
+import org.neo4j.server.logging.Logger;
+
+public class PerformRecoveryIfNecessary implements PreflightTask {
+
+ private final Logger logger = Logger.getLogger( PerformRecoveryIfNecessary.class );
+ private String failureMessage = "Unable to recover database";
+
+ private Configuration config;
+ private PrintStream out;
+ private Map<String, String> dbConfig;
+
+ public PerformRecoveryIfNecessary(Configuration serverConfig, Map<String,String> dbConfig, PrintStream out)
+ {
+ this.config = serverConfig;
+ this.dbConfig = dbConfig;
+ this.out = out;
+ }
+
+ @Override
+ public boolean run() {
+ try {
+ File dbLocation = new File( config.getString( Configurator.DATABASE_LOCATION_PROPERTY_KEY ) );
+ if(dbLocation.exists())
+ {
+ StoreRecoverer recoverer = new StoreRecoverer();
+
+ if(recoverer.recoveryNeededAt(dbLocation, dbConfig))
+ {
+ out.println("Detected incorrectly shut down database, performing recovery..");
+ recoverer.recover(dbLocation, dbConfig);
+ }
+ }
+
+ return true;
+ } catch(IOException e) {
+ logger.error("Recovery startup task failed.", e);
+ return false;
+ }
+ }
+
+ @Override
+ public String getFailureMessage() {
+ return failureMessage;
+ }
+
+}
View
90 ...oremigration/PreStartupStoreUpgrader.java → .../preflight/PerformUpgradeIfNecessary.java
@@ -17,15 +17,13 @@
* 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.server.storemigration;
+package org.neo4j.server.preflight;
import java.io.File;
-import java.io.IOException;
import java.io.PrintStream;
-import java.util.HashMap;
-import java.util.Properties;
+import java.util.Map;
+import org.apache.commons.configuration.Configuration;
import org.neo4j.graphdb.factory.GraphDatabaseSettings;
import org.neo4j.kernel.DefaultFileSystemAbstraction;
import org.neo4j.kernel.DefaultIdGeneratorFactory;
@@ -43,63 +41,48 @@
import org.neo4j.kernel.impl.storemigration.monitoring.VisibleMigrationProgressMonitor;
import org.neo4j.kernel.impl.util.StringLogger;
import org.neo4j.server.configuration.Configurator;
-import org.neo4j.server.configuration.PropertyFileConfigurator;
-import org.neo4j.server.configuration.validation.DatabaseLocationMustBeSpecifiedRule;
-import org.neo4j.server.configuration.validation.Validator;
import org.neo4j.server.logging.Logger;
-public class PreStartupStoreUpgrader
-{
- public static void main( String[] args ) throws IOException
- {
- PreStartupStoreUpgrader preStartupStoreUpgrader =
- new PreStartupStoreUpgrader( System.getProperties(), System.out );
- int exit = preStartupStoreUpgrader.run();
- if ( exit != 0 )
- {
- System.exit( exit );
- }
- }
+public class PerformUpgradeIfNecessary implements PreflightTask {
- private final Logger logger = Logger.getLogger( PreStartupStoreUpgrader.class );
- private Properties systemProperties;
- private PrintStream out;
+ private final Logger logger = Logger.getLogger( PerformUpgradeIfNecessary.class );
+ private String failureMessage = "Unable to upgrade database";
+ private Configuration config;
+ private PrintStream out;
+ private Map<String, String> dbConfig;
- public PreStartupStoreUpgrader( Properties systemProperties, PrintStream out )
- {
- this.systemProperties = systemProperties;
- this.out = out;
- }
-
- public int run()
- {
- try
+ public PerformUpgradeIfNecessary(Configuration serverConfig, Map<String,String> dbConfig, PrintStream out)
+ {
+ this.config = serverConfig;
+ this.dbConfig = dbConfig;
+ this.out = out;
+ }
+
+ @Override
+ public boolean run() {
+ try
{
- Configurator configurator = getConfigurator();
- HashMap<String, String> config = new HashMap<String, String>( configurator.getDatabaseTuningProperties() );
-
- String dbLocation = new File( configurator.configuration()
- .getString( Configurator.DATABASE_LOCATION_PROPERTY_KEY ) ).getAbsolutePath();
+ String dbLocation = new File( config.getString( Configurator.DATABASE_LOCATION_PROPERTY_KEY ) ).getAbsolutePath();
if ( new CurrentDatabase().storeFilesAtCurrentVersion( new File( dbLocation ) ) )
{
- return 0;
+ return true;
}
String separator = System.getProperty( "file.separator" );
String store = dbLocation + separator + NeoStore.DEFAULT_NAME;
- config.put( "store_dir", dbLocation );
- config.put( "neo_store", store );
+ dbConfig.put( "store_dir", dbLocation );
+ dbConfig.put( "neo_store", store );
if ( !new UpgradableDatabase().storeFilesUpgradeable( new File( store ) ) )
{
logger.info( "Store files missing, or not in suitable state for upgrade. " +
"Leaving this problem for main server process to resolve." );
- return 0;
+ return true;
}
FileSystemAbstraction fileSystem = new DefaultFileSystemAbstraction();
- Config conf = new Config(new ConfigurationDefaults(GraphDatabaseSettings.class ).apply(config) );
+ Config conf = new Config(new ConfigurationDefaults(GraphDatabaseSettings.class ).apply(dbConfig) );
StoreUpgrader storeUpgrader = new StoreUpgrader( conf, StringLogger.SYSTEM,new ConfigMapUpgradeConfiguration( conf ),
new UpgradableDatabase(), new StoreMigrator( new VisibleMigrationProgressMonitor( out ) ),
new DatabaseFiles(), new DefaultIdGeneratorFactory(), fileSystem );
@@ -111,28 +94,27 @@ public int run()
catch ( UpgradeNotAllowedByConfigurationException e )
{
logger.info( e.getMessage() );
- out.println( e.getMessage() );
- return 1;
+ out.println(e.getMessage());
+ failureMessage = e.getMessage();
+ return false;
}
catch ( StoreUpgrader.UnableToUpgradeException e )
{
logger.error( e );
- return 1;
+ return false;
}
- return 0;
+ return true;
}
catch ( Exception e )
{
logger.error( e );
- return 1;
+ return false;
}
- }
+ }
- protected Configurator getConfigurator()
- {
- File configFile = new File( systemProperties.getProperty( Configurator.NEO_SERVER_CONFIG_FILE_KEY,
- Configurator.DEFAULT_CONFIG_DIR ) );
- return new PropertyFileConfigurator( new Validator( new DatabaseLocationMustBeSpecifiedRule() ), configFile );
- }
+ @Override
+ public String getFailureMessage() {
+ return failureMessage;
+ }
}
View
85 server/src/main/java/org/neo4j/server/preflight/PreFlightTasks.java
@@ -0,0 +1,85 @@
+/**
+ * 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 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.server.preflight;
+
+import org.neo4j.server.logging.Logger;
+
+/**
+ * These are tasks that are run on server startup that may take a long time
+ * to execute, such as recovery, upgrades and so on.
+ *
+ * This implementation still needs some work, because of some of the refactoring
+ * done regarding the NeoServer. Specifically, some of these tasks verify that
+ * properties files exist and are valid. Other preflight tasks we might want to
+ * add could be auto-generating config files if they don't exist and creating required
+ * directories.
+ *
+ * All of these (including auto-generating neo4j.properties and creating directories)
+ * except validating and potentially generating neo4j-server.properties depend on having
+ * the server configuration available. Eg. we can't both ensure that file exists within these
+ * tests, while at the same time depending on that file existing.
+ *
+ * The validation is not a problem, because we will refactor the server config to use the
+ * new configuration system from the kernel, which automatically validates itself.
+ *
+ * Ensuring the config file exists (and potentially auto-generating it) is a problem.
+ * Either this need to be split into tasks that have dependencies, and tasks that don't.
+ *
+ * Although, it seems it is only this one edge case, so perhaps accepting that and adding
+ * code to the bootstrapper to ensure the config file exists is acceptable.
+ */
+public class PreFlightTasks
+{
+ public static final Logger log = Logger.getLogger( PreFlightTasks.class );
+
+ private final PreflightTask[] tasks;
+
+ private PreflightTask failedTask = null;
+
+ public PreFlightTasks(PreflightTask... tasks)
+ {
+ this.tasks = tasks;
+ }
+
+ public boolean run()
+ {
+ if ( tasks == null || tasks.length < 1 )
+ {
+ return true;
+ }
+
+ for ( PreflightTask r : tasks )
+ {
+ if ( !r.run() )
+ {
+ log.error( r.getFailureMessage() );
+ failedTask = r;
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+ public PreflightTask failedTask()
+ {
+ return failedTask;
+ }
+}
View
14 ...BeSpecifiedAsASystemPropertyRuleTest.java → ...r/preflight/PreflightFailedException.java
@@ -17,16 +17,14 @@
* 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.server.startup.healthcheck;
+package org.neo4j.server.preflight;
-import org.junit.Test;
-
-public class ConfigFileMustBeSpecifiedAsASystemPropertyRuleTest
+@SuppressWarnings( "serial" )
+public class PreflightFailedException extends RuntimeException
{
- @Test
- public void shouldFailWhenSystemPropertyNotSet()
+ public PreflightFailedException( PreflightTask task )
{
-
+ super( String.format( "Startup failed due to preflight task [%s]: %s", task.getClass(),
+ task.getFailureMessage() ) );
}
-
}
View
7 ...p/healthcheck/StartupHealthCheckRule.java → ...neo4j/server/preflight/PreflightTask.java
@@ -17,13 +17,12 @@
* 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.server.startup.healthcheck;
+package org.neo4j.server.preflight;
-import java.util.Properties;
-public interface StartupHealthCheckRule
+public interface PreflightTask
{
- public boolean execute( Properties properties );
+ public boolean run();
public String getFailureMessage();
}
View
74 server/src/main/java/org/neo4j/server/startup/healthcheck/ConfigFileMustBePresentRule.java
@@ -1,74 +0,0 @@
-/**
- * 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 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.server.startup.healthcheck;
-
-import java.io.File;
-import java.util.Properties;
-
-import org.neo4j.server.configuration.Configurator;
-
-public class ConfigFileMustBePresentRule implements StartupHealthCheckRule
-{
- private static final String EMPTY_STRING = "";
- private boolean passed = false;
- private boolean ran = false;
- private String failureMessage = EMPTY_STRING;
-
- public boolean execute( Properties properties )
- {
- ran = true;
-
- String configFilename = properties.getProperty( Configurator.NEO_SERVER_CONFIG_FILE_KEY );
-
- if ( configFilename == null )
- {
- failureMessage = String.format( "Property [%s] has not been set.", Configurator.NEO_SERVER_CONFIG_FILE_KEY );
-
- return false;
- }
-
- File configFile = new File( configFilename );
- if ( !configFile.exists() )
- {
- failureMessage = String.format( "No configuration file at [%s]", configFile.getAbsoluteFile() );
- return false;
- }
-
- passed = true;
- return passed;
- }
-
- public String getFailureMessage()
- {
- if ( passed )
- {
- return EMPTY_STRING;
- }
-
- if ( !ran )
- {
- return String.format( "%s has not been run", getClass().getName() );
- }
- else
- {
- return failureMessage;
- }
- }
-}
View
70 server/src/main/java/org/neo4j/server/startup/healthcheck/StartupHealthCheck.java
@@ -1,70 +0,0 @@
-/**
- * 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 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.server.startup.healthcheck;
-
-import java.util.Properties;
-
-import org.neo4j.server.logging.Logger;
-
-public class StartupHealthCheck
-{
- public static final Logger log = Logger.getLogger( StartupHealthCheck.class );
-
- private final StartupHealthCheckRule[] rules;
-
- private StartupHealthCheckRule failedRule = null;
- private final Properties properties;
-
- public StartupHealthCheck( Properties properties , StartupHealthCheckRule... rules)
- {
- this.rules = rules;
- this.properties = properties;
- }
-
- public StartupHealthCheck( StartupHealthCheckRule... rules )
- {
- this(System.getProperties(), rules);
- }
-
- public boolean run()
- {
- if ( rules == null || rules.length < 1 )
- {
- return true;
- }
-
- for ( StartupHealthCheckRule r : rules )
- {
- if ( !r.execute( properties ) )
- {
- log.error( r.getFailureMessage() );
- failedRule = r;
- return false;
- }
- }
-
- return true;
- }
-
- public StartupHealthCheckRule failedRule()
- {
- return failedRule;
- }
-}
View
45 ...ck/StartupHealthCheckFailedException.java → ...eo4j/server/TestInterruptThreadTimer.java
@@ -17,14 +17,41 @@
* 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.server.startup.healthcheck;
+package org.neo4j.server;
-@SuppressWarnings( "serial" )
-public class StartupHealthCheckFailedException extends RuntimeException
-{
- public StartupHealthCheckFailedException( StartupHealthCheckRule failedRule )
- {
- super( String.format( "Startup health check failed due to rule [%s]. %s", failedRule.getClass(),
- failedRule.getFailureMessage() ) );
- }
+import static org.junit.Assert.fail;
+
+import org.junit.Test;
+
+
+public class TestInterruptThreadTimer {
+
+ @Test
+ public void shouldInterruptIfTimeoutIsReached()
+ {
+ try {
+ InterruptThreadTimer timer = InterruptThreadTimer.createTimer(100, Thread.currentThread());
+ timer.startCountdown();
+ Thread.sleep(3000);
+ fail("Should have been interrupted.");
+ } catch(InterruptedException e)
+ {
+ // ok
+ }
+ }
+
+ @Test
+ public void shouldNotInterruptIfTimeoutIsNotReached()
+ {
+ try {
+ InterruptThreadTimer timer = InterruptThreadTimer.createTimer(1000 * 10, Thread.currentThread());
+ timer.startCountdown();
+ Thread.sleep(1);
+ timer.stopCountdown();
+ } catch(InterruptedException e)
+ {
+ fail("Should not have been interrupted.");
+ }
+ }
+
}
View
28 server/src/test/java/org/neo4j/server/helpers/ServerBuilder.java
@@ -45,11 +45,11 @@
import org.neo4j.server.database.CommunityDatabase;
import org.neo4j.server.database.Database;
import org.neo4j.server.database.EphemeralDatabase;
+import org.neo4j.server.preflight.PreFlightTasks;
+import org.neo4j.server.preflight.PreflightTask;
import org.neo4j.server.rest.paging.Clock;
import org.neo4j.server.rest.paging.FakeClock;
import org.neo4j.server.rest.paging.LeaseManagerProvider;
-import org.neo4j.server.startup.healthcheck.StartupHealthCheck;
-import org.neo4j.server.startup.healthcheck.StartupHealthCheckRule;
public class ServerBuilder
{
@@ -58,7 +58,7 @@
protected String dbDir = null;
private String webAdminUri = "/db/manage/";
private String webAdminDataUri = "/db/data/";
- protected StartupHealthCheck startupHealthCheck;
+ protected PreFlightTasks preflightTasks;
private final HashMap<String, String> thirdPartyPackages = new HashMap<String, String>();
private final Properties arbitraryProperties = new Properties();
@@ -91,9 +91,9 @@ public CommunityNeoServer build() throws IOException
}
File configFile = createPropertiesFiles();
- if ( startupHealthCheck == null )
+ if ( preflightTasks == null )
{
- startupHealthCheck = new StartupHealthCheck()
+ preflightTasks = new PreFlightTasks()
{
@Override
public boolean run()
@@ -111,8 +111,8 @@ public boolean run()
return new CommunityNeoServer(new PropertyFileConfigurator( new Validator( new DatabaseLocationMustBeSpecifiedRule() ), configFile ))
{
@Override
- protected StartupHealthCheck createHealthCheck() {
- return startupHealthCheck;
+ protected PreFlightTasks createPreflightTasks() {
+ return preflightTasks;
}
@Override
@@ -319,9 +319,9 @@ public ServerBuilder withoutWebServerPort()
return this;
}
- public ServerBuilder withFailingStartupHealthcheck()
+ public ServerBuilder withFailingPreflightTasks()
{
- startupHealthCheck = new StartupHealthCheck()
+ preflightTasks = new PreFlightTasks()
{
@Override
public boolean run()
@@ -330,9 +330,9 @@ public boolean run()
}
@Override
- public StartupHealthCheckRule failedRule()
+ public PreflightTask failedTask()
{
- return new StartupHealthCheckRule()
+ return new PreflightTask()
{
@Override
@@ -342,7 +342,7 @@ public String getFailureMessage()
}
@Override
- public boolean execute( Properties properties )
+ public boolean run()
{
return false;
}
@@ -418,9 +418,9 @@ public ServerBuilder withProperty( String key, String value )
return this;
}
- public ServerBuilder withStartupHealthCheckRules( StartupHealthCheckRule... rules )
+ public ServerBuilder withPreflightTasks( PreflightTask... tasks )
{
- this.startupHealthCheck = new StartupHealthCheck( arbitraryProperties, rules );
+ this.preflightTasks = new PreFlightTasks( tasks );
return this;
}
}
View
43 ...heck/HTTPLoggingPreparednessRuleTest.java → ...ight/HTTPLoggingPreparednessRuleTest.java
@@ -17,7 +17,7 @@
* 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.server.startup.healthcheck;
+package org.neo4j.server.preflight;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
@@ -28,12 +28,13 @@
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.util.Properties;
import java.util.UUID;
+import org.apache.commons.configuration.Configuration;
import org.apache.commons.lang.StringUtils;
import org.junit.Test;
import org.neo4j.server.configuration.Configurator;
+import org.neo4j.server.configuration.MapBasedConfiguration;
import org.neo4j.test.TargetDirectory;
public class HTTPLoggingPreparednessRuleTest
@@ -42,12 +43,12 @@
public void shouldPassWhenExplicitlyDisabled()
{
// given
- HTTPLoggingPreparednessRule rule = new HTTPLoggingPreparednessRule();
- final Properties properties = new Properties();
- properties.put( Configurator.HTTP_LOGGING, "false" );
+ Configuration config = new MapBasedConfiguration();
+ config.setProperty( Configurator.HTTP_LOGGING, "false" );
+ EnsurePreparedForHttpLogging rule = new EnsurePreparedForHttpLogging(config);
// when
- boolean result = rule.execute( properties );
+ boolean result = rule.run( );
// then
assertTrue( result );
@@ -58,11 +59,11 @@ public void shouldPassWhenExplicitlyDisabled()
public void shouldPassWhenImplicitlyDisabled()
{
// given
- HTTPLoggingPreparednessRule rule = new HTTPLoggingPreparednessRule();
- final Properties properties = new Properties();
+ Configuration config = new MapBasedConfiguration();
+ EnsurePreparedForHttpLogging rule = new EnsurePreparedForHttpLogging(config);
// when
- boolean result = rule.execute( properties );
+ boolean result = rule.run( );
// then
assertTrue( result );
@@ -76,15 +77,14 @@ public void shouldPassWhenEnabledWithGoodConfigSpecified() throws Exception
final File logDir = TargetDirectory.forTest( this.getClass() ).directory( "logDir" );
final File confDir = TargetDirectory.forTest( this.getClass() ).directory( "confDir" );
-
- HTTPLoggingPreparednessRule rule = new HTTPLoggingPreparednessRule();
- final Properties properties = new Properties();
- properties.put( Configurator.HTTP_LOGGING, "true" );
- properties.put( Configurator.HTTP_LOG_CONFIG_LOCATION,
- createConfigFile( createLogbackConfigXml( logDir ), confDir ).getAbsolutePath() );
+ Configuration config = new MapBasedConfiguration();
+ config.setProperty( Configurator.HTTP_LOGGING, "true" );
+ config.setProperty( Configurator.HTTP_LOG_CONFIG_LOCATION,
+ createConfigFile( createLogbackConfigXml( logDir ), confDir ).getAbsolutePath() );
+ EnsurePreparedForHttpLogging rule = new EnsurePreparedForHttpLogging(config);
// when
- boolean result = rule.execute( properties );
+ boolean result = rule.run( );
// then
assertTrue( result );
@@ -97,16 +97,15 @@ public void shouldFailWhenEnabledWithUnwritableLogDirSpecifiedInConfig() throws
// given
final File confDir = TargetDirectory.forTest( this.getClass() ).directory( "confDir" );
-
- HTTPLoggingPreparednessRule rule = new HTTPLoggingPreparednessRule();
- final Properties properties = new Properties();
- properties.put( Configurator.HTTP_LOGGING, "true" );
+ Configuration config = new MapBasedConfiguration();
+ config.setProperty( Configurator.HTTP_LOGGING, "true" );
final File unwritableDirectory = createUnwritableDirectory();
- properties.put( Configurator.HTTP_LOG_CONFIG_LOCATION,
+ config.setProperty( Configurator.HTTP_LOG_CONFIG_LOCATION,
createConfigFile( createLogbackConfigXml( unwritableDirectory ), confDir ).getAbsolutePath() );
+ EnsurePreparedForHttpLogging rule = new EnsurePreparedForHttpLogging(config);
// when
- boolean result = rule.execute( properties );
+ boolean result = rule.run( );
// then
assertFalse( result );
View
113 server/src/test/java/org/neo4j/server/preflight/TestPerformRecoveryIfNecessary.java
@@ -0,0 +1,113 @@
+/**
+ * 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 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.server.preflight;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.junit.Assert.assertThat;
+
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.util.HashMap;
+import java.util.Properties;
+
+import org.apache.commons.configuration.Configuration;
+import org.junit.Test;
+import org.neo4j.graphdb.factory.GraphDatabaseFactory;
+import org.neo4j.kernel.impl.recovery.StoreRecoverer;
+import org.neo4j.kernel.impl.util.FileUtils;
+import org.neo4j.server.configuration.Configurator;
+import org.neo4j.server.configuration.MapBasedConfiguration;
+
+public class TestPerformRecoveryIfNecessary {
+
+ public static final String HOME_DIRECTORY = "target/" + TestPerformRecoveryIfNecessary.class.getSimpleName();
+ public static final String STORE_DIRECTORY = HOME_DIRECTORY + "/data/graph.db";
+
+ @Test
+ public void shouldNotDoAnythingIfNoDBPresent() throws Exception
+ {
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ Configuration config = buildProperties();
+ PerformRecoveryIfNecessary task = new PerformRecoveryIfNecessary(config, new HashMap<String,String>(), new PrintStream(outputStream));
+
+ assertThat("Recovery task runs successfully.", task.run(), is(true));
+ assertThat("No database should have been created.", new File(STORE_DIRECTORY).exists(), is(false));
+ assertThat("Recovery task should not print anything.", outputStream.toString(), is(""));
+ }
+
+ @Test
+ public void doesNotPrintAnythingIfDatabaseWasCorrectlyShutdown() throws Exception
+ {
+ // Given
+ Configuration config = buildProperties();
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ new GraphDatabaseFactory().newEmbeddedDatabase(STORE_DIRECTORY).shutdown();
+
+ PerformRecoveryIfNecessary task = new PerformRecoveryIfNecessary(config, new HashMap<String,String>(), new PrintStream(outputStream));
+
+ assertThat("Recovery task should run successfully.", task.run(), is(true));
+ assertThat("Database should exist.", new File(STORE_DIRECTORY).exists(), is(true));
+ assertThat("Recovery should not print anything.", outputStream.toString(), is(""));
+ }
+
+ @Test
+ public void shouldPerformRecoveryIfNecessary() throws Exception
+ {
+ // Given
+ StoreRecoverer recoverer = new StoreRecoverer();
+ Configuration config = buildProperties();
+ ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
+ new GraphDatabaseFactory().newEmbeddedDatabase(STORE_DIRECTORY).shutdown();
+ // Make this look incorrectly shut down
+ new File(STORE_DIRECTORY, "nioneo_logical.log.active").delete();
+
+ assertThat("Store should not be recovered", recoverer.recoveryNeededAt(new File(STORE_DIRECTORY), new HashMap<String,String>()),
+ is(true));
+
+ // Run recovery
+ PerformRecoveryIfNecessary task = new PerformRecoveryIfNecessary(config, new HashMap<String,String>(), new PrintStream(outputStream));
+ assertThat("Recovery task should run successfully.", task.run(), is(true));
+ assertThat("Database should exist.", new File(STORE_DIRECTORY).exists(), is(true));
+ assertThat("Recovery should print status message.", outputStream.toString(), is("Detected incorrectly shut down database, performing recovery..\n"));
+ assertThat("Store should be recovered", recoverer.recoveryNeededAt(new File(STORE_DIRECTORY), new HashMap<String,String>()),
+ is(false));
+ }
+
+ private Configuration buildProperties() throws IOException
+ {
+ FileUtils.deleteRecursively( new File( HOME_DIRECTORY ) );
+ new File( HOME_DIRECTORY + "/conf" ).mkdirs();
+
+ Properties databaseProperties = new Properties();
+
+ String databasePropertiesFileName = HOME_DIRECTORY + "/conf/neo4j.properties";
+ databaseProperties.store( new FileWriter( databasePropertiesFileName ), null );
+
+ Configuration serverProperties = new MapBasedConfiguration();
+ serverProperties.setProperty( Configurator.DATABASE_LOCATION_PROPERTY_KEY, STORE_DIRECTORY );
+ serverProperties.setProperty( Configurator.DB_TUNING_PROPERTY_FILE_KEY, databasePropertiesFileName );
+
+ return serverProperties;
+ }
+
+}
View
75 ...igration/PreStartupStoreUpgraderTest.java → ...flight/TestPerformUpgradeIfNecessary.java
@@ -17,9 +17,11 @@
* 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.server.storemigration;
+package org.neo4j.server.preflight;
+import static org.hamcrest.CoreMatchers.is;
import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
import static org.neo4j.kernel.impl.util.FileUtils.copyRecursively;
import static org.neo4j.kernel.impl.util.FileUtils.deleteRecursively;
@@ -30,32 +32,36 @@
import java.io.IOException;
import java.io.PrintStream;
import java.net.URL;
+import java.util.Map;
import java.util.Properties;
+import org.apache.commons.configuration.Configuration;
import org.junit.Test;
import org.neo4j.graphdb.factory.GraphDatabaseFactory;
import org.neo4j.graphdb.factory.GraphDatabaseSettings;
+import org.neo4j.helpers.collection.MapUtil;
import org.neo4j.kernel.impl.util.FileUtils;
import org.neo4j.server.configuration.Configurator;
+import org.neo4j.server.configuration.MapBasedConfiguration;
-public class PreStartupStoreUpgraderTest
+public class TestPerformUpgradeIfNecessary
{
- public static final String HOME_DIRECTORY = "target/" + PreStartupStoreUpgraderTest.class.getSimpleName();
+ public static final String HOME_DIRECTORY = "target/" + TestPerformUpgradeIfNecessary.class.getSimpleName();
public static final String STORE_DIRECTORY = HOME_DIRECTORY + "/data/graph.db";
@Test
public void shouldExitImmediatelyIfStoreIsAlreadyAtLatestVersion() throws IOException
{
- Properties systemProperties = buildProperties( false );
+ Configuration serverConfig = buildProperties( false );
new GraphDatabaseFactory().newEmbeddedDatabaseBuilder( STORE_DIRECTORY ).newGraphDatabase().shutdown();
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- PreStartupStoreUpgrader upgrader = new PreStartupStoreUpgrader( systemProperties,
- new PrintStream( outputStream ) );
+ PerformUpgradeIfNecessary upgrader = new PerformUpgradeIfNecessary( serverConfig,
+ loadNeo4jProperties(), new PrintStream( outputStream ) );
- int exit = upgrader.run();
+ boolean exit = upgrader.run();
- assertEquals( 0, exit );
+ assertEquals( true, exit );
assertEquals( "", new String( outputStream.toByteArray() ) );
}
@@ -63,20 +69,21 @@ public void shouldExitImmediatelyIfStoreIsAlreadyAtLatestVersion() throws IOExce
@Test
public void shouldGiveHelpfulMessageIfAutoUpgradeParameterNotSet() throws IOException
{
- Properties systemProperties = buildProperties( false );
+ Configuration serverProperties = buildProperties( false );
prepareSampleLegacyDatabase( new File( STORE_DIRECTORY ) );
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- PreStartupStoreUpgrader upgrader = new PreStartupStoreUpgrader( systemProperties,
- new PrintStream( outputStream ) );
+ PerformUpgradeIfNecessary upgrader = new PerformUpgradeIfNecessary( serverProperties,
+ loadNeo4jProperties(), new PrintStream( outputStream ) );
- int exit = upgrader.run();
-
- assertEquals( 1, exit );
+ boolean exit = upgrader.run();
+ assertEquals( false, exit );
+
String[] lines = new String( outputStream.toByteArray() ).split( "\\r?\\n" );
- assertTrue( lines[0].contains( "To enable automatic upgrade, please set configuration parameter " +
- "\"allow_store_upgrade=true\"" ) );
+ assertThat( "'" + lines[0] + "' contains '" + "To enable automatic upgrade, please set configuration parameter " +
+ "\"allow_store_upgrade=true\"", lines[0].contains("To enable automatic upgrade, please set configuration parameter " +
+ "\"allow_store_upgrade=true\""), is(true) );
}
@Test
@@ -84,12 +91,12 @@ public void shouldExitCleanlyIfDatabaseMissingSoThatDatabaseCreationIsLeftToMain
{
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- PreStartupStoreUpgrader upgrader = new PreStartupStoreUpgrader( buildProperties( true ),
- new PrintStream( outputStream ) );
+ PerformUpgradeIfNecessary upgrader = new PerformUpgradeIfNecessary( buildProperties( true ),
+ loadNeo4jProperties(), new PrintStream( outputStream ) );
- int exit = upgrader.run();
+ boolean exit = upgrader.run();
- assertEquals( 0, exit );
+ assertEquals( true, exit );
assertEquals( "", new String( outputStream.toByteArray() ) );
}
@@ -97,16 +104,16 @@ public void shouldExitCleanlyIfDatabaseMissingSoThatDatabaseCreationIsLeftToMain
@Test
public void shouldUpgradeDatabase() throws IOException
{
- Properties systemProperties = buildProperties( true );
+ Configuration serverConfig = buildProperties( true );
prepareSampleLegacyDatabase( new File( STORE_DIRECTORY ) );
ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
- PreStartupStoreUpgrader upgrader = new PreStartupStoreUpgrader( systemProperties,
- new PrintStream( outputStream ) );
+ PerformUpgradeIfNecessary upgrader = new PerformUpgradeIfNecessary( serverConfig,
+ loadNeo4jProperties(), new PrintStream( outputStream ) );
- int exit = upgrader.run();
+ boolean exit = upgrader.run();
- assertEquals( 0, exit );
+ assertEquals( true, exit );
String[] lines = new String( outputStream.toByteArray() ).split( "\\r?\\n" );
assertEquals( "Starting upgrade of database store files", lines[0] );
@@ -114,7 +121,7 @@ public void shouldUpgradeDatabase() throws IOException
assertEquals( "Finished upgrade of database store files", lines[2] );
}
- private Properties buildProperties(boolean allowStoreUpgrade) throws IOException
+ private Configuration buildProperties(boolean allowStoreUpgrade) throws IOException
{
FileUtils.deleteRecursively( new File( HOME_DIRECTORY ) );
new File( HOME_DIRECTORY + "/conf" ).mkdirs();
@@ -127,15 +134,17 @@ private Properties buildProperties(boolean allowStoreUpgrade) throws IOException
String databasePropertiesFileName = HOME_DIRECTORY + "/conf/neo4j.properties";
databaseProperties.store( new FileWriter( databasePropertiesFileName ), null );
- Properties serverProperties = new Properties();
+ Configuration serverProperties = new MapBasedConfiguration();
serverProperties.setProperty( Configurator.DATABASE_LOCATION_PROPERTY_KEY, STORE_DIRECTORY );
serverProperties.setProperty( Configurator.DB_TUNING_PROPERTY_FILE_KEY, databasePropertiesFileName );
- String serverPropertiesFileName = HOME_DIRECTORY + "/conf/neo4j-server.properties";
- serverProperties.store( new FileWriter( serverPropertiesFileName ), null );
- Properties systemProperties = new Properties();
- systemProperties.put( Configurator.NEO_SERVER_CONFIG_FILE_KEY, serverPropertiesFileName );
- return systemProperties;
+ return serverProperties;
+ }
+
+ private Map<String,String> loadNeo4jProperties() throws IOException
+ {
+ String databasePropertiesFileName = HOME_DIRECTORY + "/conf/neo4j.properties";
+ return MapUtil.load(new File(databasePropertiesFileName));
}
public static void prepareSampleLegacyDatabase( File workingDirectory ) throws IOException
@@ -150,7 +159,7 @@ public static void prepareSampleLegacyDatabase( File workingDirectory ) throws I
public static File findOldFormatStoreDirectory()
{
- URL legacyStoreResource = PreStartupStoreUpgraderTest.class.getResource( "legacystore/exampledb/neostore" );
+ URL legacyStoreResource = TestPerformUpgradeIfNecessary.class.getResource( "legacystore/exampledb/neostore" );
return new File( legacyStoreResource.getFile() ).getParentFile();
}
View
42 ...p/healthcheck/StartupHealthCheckTest.java → .../server/preflight/TestPreflightTasks.java
@@ -17,7 +17,7 @@
* 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.server.startup.healthcheck;
+package org.neo4j.server.preflight;
import static org.hamcrest.Matchers.containsString;
import static org.junit.Assert.assertFalse;
@@ -25,40 +25,40 @@
import static org.junit.Assert.assertThat;
import static org.junit.Assert.assertTrue;
-import java.util.Properties;
-
import org.junit.Test;
import org.neo4j.server.logging.InMemoryAppender;
+import org.neo4j.server.preflight.PreFlightTasks;
+import org.neo4j.server.preflight.PreflightTask;
-public class StartupHealthCheckTest
+public class TestPreflightTasks
{
@Test
public void shouldPassWithNoRules()
{
- StartupHealthCheck check = new StartupHealthCheck();
+ PreFlightTasks check = new PreFlightTasks();
assertTrue( check.run() );
}
@Test
public void shouldRunAllHealthChecksToCompletionIfNonFail()
{
- StartupHealthCheck check = new StartupHealthCheck( getPassingRules() );
+ PreFlightTasks check = new PreFlightTasks( getPassingRules() );
assertTrue( check.run() );