package com.ldbc.driver.runtime.coordination; import com.ldbc.driver.runtime.ConcurrentErrorReporter; import com.ldbc.driver.temporal.TimeSource; import java.util.List; import java.util.concurrent.BlockingQueue; import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicLong; import static java.lang.String.format; public class PeerCommunicatorThread extends Thread { private final TimeSource timeSource; // TODO heartbeat failure detection // TODO need separate non-Thread class to do that // TODO temporary until Akka/network is integrated // TODO need dummy PeerThread that just sends back the Completion Time it received private final BlockingQueue<CompletionTimeEvent.ExternalCompletionTimeEvent> peerReceiveQueue; private final List<BlockingQueue<CompletionTimeEvent.ExternalCompletionTimeEvent>> peerSendQueues; private final static long PEER_RECEIVE_QUEUE_POLL_TIMEOUT_AS_MILLI = 100; private final String myId; private final ConcurrentErrorReporter errorReporter; private final long heartbeatPeriodAsMilli; private final AtomicBoolean terminate; private final AtomicLong sharedLctReference; private final BlockingQueue<CompletionTimeEvent> completionTimeQueue; private long lastHeartbeatAsMilli; public PeerCommunicatorThread( TimeSource timeSource, String myId, ConcurrentErrorReporter errorReporter, long heartbeatPeriodAsMilli, AtomicBoolean terminate, AtomicLong sharedLctReference, BlockingQueue<CompletionTimeEvent> completionTimeQueue, // TODO temporary until Akka/network is integrated BlockingQueue<CompletionTimeEvent.ExternalCompletionTimeEvent> peerReceiveQueue, List<BlockingQueue<CompletionTimeEvent.ExternalCompletionTimeEvent>> peerSendQueues ) { super( PeerCommunicatorThread.class.getSimpleName() + "-" + System.currentTimeMillis() ); this.timeSource = timeSource; this.myId = myId; this.errorReporter = errorReporter; this.heartbeatPeriodAsMilli = heartbeatPeriodAsMilli; this.terminate = terminate; this.sharedLctReference = sharedLctReference; this.completionTimeQueue = completionTimeQueue; // TODO temporary until Akka/network is integrated this.peerReceiveQueue = peerReceiveQueue; this.peerSendQueues = peerSendQueues; // to force immediate transfer of local completion time lastHeartbeatAsMilli = this.timeSource.nowAsMilli() - heartbeatPeriodAsMilli; } @Override public void run() { while ( false == terminate.get() ) { try { if ( timeSource.nowAsMilli() - lastHeartbeatAsMilli > heartbeatPeriodAsMilli ) { sendCompletionTimeToPeers(); lastHeartbeatAsMilli = timeSource.nowAsMilli(); } CompletionTimeEvent.ExternalCompletionTimeEvent event = peerReceiveQueue.poll( PEER_RECEIVE_QUEUE_POLL_TIMEOUT_AS_MILLI, TimeUnit.MILLISECONDS ); if ( null != event ) { completionTimeQueue.put( event ); } } catch ( InterruptedException e ) { errorReporter.reportError( this, format( "Thread was interrupted" ) ); break; } } } private void sendCompletionTimeToPeers() throws InterruptedException { long ct = sharedLctReference.get(); for ( BlockingQueue<CompletionTimeEvent.ExternalCompletionTimeEvent> peerSendChannel : peerSendQueues ) { CompletionTimeEvent.writeExternalCompletionTime( myId, ct ); } } }