/**
* Copyright (c) 2002-2011 "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.index.impl.lucene;
import org.neo4j.graphdb.GraphDatabaseService;
import org.neo4j.graphdb.Node;
import org.neo4j.graphdb.index.Index;
import java.util.Queue;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.atomic.AtomicInteger;
public class BaseWorker extends Thread
{
protected Index<Node> index;
protected GraphDatabaseService graphDb;
protected Exception exception;
protected CountDownLatch latch = new CountDownLatch( 1 );
protected AtomicInteger threadState = new AtomicInteger( STARTING );
private static final int WAITING = 1;
private static final int RUNNING = 2;
private static final int DONE = 3;
private static final int STARTING = 4;
private Queue<Command> commands = new ConcurrentLinkedQueue<Command>();
public BaseWorker( Index<Node> index, GraphDatabaseService graphDb )
{
this.index = index;
this.graphDb = graphDb;
start();
waitForWorkerToStart();
}
@Override
public void run()
{
CommandState state = new CommandState( index, graphDb );
threadState.set( STARTING );
while ( state.alive )
{
try
{
latch = new CountDownLatch( 1 );
log( "WORKER: Waiting for latch" );
latch.await();
threadState.set( RUNNING );
Command command = commands.poll();
log( "WORKER: I have a command! " + command.getClass().getSimpleName() );
command.doWork( state );
threadState.set( DONE );
} catch ( InterruptedException e )
{
throw new RuntimeException( e );
} catch ( Exception exception )
{
this.exception = exception;
threadState.set( DONE );
}
}
}
private void log( String s )
{
// System.out.println( Thread.currentThread().getId() + " - " + s );
}
protected void queueCommand( Command cmd )
{
commands.add( cmd );
log( "MASTER: Queuing command, and starting worker - " + cmd.getClass().getSimpleName() );
latch.countDown();
waitForCommandToComplete();
threadState.set( WAITING );
}
private void waitForCommandToComplete()
{
waitFor( DONE, WAITING );
}
private void waitForWorkerToStart()
{
waitFor( STARTING, WAITING );
}
private void waitFor( int expectedState, int newState )
{
int retries = 0;
while ( !threadState.compareAndSet( expectedState, newState ) && retries++ < 100 )
{
try
{
Thread.sleep( 10 );
} catch ( InterruptedException e )
{
throw new RuntimeException( e );
}
}
if (retries > 300)
{
throw new IllegalStateException( "Something didn't finish in a timely manner. Aborting..." );
}
}
}