/**
* 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.net;
import org.neo4j.onlinebackup.ha.Master;
public class HandleIncommingSlaveJob extends ConnectionJob
{
private static enum Status implements JobStatus
{
GET_GREETING,
SETUP_GREETING,
SEND_GREETING,
SEND_BYE,
}
private final Master master;
private long slaveVersion;
private String xaDsName;
private int retries = 0;
public HandleIncommingSlaveJob( Connection connection, Master master )
{
super( connection, master );
this.master = master;
setStatus( Status.GET_GREETING );
}
private boolean getGreeting()
{
if ( retries > 20 )
{
close();
}
if ( !acquireReadBuffer() )
{
return false;
}
try
{
// HEADER(1) + DB_ID(8) + DB_TIMESTAMP(8) + DB_VERISON(8) +
// NAME_length(4) + NAME
// buffer.limit( 25 );
int read = connection.read();
if ( read > 29 )
{
buffer.flip();
byte slaveGreeting = buffer.get();
if ( slaveGreeting != HeaderConstants.SLAVE_GREETING )
{
setStatus( Status.SEND_BYE );
return true;
}
long id = buffer.getLong();
long timestamp = buffer.getLong();
long version = buffer.getLong();
int strLen = buffer.getInt();
byte[] bytes = new byte[strLen];
buffer.get( bytes );
xaDsName = new String( bytes );
long masterId = master.getIdentifier( xaDsName );
long masterTimestamp = master.getCreationTime( xaDsName );
long masterVersion = master.getVersion( xaDsName );
if ( id != masterId || timestamp != masterTimestamp ||
version > masterVersion )
{
log( "Got wrong id/time/version [" + id + "/" + timestamp +
"/" + version + "]" + "[" + masterId + "/" +
masterTimestamp + "/" + masterVersion +
"] for data source " + xaDsName );
setStatus( Status.SEND_BYE );
return true;
}
log( "Got slave version[" + version + "]. I am version[" +
master.getVersion( xaDsName ) + "] for data source " + xaDsName );
slaveVersion = version;
setStatus( Status.SETUP_GREETING );
retries = 0;
return true;
}
else
{
retries++;
if ( read > 0 )
{
connection.pushBackAllReadData();
}
return false;
}
}
finally
{
releaseReadBuffer();
}
}
private boolean setupGreeting()
{
if ( retries > 20 )
{
close();
}
if ( !acquireWriteBuffer() )
{
retries++;
return false;
}
buffer.put( HeaderConstants.MASTER_GREETING );
buffer.putLong( master.getVersion( xaDsName ) );
buffer.flip();
log( "Setup greeting" );
setStatus( Status.SEND_GREETING );
retries = 0;
return true;
}
private boolean sendGreeting()
{
if ( retries > 20 )
{
close();
}
log( "Send greeting" );
connection.write();
if ( !buffer.hasRemaining() )
{
releaseWriteBuffer();
setNoRequeue();
setChainJob( new HandleSlaveConnection(
connection, master, xaDsName ) );
return true;
}
retries++;
return false;
}
private boolean sendBye()
{
if ( retries > 20 )
{
close();
}
if ( !acquireWriteBuffer() )
{
retries++;
return false;
}
try
{
log( "Send bye" );
buffer.put( HeaderConstants.BYE );
buffer.flip();
connection.write();
return true;
}
finally
{
releaseWriteBuffer();
close();
}
}
@Override
public boolean performJob()
{
switch ( (Status) getStatus() )
{
case GET_GREETING: return getGreeting();
case SETUP_GREETING: return setupGreeting();
case SEND_GREETING: return sendGreeting();
case SEND_BYE: return sendBye();
default:
throw new IllegalStateException( "Unkown status: " +
getStatus() );
}
}
@Override
void connectionClosed()
{
System.out.println( "Connection closed " + connection );
}
}