Package de.scoopgmbh.copper.persistent

Source Code of de.scoopgmbh.copper.persistent.PersistentPriorityProcessorPool

/*
* Copyright 2002-2013 SCOOP Software GmbH
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package de.scoopgmbh.copper.persistent;

import java.util.List;
import java.util.Queue;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import de.scoopgmbh.copper.ProcessingEngine;
import de.scoopgmbh.copper.ProcessingState;
import de.scoopgmbh.copper.Workflow;
import de.scoopgmbh.copper.common.PriorityProcessorPool;
import de.scoopgmbh.copper.common.Processor;
import de.scoopgmbh.copper.common.WfPriorityQueue;
import de.scoopgmbh.copper.internal.WorkflowAccessor;
import de.scoopgmbh.copper.management.PersistentPriorityProcessorPoolMXBean;
import de.scoopgmbh.copper.persistent.txn.TransactionController;

/**
* Implementation of the {@link PriorityProcessorPool} interface for use in the {@link PersistentScottyEngine}.
*
* @author austermann
*
*/
public class PersistentPriorityProcessorPool extends PriorityProcessorPool implements PersistentProcessorPool, PersistentPriorityProcessorPoolMXBean {

  private static final Logger logger = LoggerFactory.getLogger(PersistentPriorityProcessorPool.class);
 
  private TransactionController transactionController;
 
  private Thread thread;
  private volatile boolean shutdown = false;
  private final Object mutex = new Object();

  private volatile int lowerThreshold = 3000;
  private volatile int upperThreshold = 6000;
  private volatile int upperThresholdReachedWaitMSec = 50;
  private volatile int emptyQueueWaitMSec = 500;
  private volatile int dequeueBulkSize = 2000;
 
  /**
   * Creates a new {@link PersistentPriorityProcessorPool} with as many worker threads as processors available on the corresponding environment.
   * <code>id</code> and <code>transactionControler</code> need to be initialized later using the setter.
   */
  public PersistentPriorityProcessorPool() {
    super();
  }

  /**
   * Creates a new {@link PersistentPriorityProcessorPool} with as many worker threads as processors available on the corresponding environment.
   */
  public PersistentPriorityProcessorPool(String id, TransactionController transactionController) {
    super(id);
    this.transactionController = transactionController;
  }
 
  public PersistentPriorityProcessorPool(String id, TransactionController transactionController, int numberOfThreads) {
    super(id, numberOfThreads);
    this.transactionController = transactionController;
  }

  public void setTransactionController(TransactionController transactionController) {
    this.transactionController = transactionController;
  }
 
  @Override
  protected Processor newProcessor(String name, Queue<Workflow<?>> queue, int threadPriority, ProcessingEngine engine) {
    return new PersistentProcessor(name, queue, threadPriority, engine, transactionController);
  }
 
  @Override
  protected Queue<Workflow<?>> createQueue() {
    return new WfPriorityQueue() {
      private boolean notifiedLowerThreshold = false;
      @Override
      public Workflow<?> poll() {
        Workflow<?> wf = super.poll();
        if (!notifiedLowerThreshold && size() < lowerThreshold) {
          doNotify();
          notifiedLowerThreshold = true;
        }
        if (notifiedLowerThreshold && size() > lowerThreshold) {
          notifiedLowerThreshold = false;
        }
        return wf;
      }
     
    };
  }
 
  @Override
  public synchronized void startup() {
    super.startup();
    if (transactionController == null) throw new NullPointerException("property transactionController is null");
    thread = new Thread(new Runnable() {
      @Override
      public void run() {
        PersistentPriorityProcessorPool.this.run();
      }
    }, getId()+"#DBReader");
    thread.start();
  }
 
  @Override
  public synchronized void shutdown() {
    super.shutdown();
    shutdown = true;
    thread.interrupt();
  }
 
  private void run() {
    logger.info("started");
    final PersistentScottyEngine engine = (PersistentScottyEngine) getEngine();
    final ScottyDBStorageInterface dbStorage = engine.getDbStorage();
    while(!shutdown) {
      try {
        while (!shutdown) {
          int queueSize = 0;
          synchronized (queue) {
            queueSize = queue.size();
          }
          if (queueSize < upperThreshold) {
            break;
          }
          if (logger.isTraceEnabled()) logger.trace("Queue size "+queueSize+" >= upper threshold "+upperThreshold+". Waiting...");
          doWait(upperThresholdReachedWaitMSec);
        }
        logger.trace("Dequeueing elements from DB...");
        List<Workflow<?>> rv = dbStorage.dequeue(getId(), dequeueBulkSize);
        if (shutdown) break;
        if (rv.isEmpty()) {
          if (logger.isTraceEnabled()) logger.trace("Dequeue returned nothing. Waiting...");
          doWait(emptyQueueWaitMSec);
        }
        else {
          if (logger.isTraceEnabled()) logger.trace("Dequeue returned "+rv.size()+" elements.");
          for (Workflow<?> wf : rv) {
            WorkflowAccessor.setProcessingState(wf, ProcessingState.DEQUEUED);
            engine.register(wf);
          }
          synchronized (queue) {
            queue.addAll(rv);
            queue.notifyAll();
          }
        }
      }
      catch(InterruptedException e) {
        logger.info("interrupted");
      }
      catch(Exception e) {
        logger.error("dequeue failed",e);
      }
    }
    logger.info("stopped");
  }

  @Override
  public void doNotify() {
    logger.trace("doNotify");
    synchronized (mutex) {
      mutex.notify();
    }
  }
 
  private void doWait(long t) throws InterruptedException {
    if (logger.isTraceEnabled()) logger.trace("doWait("+t+")");
    synchronized (mutex) {
      mutex.wait(t);
    }
  }
 
  public void setLowerThreshold(int lowerThreshold) {
    if (lowerThreshold < 0 || lowerThreshold > upperThreshold) throw new IllegalArgumentException();
    this.lowerThreshold = lowerThreshold;
  }
 
  public int getLowerThreshold() {
    return lowerThreshold;
  }
 
  public void setUpperThreshold(int upperThreshold) {
    if (upperThreshold < 1 || upperThreshold < lowerThreshold) throw new IllegalArgumentException();
    this.upperThreshold = upperThreshold;
  }
 
  public int getUpperThreshold() {
    return upperThreshold;
  }

  public int getUpperThresholdReachedWaitMSec() {
    return upperThresholdReachedWaitMSec;
  }

  public void setUpperThresholdReachedWaitMSec(int upperThresholdReachedWaitMSec) {
    if (upperThresholdReachedWaitMSec <= 0) throw new IllegalArgumentException();
    this.upperThresholdReachedWaitMSec = upperThresholdReachedWaitMSec;
  }

  public int getEmptyQueueWaitMSec() {
    return emptyQueueWaitMSec;
  }

  public void setEmptyQueueWaitMSec(int emptyQueueWaitMSec) {
    if (emptyQueueWaitMSec <= 0) throw new IllegalArgumentException();
    this.emptyQueueWaitMSec = emptyQueueWaitMSec;
  }

  public int getDequeueBulkSize() {
    return dequeueBulkSize;
  }

  public void setDequeueBulkSize(int dequeueBulkSize) {
    if (dequeueBulkSize <= 0) throw new IllegalArgumentException();
    this.dequeueBulkSize = dequeueBulkSize;
  }
 
  protected TransactionController getTransactionController() {
    return transactionController;
  }


}
TOP

Related Classes of de.scoopgmbh.copper.persistent.PersistentPriorityProcessorPool

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.