Skip to content

Commit

Permalink
Modify the ArbiterBootstrapper to conform to the Bootstrapper interface
Browse files Browse the repository at this point in the history
  • Loading branch information
benbc committed Mar 16, 2016
1 parent f484355 commit a86ad8e
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 131 deletions.
Expand Up @@ -25,16 +25,13 @@
import java.util.List;
import java.util.Map;

import org.neo4j.dbms.DatabaseManagementSystemSettings;
import org.neo4j.graphdb.factory.GraphDatabaseSettings;
import org.neo4j.helpers.collection.MapUtil;
import org.neo4j.helpers.collection.Pair;
import org.neo4j.kernel.configuration.Config;
import org.neo4j.logging.Log;
import org.neo4j.shell.ShellSettings;

import static java.util.Arrays.asList;

import static org.neo4j.kernel.configuration.Settings.TRUE;

public class ConfigLoader
Expand Down Expand Up @@ -64,11 +61,6 @@ public Config loadConfig( File configFile, File legacyConfigFile, Log log, Pair<
return config;
}

protected Iterable<Class<?>> settingsClasses( HashMap<String, String> settings )
{
return asList( ServerSettings.class, GraphDatabaseSettings.class, DatabaseManagementSystemSettings.class );
}

private HashMap<String, String> calculateSettings( File configFile, File legacyConfigFile, Log log,
Pair<String, String>[] configOverrides )
{
Expand Down
Expand Up @@ -32,8 +32,8 @@
import org.neo4j.cluster.client.ClusterClientModule;
import org.neo4j.cluster.protocol.election.NotElectableElectionCredentialsProvider;
import org.neo4j.function.Predicates;
import org.neo4j.helpers.Args;
import org.neo4j.helpers.collection.MapUtil;
import org.neo4j.helpers.collection.Pair;
import org.neo4j.io.fs.DefaultFileSystemAbstraction;
import org.neo4j.io.fs.FileSystemAbstraction;
import org.neo4j.kernel.configuration.Config;
Expand All @@ -45,50 +45,47 @@
import org.neo4j.kernel.lifecycle.LifecycleException;
import org.neo4j.kernel.monitoring.Monitors;
import org.neo4j.logging.FormattedLogProvider;
import org.neo4j.server.Bootstrapper;
import org.neo4j.server.configuration.ServerSettings;

import static org.neo4j.helpers.Exceptions.peel;

public class ArbiterBootstrapper implements AutoCloseable
public class ArbiterBootstrapper implements Bootstrapper, AutoCloseable
{
private final LifeSupport life = new LifeSupport();
private final Timer timer;
private final Timer timer = new Timer( true );

public ArbiterBootstrapper( Config config ) throws IOException
public static void main( String[] args ) throws IOException
{
start( config );

timer = new Timer( true );
addShutdownHook();
life.start();
int status = new ArbiterBootstrapper().start( getConfigFile() );
if ( status != 0 )
{
System.exit( status );
}
}

protected void addShutdownHook()
static File getConfigFile()
{
Runtime.getRuntime().addShutdownHook( new Thread()
String configPath = System.getProperty( ServerSettings.SERVER_CONFIG_FILE_KEY );
if ( configPath == null )
{
@Override
public void run()
{
// ClusterJoin will block on a Future.get(), which will prevent it to shutdown.
// Adding a timer here in case a shutdown is requested before cluster join has succeeded. Otherwise
// the deadlock will prevent the shutdown from finishing.
timer.schedule( new TimerTask()
{
@Override
public void run()
{
System.err.println( "Failed to stop in a reasonable time, terminating..." );
Runtime.getRuntime().halt( 1 );
}
}, 4_000L);
life.shutdown();
}
} );
throw new RuntimeException( "System property " + ServerSettings.SERVER_CONFIG_FILE_KEY +
" must be provided" );
}

File configFile = new File( configPath );
if ( !configFile.exists() )
{
throw new IllegalArgumentException( configFile + " doesn't exist" );
}
return configFile;
}

private void start( Config config ) throws IOException
@SafeVarargs
@Override
public final int start( File configFile, Pair<String, String>... configOverrides )
{
Config config = getConfig( configFile, configOverrides );
try
{
life.add( new Neo4jJobScheduler() );
Expand Down Expand Up @@ -116,37 +113,42 @@ private void start( Config config ) throws IOException
throw e;
}
}
addShutdownHook();
life.start();

return 0;
}

public static void main( String[] args ) throws IOException
@Override
public int stop()
{
new ArbiterBootstrapper( getConfig( args ) );
life.shutdown();
return 0;
}

@Override
public void close()
{
life.shutdown();
stop();
}

public static Config getConfig( String[] args ) throws IOException
private static Config getConfig( File configFile, Pair<String, String>... configOverrides )
{
Map<String, String> config = new HashMap<>();
String configPath = System.getProperty( ServerSettings.SERVER_CONFIG_FILE_KEY );
if ( configPath != null )
try
{
File configFile = new File( configPath );
if ( configFile.exists() )
{
config.putAll( MapUtil.load( configFile ) );
}
else
{
throw new IllegalArgumentException( configFile + " doesn't exist" );
}
config.putAll( MapUtil.load( configFile ) );
}
catch ( IOException e )
{
throw new RuntimeException( "Unable to load config file " + configFile, e );
}

for ( Pair<String, String> configOverride : configOverrides )
{
config.put( configOverride.first(), configOverride.other() );
}

config.putAll( Args.parse( args ).asMap() );
verifyConfig( config );
return new Config( config );
}
Expand All @@ -155,20 +157,49 @@ private static void verifyConfig( Map<String, String> config )
{
if ( !config.containsKey( ClusterSettings.initial_hosts.name() ) )
{
System.err.println( "No initial hosts to connect to supplied" );
System.exit( 1 );
throw new IllegalArgumentException( "No initial hosts to connect to supplied" );
}
if ( !config.containsKey( ClusterSettings.server_id.name() ) )
{
System.err.println( "No server id specified" );
System.exit( 1 );
throw new IllegalArgumentException( "No server id specified" );
}
}

private static LogService logService( FileSystemAbstraction fileSystem ) throws IOException
private static LogService logService( FileSystemAbstraction fileSystem )
{
String logDir = System.getProperty( "org.neo4j.cluster.logdirectory", "data/log" );
return StoreLogService.withUserLogProvider( FormattedLogProvider.toOutputStream( System.out ) )
.inStoreDirectory( fileSystem, new File( logDir ) );
try
{
return StoreLogService.withUserLogProvider( FormattedLogProvider.toOutputStream( System.out ) )
.inStoreDirectory( fileSystem, new File( logDir ) );
}
catch ( IOException e )
{
throw new RuntimeException( e );
}
}

private void addShutdownHook()
{
Runtime.getRuntime().addShutdownHook( new Thread()
{
@Override
public void run()
{
// ClusterJoin will block on a Future.get(), which will prevent it to shutdown.
// Adding a timer here in case a shutdown is requested before cluster join has succeeded. Otherwise
// the deadlock will prevent the shutdown from finishing.
timer.schedule( new TimerTask()
{
@Override
public void run()
{
System.err.println( "Failed to stop in a reasonable time, terminating..." );
Runtime.getRuntime().halt( 1 );
}
}, 4_000L );
ArbiterBootstrapper.this.stop();
}
} );
}
}
Expand Up @@ -83,9 +83,6 @@ public class ArbiterBootstrapperIT
public void canJoinWithExplicitInitialHosts() throws Exception
{
startAndAssertJoined( 5003,
// Config file
stringMap(),
// Arguments
stringMap(
initial_hosts.name(), ":5001",
server_id.name(), "3" )
Expand All @@ -97,56 +94,16 @@ public void willFailJoinIfIncorrectInitialHostsSet() throws Exception
{
assumeFalse( "Cannot kill processes on windows.", SystemUtils.IS_OS_WINDOWS );
startAndAssertJoined( SHOULD_NOT_JOIN,
// Config file
stringMap(),
// Arguments
stringMap(
initial_hosts.name(), ":5011",
server_id.name(), "3" )
);
}

@Test
public void canJoinWithInitialHostsInConfigFile() throws Exception
{
startAndAssertJoined( 5003,
// Config file
stringMap( initial_hosts.name(), ":5001" ),
// Arguments
stringMap( server_id.name(), "3" ) );
}

@Test
public void willFailJoinIfIncorrectInitialHostsSetInConfigFile() throws Exception
{
assumeFalse( "Cannot kill processes on windows.", SystemUtils.IS_OS_WINDOWS );
startAndAssertJoined( SHOULD_NOT_JOIN,
// Config file
stringMap( initial_hosts.name(), ":5011" ),
// Arguments
stringMap( server_id.name(), "3" ) );
}

@Test
public void canOverrideInitialHostsConfigFromConfigFile() throws Exception
{
startAndAssertJoined( 5003,
// Config file
stringMap( initial_hosts.name(), ":5011" ),
// Arguments
stringMap(
initial_hosts.name(), ":5001",
server_id.name(), "3" )
);
}

@Test
public void canSetSpecificPort() throws Exception
{
startAndAssertJoined( 5010,
// Config file
stringMap(),
// Arguments
stringMap(
initial_hosts.name(), ":5001",
server_id.name(), "3",
Expand All @@ -155,15 +112,13 @@ public void canSetSpecificPort() throws Exception
}

@Test
public void usesPortRangeFromConfigFile() throws Exception
public void usesPortRange() throws Exception
{
startAndAssertJoined( 5012,
// Config file
stringMap(
initial_hosts.name(), ":5001",
cluster_server.name(), ":5012-5020" ),
// Arguments
stringMap( server_id.name(), "3" )
cluster_server.name(), ":5012-5020",
server_id.name(), "3" )
);
}

Expand Down Expand Up @@ -229,26 +184,23 @@ private File configFile( Map<String, String> config ) throws IOException
return configFile;
}

private void startAndAssertJoined( Integer expectedAssignedPort, Map<String, String> configInConfigFile,
Map<String, String> config ) throws Exception
private void startAndAssertJoined( Integer expectedAssignedPort, Map<String, String> config ) throws Exception
{
Map<String,String> localCopy = new HashMap<>( configInConfigFile );
localCopy.put( GraphDatabaseSettings.auth_store.name(), Files.createTempFile("auth", "").toString() );
Map<String, String> localCopy = new HashMap<>( config );
localCopy.put( GraphDatabaseSettings.auth_store.name(), Files.createTempFile( "auth", "" ).toString() );
File configFile = configFile( localCopy );
CountDownLatch latch = new CountDownLatch( 1 );
AtomicInteger port = new AtomicInteger();
clients[0].addClusterListener( joinAwaitingListener( latch, port ) );

boolean arbiterStarted = startArbiter( configFile, config, latch );
boolean arbiterStarted = startArbiter( configFile, latch );
if ( expectedAssignedPort == null )
{
assertFalse( format( "Should not be able to start arbiter given config file:%s " +
"and arguments:%s", configInConfigFile, config ), arbiterStarted );
assertFalse( format( "Should not be able to start arbiter given config file:%s", config ), arbiterStarted );
}
else
{
assertTrue( format( "Should be able to start arbiter given config file:%s " +
"and arguments:%s", configInConfigFile, config ), arbiterStarted );
assertTrue( format( "Should be able to start arbiter given config file:%s", config ), arbiterStarted );
assertEquals( expectedAssignedPort.intValue(), port.get() );
}
}
Expand All @@ -267,14 +219,13 @@ public void joinedCluster( InstanceId member, URI memberUri )
};
}

private boolean startArbiter( File configFile, Map<String, String> config, CountDownLatch latch )
throws Exception
private boolean startArbiter( File configFile, CountDownLatch latch ) throws Exception
{
Process process = null;
ProcessStreamHandler handler = null;
try
{
process = startArbiterProcess( configFile, config );
process = startArbiterProcess( configFile );
new InputStreamAwaiter( process.getInputStream() ).awaitLine( START_SIGNAL, 20, SECONDS );
handler = new ProcessStreamHandler( process, false, "", IGNORE_FAILURES );
handler.launch();
Expand Down Expand Up @@ -307,8 +258,7 @@ private boolean startArbiter( File configFile, Map<String, String> config, Count
}
}

private Process startArbiterProcess( File configFile, Map<String, String> config )
throws Exception
private Process startArbiterProcess( File configFile ) throws Exception
{
List<String> args = new ArrayList<>( asList( "java", "-cp", getProperty( "java.class.path" ),
"-Dorg.neo4j.cluster.logdirectory=" + directory.getAbsolutePath() ) );
Expand All @@ -317,11 +267,6 @@ private Process startArbiterProcess( File configFile, Map<String, String> config
args.add( "-D" + ServerSettings.SERVER_CONFIG_FILE_KEY + "=" + configFile.getAbsolutePath() );
}
args.add( ArbiterBootstrapperTestProxy.class.getName() );

for ( Map.Entry<String, String> entry : config.entrySet() )
{
args.add( "-" + entry.getKey() + "=" + entry.getValue() );
}
return getRuntime().exec( args.toArray( new String[args.size()] ) );
}

Expand Down

0 comments on commit a86ad8e

Please sign in to comment.