Package com.opengamma.engine.view.worker

Source Code of com.opengamma.engine.view.worker.SequencePartitioningViewProcessWorker

/**
* Copyright (C) 2013 - present by OpenGamma Inc. and the OpenGamma group of companies
*
* Please see distribution for license.
*/
package com.opengamma.engine.view.worker;

import java.util.ArrayList;
import java.util.Collection;
import java.util.EnumSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.threeten.bp.Instant;

import com.opengamma.engine.view.ViewComputationResultModel;
import com.opengamma.engine.view.ViewDefinition;
import com.opengamma.engine.view.compilation.CompiledViewDefinitionWithGraphs;
import com.opengamma.engine.view.cycle.ViewCycle;
import com.opengamma.engine.view.cycle.ViewCycleMetadata;
import com.opengamma.engine.view.execution.ArbitraryViewCycleExecutionSequence;
import com.opengamma.engine.view.execution.ExecutionOptions;
import com.opengamma.engine.view.execution.ViewCycleExecutionOptions;
import com.opengamma.engine.view.execution.ViewCycleExecutionSequence;
import com.opengamma.engine.view.execution.ViewExecutionFlags;
import com.opengamma.engine.view.execution.ViewExecutionOptions;
import com.opengamma.engine.view.impl.ViewProcessContext;

/**
* Implementation of {@link ViewProcessWorker} for partitioning a sequence and delegating to other workers to handle each partition.
*/
public class SequencePartitioningViewProcessWorker implements ViewProcessWorker, ViewProcessWorkerContext {

  private static final Logger s_logger = LoggerFactory.getLogger(SequencePartitioningViewProcessWorker.class);

  private final ViewProcessWorkerFactory _delegate;
  private final ViewProcessWorkerContext _context;
  private final EnumSet<ViewExecutionFlags> _executionFlags;
  private final Integer _maxSuccessiveDeltaCycles;
  private final ViewCycleExecutionSequence _sequence;
  private final ViewCycleExecutionOptions _defaultExecutionOptions;
  private final Queue<ViewProcessWorker> _workers = new LinkedList<ViewProcessWorker>();
  private volatile ViewDefinition _viewDefinition;
  private int _partition;
  private boolean _terminated;
  private int _spawnedWorkerCount;
  private int _spawnedCycleCount;
  private int _spawnedWorkers;
  private int _trigger;

  public SequencePartitioningViewProcessWorker(final ViewProcessWorkerFactory delegate, final ViewProcessWorkerContext context, final ViewExecutionOptions executionOptions,
      final ViewDefinition viewDefinition, final int partition, final int maxWorkers) {
    _delegate = delegate;
    _context = context;
    _executionFlags = EnumSet.copyOf(executionOptions.getFlags());
    _maxSuccessiveDeltaCycles = executionOptions.getMaxSuccessiveDeltaCycles();
    _defaultExecutionOptions = executionOptions.getDefaultExecutionOptions();
    _sequence = executionOptions.getExecutionSequence();
    _viewDefinition = viewDefinition;
    _partition = partition;
    _trigger = maxWorkers;
    if (!_executionFlags.remove(ViewExecutionFlags.WAIT_FOR_INITIAL_TRIGGER)) {
      // Kick off first batch of workers
      triggerCycle();
    }
  }

  private ViewProcessWorkerFactory getDelegate() {
    return _delegate;
  }

  private ViewProcessWorkerContext getWorkerContext() {
    return _context;
  }

  private EnumSet<ViewExecutionFlags> getExecutionFlags() {
    return _executionFlags;
  }

  private ViewCycleExecutionOptions getDefaultExecutionOptions() {
    return _defaultExecutionOptions;
  }

  private Integer getMaxSuccessiveDeltaCycles() {
    return _maxSuccessiveDeltaCycles;
  }

  private ViewExecutionOptions getExecutionOptions(ViewCycleExecutionSequence newSequence) {
    return new ExecutionOptions(newSequence, getExecutionFlags(), getMaxSuccessiveDeltaCycles(), getDefaultExecutionOptions());
  }

  private ViewCycleExecutionSequence getSequence() {
    return _sequence;
  }

  private ViewDefinition getViewDefinition() {
    return _viewDefinition;
  }

  private int getPartitionSize() {
    return _partition;
  }

  private synchronized void spawnWorker() {
    ViewCycleExecutionSequence sequence = getSequence();
    final int partitionSize = getPartitionSize();
    final List<ViewCycleExecutionOptions> partition = new ArrayList<ViewCycleExecutionOptions>(partitionSize);
    for (int i = 0; i < partitionSize; i++) {
      final ViewCycleExecutionOptions step = sequence.poll(getDefaultExecutionOptions());
      if (step != null) {
        partition.add(step);
      } else {
        break;
      }
    }
    if (partition.isEmpty()) {
      s_logger.info("No more cycles to execute");
    } else {
      final int firstCycle = _spawnedCycleCount;
      _spawnedCycleCount += partition.size();
      s_logger.info("Spawning worker {} for {} cycles {} - {}", new Object[] {++_spawnedWorkerCount, getWorkerContext(), firstCycle, _spawnedCycleCount });
      ViewProcessWorker delegate = getDelegate().createWorker(this, getExecutionOptions(new ArbitraryViewCycleExecutionSequence(partition)), getViewDefinition());
      _workers.add(delegate);
      _spawnedWorkers++;
    }
  }

  // ViewProcessWorker

  @Override
  public synchronized boolean triggerCycle() {
    if (_trigger == 0) {
      s_logger.debug("Ignoring triggerCycle on run-as-fast-as-possible sequence");
      return false;
    }
    while (_trigger > 0) {
      spawnWorker();
      _trigger--;
    }
    return true;
  }

  @Override
  public boolean requestCycle() {
    s_logger.debug("Ignoring requestCycle on run-as-fast-as-possible sequence");
    return false;
  }

  @Override
  public void updateViewDefinition(ViewDefinition viewDefinition) {
    // This is not a good state of affairs as the caller has little or no control or knowledge over the sequence we're working on
    s_logger.warn("View definition updated on run-as-fast-as-possible sequence");
    _viewDefinition = viewDefinition;
    Collection<ViewProcessWorker> delegates;
    synchronized (this) {
      delegates = new ArrayList<ViewProcessWorker>(_workers);
    }
    for (ViewProcessWorker delegate : delegates) {
      delegate.updateViewDefinition(_viewDefinition);
    }
  }

  @Override
  public void terminate() {
    Collection<ViewProcessWorker> delegates;
    synchronized (this) {
      _terminated = true;
      delegates = new ArrayList<ViewProcessWorker>(_workers);
    }
    for (ViewProcessWorker delegate : delegates) {
      delegate.terminate();
    }
  }

  @Override
  public void join() throws InterruptedException {
    Collection<ViewProcessWorker> delegates;
    synchronized (this) {
      delegates = new ArrayList<ViewProcessWorker>(_workers);
    }
    for (ViewProcessWorker delegate : delegates) {
      delegate.join();
    }
  }

  @Override
  public boolean join(long timeout) throws InterruptedException {
    Collection<ViewProcessWorker> delegates;
    final long maxTime = System.nanoTime() + (timeout * 1000000);
    long time;
    do {
      synchronized (this) {
        delegates = new ArrayList<ViewProcessWorker>(_workers);
      }
      for (ViewProcessWorker delegate : delegates) {
        time = (maxTime - System.nanoTime()) / 1000000;
        if (time <= 0) {
          return false;
        }
        if (!delegate.join(time)) {
          return false;
        }
      }
      if (isTerminated()) {
        return true;
      }
      time = (maxTime - System.nanoTime()) / 1000000;
    } while (time > 0);
    return false;
  }

  /**
   * Tests whether at least one of the workers in the buffer is still active. This will also housekeep the buffer of workers, removing any that have terminated.
   *
   * @return true if the worker buffer is empty, or all return true from {@code isTerminated} (which leaves the buffer empty)
   */
  @Override
  public boolean isTerminated() {
    ViewProcessWorker worker;
    synchronized (this) {
      worker = _workers.peek();
    }
    while (worker != null) {
      if (!worker.isTerminated()) {
        return false;
      }
      synchronized (this) {
        ViewProcessWorker worker2 = _workers.poll();
        if (worker2 == worker) {
          s_logger.debug("Removing completed worker from head of queue");
          worker = worker2;
        } else if (worker2 == null) {
          s_logger.debug("Completed worker already removed from queue");
          break;
        } else {
          s_logger.debug("Concurrent worker queue access");
          _workers.add(worker2);
          worker = _workers.peek();
        }
      }
    }
    return true;
  }

  @Override
  public void forceGraphRebuild() {
    Collection<ViewProcessWorker> delegates;
    synchronized (this) {
      delegates = new ArrayList<>(_workers);
    }
    for (ViewProcessWorker delegate : delegates) {
      delegate.forceGraphRebuild();
    }
  }

  // ViewProcessWorkerContext

  @Override
  public ViewProcessContext getProcessContext() {
    return getWorkerContext().getProcessContext();
  }

  @Override
  public void viewDefinitionCompiled(ViewExecutionDataProvider dataProvider, CompiledViewDefinitionWithGraphs compiled) {
    s_logger.debug("View definition compiled");
    getWorkerContext().viewDefinitionCompiled(dataProvider, compiled);
  }

  @Override
  public void viewDefinitionCompilationFailed(Instant compilationTime, Exception exception) {
    s_logger.debug("View definition compilation failed");
    getWorkerContext().viewDefinitionCompilationFailed(compilationTime, exception);
  }

  @Override
  public void cycleStarted(ViewCycleMetadata cycleMetadata) {
    s_logger.debug("Cycle started");
    getWorkerContext().cycleStarted(cycleMetadata);
  }

  @Override
  public void cycleFragmentCompleted(ViewComputationResultModel result, ViewDefinition viewDefinition) {
    s_logger.debug("Cycle fragment completed");
    getWorkerContext().cycleFragmentCompleted(result, viewDefinition);
  }

  @Override
  public void cycleCompleted(ViewCycle cycle) {
    s_logger.debug("Cycle completed");
    getWorkerContext().cycleCompleted(cycle);
  }

  @Override
  public void cycleExecutionFailed(ViewCycleExecutionOptions options, Exception exception) {
    s_logger.debug("Cycle execution failed");
    getWorkerContext().cycleExecutionFailed(options, exception);
  }

  @Override
  public void workerCompleted() {
    s_logger.debug("Worker completed");
    final boolean finished;
    synchronized (this) {
      finished = (--_spawnedWorkers) == 0;
      if (!_terminated) {
        spawnWorker();
      }
    }
    // isTerminated will housekeep the queue for us, but may not return TRUE as the worker that called us might not be considered terminated yet
    isTerminated();
    if (finished) {
      getWorkerContext().workerCompleted();
    }
  }

  // Object

  @Override
  public String toString() {
    return "Partition[" + getWorkerContext() + "]";
  }

}
TOP

Related Classes of com.opengamma.engine.view.worker.SequencePartitioningViewProcessWorker

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.