/**
* 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.protocol.omega;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedMap;
import java.util.TreeMap;
import org.neo4j.cluster.protocol.cluster.ClusterContext;
import org.neo4j.cluster.protocol.omega.state.State;
import org.neo4j.cluster.protocol.omega.state.View;
public class OmegaContext
{
public void startTimers()
{
}
public void roundDone( int refreshRound )
{
refreshContexts.remove( refreshRound );
}
public Iterable<? extends URI> getServers()
{
return clusterContext.configuration.getMembers();
}
public State getMyState()
{
return registry.get( clusterContext.getMe() );
}
public View getMyView()
{
return views.get( clusterContext.getMe() );
}
public int getMyProcessId()
{
return getMyState().getEpochNum().getProcessId();
}
public int startCollectionRound()
{
int nextRound = collectionContexts.isEmpty() ? 1 : collectionContexts.lastKey() + 1;
Map<URI, View> oldViews = new HashMap<URI, View>();
oldViews.putAll( views );
collectionContexts.put( nextRound, new CollectionRound( oldViews, nextRound ) );
return nextRound;
}
public Map<URI, View> getPreviousViewForCollectionRound( int newCollectionRound )
{
return collectionContexts.get( newCollectionRound ).getOldViews();
}
public int getStatusResponsesForRound( int newCollectionRound )
{
return collectionContexts.get( newCollectionRound ).getResponseCount();
}
public Map<URI, View> getViews()
{
return views;
}
public void collectionRoundDone( int collectionRound )
{
CollectionRound theRound = collectionContexts.get( collectionRound );
Map<URI, View> previousView = theRound.getOldViews();
// Now, consolidate them
for ( Map.Entry<URI, View> newView : views.entrySet() )
{
URI uri = newView.getKey();
View view = newView.getValue();
View oldView = previousView.get( uri );
if ( oldView == null )
{
// This means we didn't know about it, so it is definitely not expired
view.setExpired( false );
continue;
}
if ( view.getState().compareTo( oldView.getState() ) <= 0 )
{
view.setExpired( true );
}
if ( view.getState().getEpochNum().compareTo( oldView.getState().getEpochNum() ) > 0 )
{
view.setExpired( false );
}
}
}
public void responseReceivedForRound( int collectionRound, URI from, Map<URI, State> view )
{
CollectionRound thisRound = collectionContexts.get( collectionRound );
thisRound.responseReceived( from );
for ( Map.Entry<URI, State> incomingView : view.entrySet() )
{
URI uri = incomingView.getKey();
State incomingState = incomingView.getValue();
View oldView = views.get( uri );
if ( oldView == null /*we don't know about it yet*/
|| incomingState.compareTo( oldView.getState() ) > 0 )
{
views.put( uri, new View( incomingState ) );
}
}
}
private static final class RefreshRoundContext
{
int acksReceived;
}
private final SortedMap<Integer, RefreshRoundContext> refreshContexts = new TreeMap<Integer, RefreshRoundContext>();
private final SortedMap<Integer, CollectionRound> collectionContexts = new TreeMap<Integer, CollectionRound>();
public int getAckCount( int forRound )
{
RefreshRoundContext context = refreshContexts.get( forRound );
if ( context == null )
{
return -1;
}
return context.acksReceived;
}
public int startRefreshRound()
{
int nextRound = refreshContexts.isEmpty() ? 1 : refreshContexts.lastKey() + 1;
refreshContexts.put( nextRound, new RefreshRoundContext() );
return nextRound;
}
public void ackReceived( int forRound )
{
refreshContexts.get( forRound ).acksReceived++;
}
private final Map<URI, State> registry = new HashMap<URI, State>();
private final Map<URI, View> views = new HashMap<URI, View>();
private final List<OmegaListener> listeners = new ArrayList<OmegaListener>();
private int bigDelta;
private int smallDelta;
private ClusterContext clusterContext;
public OmegaContext( ClusterContext clusterContext )
{
this.clusterContext = clusterContext;
}
public ClusterContext getClusterContext()
{
return clusterContext;
}
public void addListener( OmegaListener listener )
{
listeners.add( listener );
}
public void removeListener( OmegaListener listener )
{
listeners.remove( listener );
}
public int getClusterNodeCount()
{
return getClusterContext().getConfiguration().getMembers().size();
}
public Map<URI, State> getRegistry()
{
return registry;
}
}