package org.neo4j.onlinebackup.ha;
import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.channels.ReadableByteChannel;
import java.nio.channels.ServerSocketChannel;
import java.util.List;
import java.util.Map;
import java.util.concurrent.CopyOnWriteArrayList;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.kernel.EmbeddedGraphDatabase;
import org.neo4j.kernel.impl.nioneo.xa.NeoStoreXaDataSource;
import org.neo4j.onlinebackup.net.AcceptJob;
import org.neo4j.onlinebackup.net.Callback;
import org.neo4j.onlinebackup.net.Connection;
import org.neo4j.onlinebackup.net.HandleIncommingSlaveJob;
import org.neo4j.onlinebackup.net.HandleSlaveConnection;
import org.neo4j.onlinebackup.net.Job;
import org.neo4j.onlinebackup.net.JobEater;
import org.neo4j.onlinebackup.net.SocketException;
public class Master implements Callback
{
private final EmbeddedGraphDatabase graphDb;
private final NeoStoreXaDataSource xaDs;
private final JobEater jobEater;
private final ServerSocketChannel serverChannel;
private final int port;
private List<HandleSlaveConnection> slaveList = new
CopyOnWriteArrayList<HandleSlaveConnection>();
public Master( String path, Map<String,String> params, int listenPort )
{
this.graphDb = new EmbeddedGraphDatabase( path, params );
this.xaDs = (NeoStoreXaDataSource) graphDb.getConfig().getTxModule()
.getXaDataSourceManager().getXaDataSource( "nioneodb" );
xaDs.keepLogicalLogs( true );
this.port = listenPort;
try
{
serverChannel = ServerSocketChannel.open();
serverChannel.configureBlocking( false );
serverChannel.socket().bind( new InetSocketAddress( listenPort ) );
}
catch ( IOException e )
{
throw new SocketException( "Unable to bind at port[" +
listenPort + "]", e );
}
jobEater = new JobEater();
jobEater.addJob( new AcceptJob( this, serverChannel ) );
jobEater.start();
}
public GraphDatabaseService getGraphDbService()
{
return graphDb;
}
public int getPort()
{
return this.port;
}
public void jobExecuted( Job job )
{
if ( job instanceof AcceptJob )
{
// handle incomming slave
AcceptJob acceptJob = (AcceptJob) job;
if ( acceptJob.getAcceptedChannel() != null )
{
Connection connection = new Connection(
((AcceptJob) job).getAcceptedChannel() );
jobEater.addJob(
new HandleIncommingSlaveJob( connection, this ) );
}
}
else if ( job instanceof HandleIncommingSlaveJob )
{
HandleSlaveConnection chainJob =
(HandleSlaveConnection) job.getChainJob();
if ( chainJob != null )
{
slaveList.add( chainJob );
}
else
{
System.out.println( "null chain job" );
}
}
}
public void shutdown()
{
jobEater.stopEating();
try
{
serverChannel.close();
}
catch ( IOException e )
{
e.printStackTrace();
}
graphDb.shutdown();
}
public long getIdentifier()
{
return xaDs.getRandomIdentifier();
}
public long getCreationTime()
{
return xaDs.getCreationTime();
}
public long getVersion()
{
return xaDs.getCurrentLogVersion();
}
public ReadableByteChannel getLog( long version ) throws IOException
{
return xaDs.getLogicalLog( version );
}
public long getLogLength( long version )
{
return xaDs.getLogicalLogLength( version );
}
public boolean hasLog( long version )
{
return xaDs.hasLogicalLog( version );
}
public void rotateLogAndPushToSlaves() throws IOException
{
long version = getVersion();
xaDs.rotateLogicalLog();
for ( HandleSlaveConnection slave : slaveList )
{
if ( !slave.offerLogToSlave( version ) )
{
System.out.println( "Failed to offer log to slave: " + slave );
}
}
}
}