package org.arbeitspferde.groningen; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.Lock; import java.util.concurrent.locks.ReentrantLock; /** * A pipeline synchronizer that only supports one point of synchronization: blocking the pipeline * at the end of an iteration until it is signaled. The signal can arrive before the pipeline * arrives at the end of the iteration blocking point. Such a blocking pattern is meant to provide * clients a means to analyze the scores and decide if another iteration is warranted. */ public class IterationFinalizationSynchronizer implements PipelineSynchronizer { /** Sync points this synchronizer supports */ private static final SyncPoint.ComposedSyncPoints supportedSyncPoints = new SyncPoint.ComposedSyncPoints(SyncPoint.SIGNAL_ITERATION_FINALIZATION); // Locks and condition to support a single point of synchronization private final Lock finalizerLock = new ReentrantLock(); private final Condition finalizerCondition = finalizerLock.newCondition(); // Flag to allow one to give a pass to the pipeline before it arrives at the // IterationFinalizationSync point private boolean finalizedSinceIterationBegin = false; private PipelineStageInfo pipelineStageInfo = null; /** @see PipelineSynchronizer#supportsSyncPoints(SyncPoint[]) */ @Override public boolean supportsSyncPoints(SyncPoint... points) { return supportedSyncPoints.supportsSyncPoints(points); } /** @see PipelineSynchronizer#setPipelineStageTracker(PipelineStageInfo) */ @Override public void setPipelineStageTracker(PipelineStageInfo pipelineStageInfo) { this.pipelineStageInfo = pipelineStageInfo; } /** * @see PipelineSynchronizer#iterationStartHook() * * Called here to reset the finalization flag at the beginning of the iteration. */ @Override public void iterationStartHook() { finalizerLock.lock(); try { finalizedSinceIterationBegin = false; } finally { finalizerLock.unlock(); } } /** * @see org.arbeitspferde.groningen.PipelineSynchronizer#finalizeCompleteHook() * * Block the pipeline until the client steps the finalization flag or the condition is signaled. */ @Override public void finalizeCompleteHook() { finalizerLock.lock(); try { if (!finalizedSinceIterationBegin) { if (pipelineStageInfo != null) { pipelineStageInfo.set(PipelineStageState.ITERATION_FINALIZED_WAIT); } // TODO(etheon): revisit being interrupted, its meaning, how to use it in the restart of // an iteration or pausing... finalizerCondition.awaitUninterruptibly(); } } finally { finalizerLock.unlock(); } } /** @see org.arbeitspferde.groningen.PipelineSynchronizer#allowPastIterationFinalization() */ @Override public void allowPastIterationFinalization() throws UnsupportedOperationException { finalizerLock.lock(); try { finalizedSinceIterationBegin = true; finalizerCondition.signal(); } finally { finalizerLock.unlock(); } } // Most hooks have nothing to do /** @see PipelineSynchronizer#executorStartHook() */ @Override public void executorStartHook() {} /** @see PipelineSynchronizer#initialSubjectRestartCompleteHook() */ @Override public void initialSubjectRestartCompleteHook() {} /** @see PipelineSynchronizer#shouldFinalizeExperiment() */ @Override public boolean shouldFinalizeExperiment() { return false; } // The rest of the sync points are unused too /** @see org.arbeitspferde.groningen.PipelineSynchronizer#blockTilIterationStart(long) */ @Override public boolean blockTilIterationStart(long maxWaitSecs) throws UnsupportedOperationException { throw new UnsupportedOperationException( this.getClass().getEnclosingMethod().getName() + " is not used in " + this.getClass().getName()); } /** @see org.arbeitspferde.groningen.PipelineSynchronizer#allowPastIterationStart() */ @Override public void allowPastIterationStart() throws UnsupportedOperationException { throw new UnsupportedOperationException( this.getClass().getEnclosingMethod().getName() + " is not used in " + this.getClass().getName()); } /** @see org.arbeitspferde.groningen.PipelineSynchronizer#blockTilExperimentArgsPushed(long) */ @Override public boolean blockTilExperimentArgsPushed(long maxWaitSecs) throws UnsupportedOperationException { throw new UnsupportedOperationException( this.getClass().getEnclosingMethod().getName() + " is not used in " + this.getClass().getName()); } /** @see org.arbeitspferde.groningen.PipelineSynchronizer#allowPastExperimentArgsPushed() */ @Override public void allowPastExperimentArgsPushed() throws UnsupportedOperationException { throw new UnsupportedOperationException( this.getClass().getEnclosingMethod().getName() + " is not used in " + this.getClass().getName()); } /** @see org.arbeitspferde.groningen.PipelineSynchronizer#blockTilRestartedWithExpArgs(long) */ @Override public boolean blockTilRestartedWithExpArgs(long maxWaitSecs) throws UnsupportedOperationException { throw new UnsupportedOperationException( this.getClass().getEnclosingMethod().getName() + " is not used in " + this.getClass().getName()); } /** @see org.arbeitspferde.groningen.PipelineSynchronizer#allowPastRestartedWithExpArgs() */ @Override public void allowPastRestartedWithExpArgs() throws UnsupportedOperationException { throw new UnsupportedOperationException( this.getClass().getEnclosingMethod().getName() + " is not used in " + this.getClass().getName()); } /** @see org.arbeitspferde.groningen.PipelineSynchronizer#flagEndOfIteration() */ @Override public void flagEndOfIteration() throws UnsupportedOperationException { throw new UnsupportedOperationException( this.getClass().getEnclosingMethod().getName() + " is not used in " + this.getClass().getName()); } /** @see org.arbeitspferde.groningen.PipelineSynchronizer#blockTilIterationFinalization(long) */ @Override public boolean blockTilIterationFinalization(long maxWaitSecs) throws UnsupportedOperationException { throw new UnsupportedOperationException( this.getClass().getEnclosingMethod().getName() + " is not used in " + this.getClass().getName()); } }