/**
* Copyright (c) 2002-2010 "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 Affero 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 Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.neo4j.onlinebackup.ha;
import java.io.IOException;
import java.util.Map;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.kernel.EmbeddedReadOnlyGraphDatabase;
import org.neo4j.kernel.impl.nioneo.store.UnderlyingStorageException;
import org.neo4j.kernel.impl.transaction.XaDataSourceManager;
import org.neo4j.kernel.impl.transaction.xaframework.XaDataSource;
import org.neo4j.onlinebackup.net.Callback;
import org.neo4j.onlinebackup.net.ConnectToMasterJob;
import org.neo4j.onlinebackup.net.Connection;
import org.neo4j.onlinebackup.net.Job;
import org.neo4j.onlinebackup.net.JobEater;
public abstract class AbstractSlave implements Callback
{
private final EmbeddedReadOnlyGraphDatabase graphDb;
// private final NeoStoreXaDataSource xaDs;
// private final XaDataSource luceneXaDs;
// private final XaDataSource luceneFulltextXaDs;
private final XaDataSource[] xaDataSources;
private final Connection[] masterConnections;
private final JobEater jobEater;
private final LogApplier logApplier;
private final String masterIp;
private final int masterPort;
// private Connection masterConnection;
// private Connection luceneConnection;
// private Connection luceneFulltextConnection;
public AbstractSlave( String path, Map<String,String> params,
String masterIp, int masterPort )
{
params.put( "backup_slave", "true" );
this.graphDb = new EmbeddedReadOnlyGraphDatabase( path, params );
XaDataSourceManager xaDsMgr = graphDb.getConfig().getTxModule().
getXaDataSourceManager();
XaDataSource nioneo = xaDsMgr.getXaDataSource( "nioneodb" );
XaDataSource lucene = xaDsMgr.getXaDataSource( "lucene" );
XaDataSource fulltext = xaDsMgr.getXaDataSource( "lucene-fulltext" );
if ( lucene != null && fulltext != null )
{
xaDataSources = new XaDataSource[3];
xaDataSources[0] = nioneo;
xaDataSources[1] = lucene;
xaDataSources[2] = fulltext;
}
else
{
xaDataSources = new XaDataSource[1];
xaDataSources[0] = nioneo;
}
for ( XaDataSource xaDs : xaDataSources )
{
xaDs.makeBackupSlave();
}
recover();
jobEater = new JobEater();
logApplier = new LogApplier( xaDataSources );
jobEater.start();
logApplier.start();
this.masterIp = masterIp;
this.masterPort = masterPort;
masterConnections = new Connection[xaDataSources.length];
for ( int i = 0; i < masterConnections.length; i++ )
{
masterConnections[i] = new Connection( masterIp, masterPort );
while ( !masterConnections[i].connected() )
{
if ( masterConnections[i].connectionRefused() )
{
System.out.println( "Unable to connect to master" );
break;
}
}
if ( masterConnections[i].connected() )
{
String name = "nioneodb";
if ( i == 1 )
{
name = "lucene";
}
else if ( i == 2 )
{
name = "lucene-fulltext";
}
jobEater.addJob( new ConnectToMasterJob( masterConnections[i],
this, name, xaDataSources[i] ) );
}
}
// System.out.println( "At version: " + getVersion() );
}
private void recover()
{
for ( XaDataSource xaDs : xaDataSources )
{
long nextVersion = xaDs.getCurrentLogVersion();
while ( xaDs.hasLogicalLog( nextVersion ) )
{
try
{
xaDs.applyLog( xaDs.getLogicalLog( nextVersion ) );
}
catch ( IOException e )
{
throw new UnderlyingStorageException(
"Unable to recover slave to consistent state", e );
}
nextVersion++;
}
}
}
public boolean isConnectedToMaster()
{
for ( Connection masterConnection : masterConnections )
{
if ( !masterConnection.connected() )
{
return false;
}
}
return true;
}
public boolean reconnectToMaster()
{
for ( int i = 0; i < masterConnections.length; i++ )
{
if ( masterConnections[i].connected() )
{
continue;
}
masterConnections[i] = new Connection( masterIp, masterPort );
while ( !masterConnections[i].connected() )
{
if ( masterConnections[i].connectionRefused() )
{
return false;
}
}
if ( masterConnections[i].connected() )
{
String name = "nioneodb";
if ( i == 1 )
{
name = "lucene";
}
else if ( i == 2 )
{
name = "lucene-fulltext";
}
jobEater.addJob( new ConnectToMasterJob( masterConnections[i],
this, name, xaDataSources[i] ) );
}
}
return true;
}
public String getMasterIp()
{
return masterIp;
}
public int getMasterPort()
{
return masterPort;
}
public void jobExecuted( Job job )
{
}
// public long getIdentifier()
// {
// return xaDs.getRandomIdentifier();
// }
//
// public long getCreationTime()
// {
// return xaDs.getCreationTime();
// }
//
// public long getVersion()
// {
// return xaDs.getCurrentLogVersion();
// }
//
// public boolean hasLog( long version )
// {
// return xaDs.hasLogicalLog( version );
// }
//
// public String getLogName( long version )
// {
// return xaDs.getFileName( version );
// }
public void shutdown()
{
jobEater.stopEating();
logApplier.stopApplyLogs();
graphDb.shutdown();
}
protected GraphDatabaseService getGraphDb()
{
return graphDb;
}
}