/**
* 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 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.cluster.timeout;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.neo4j.cluster.com.message.Message;
import org.neo4j.cluster.com.message.MessageProcessor;
import org.neo4j.cluster.com.message.MessageSource;
import org.neo4j.cluster.com.message.MessageType;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* Calculate roundtrip latency from this host to all other hosts. This can be used for realistic timeouts.
*/
public class LatencyCalculator
implements MessageProcessor, TimeoutStrategy
{
TimeoutStrategy delegate;
Map<String, Long> conversations = new HashMap<String, Long>( );
Map<String, List<Long>> latencies = new HashMap<String, List<Long>>( );
Logger logger = LoggerFactory.getLogger(LatencyCalculator.class);
long now;
int latencyCount = 5;
public LatencyCalculator(TimeoutStrategy delegate, MessageSource incoming)
{
this.delegate = delegate;
incoming.addMessageProcessor( new MessageProcessor()
{
@Override
public void process( Message<? extends MessageType> message )
{
synchronized(LatencyCalculator.this)
{
Long sent = conversations.get( message.getHeader( Message.CONVERSATION_ID ) );
if (sent != null)
{
long received = now;
String from = message.getHeader( Message.FROM );
List<Long> hostLatencies = latencies.get( from );
if (hostLatencies == null)
{
hostLatencies = new ArrayList<Long>( );
latencies.put( from, hostLatencies );
}
long latency = received - sent;
if (latency < 0)
logger.warn( "Negative latency!" );
hostLatencies.add( latency );
if (hostLatencies.size() == latencyCount)
{
long latencySum = 0;
for( Long hostLatency : hostLatencies )
{
latencySum += hostLatency;
}
long latencyAvg = latencySum / latencyCount;
// logger.info( from+" roundtrip latency: "+latencyAvg );
hostLatencies.clear();
}
}
}
}
} );
}
@Override
public void process( Message<? extends MessageType> message )
{
if (!message.isInternal() && !message.getHeader( Message.TO ).equals( message.getHeader( Message.CREATED_BY ) ))
{
conversations.put( message.getHeader( Message.CONVERSATION_ID ), now );
}
}
@Override
public long timeoutFor( Message message )
{
return delegate.timeoutFor( message );
}
@Override
public void timeoutTriggered( Message timeoutMessage )
{
delegate.timeoutTriggered( timeoutMessage );
}
@Override
public void timeoutCancelled( Message timeoutMessage )
{
delegate.timeoutCancelled( timeoutMessage );
}
public synchronized void tick(long now)
{
this.now = now;
delegate.tick( now );
}
}