Package de.scoopgmbh.copper.persistent.adapter

Source Code of de.scoopgmbh.copper.persistent.adapter.NonTransactionalAdapterQueue$DefaultWorkerThread

/*
* 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.adapter;

import java.sql.Connection;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashSet;
import java.util.List;
import java.util.Set;
import java.util.concurrent.PriorityBlockingQueue;

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

import de.scoopgmbh.copper.batcher.Batcher;
import de.scoopgmbh.copper.persistent.adapter.AdapterCallPersisterFactory.Selector;
import de.scoopgmbh.copper.persistent.txn.DatabaseTransaction;
import de.scoopgmbh.copper.persistent.txn.TransactionController;
import edu.umd.cs.findbugs.annotations.SuppressWarnings;

public class NonTransactionalAdapterQueue {
 
  private static final Logger logger = LoggerFactory.getLogger(ReloadThread.class);

  final int transientQueueLength;
  final int triggerReloadQueueLength;
  final AdapterCallPersisterFactory persistence;
  final TransactionController ctrl;
  final Collection<String> adapterIds;
  final PriorityBlockingQueue<AdapterCall> queue;
  volatile boolean run = true;
  volatile boolean stopped = false;
  final Object reloadLock = new Object();
  final Set<Thread> waitingThreads = new HashSet<Thread>();
  final ReloadThread reloadThread;
  final Batcher batcher;
 
  class ReloadThread extends Thread {
   
    {
      setDaemon(true);
    }

    long waitMillis;
    static final long MAX_WAIT_MILLIS = 2000;

   
    @Override
    public void run() {
      waitMillis = 1;
      loop: while (run) {
        synchronized (reloadLock) {
          try {
            waitMillis *= 4;
            if (waitMillis > MAX_WAIT_MILLIS)
              waitMillis = MAX_WAIT_MILLIS;
            reloadLock.wait(waitMillis);
          } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            continue loop;
          }
        }
        if (run && queue.size() < triggerReloadQueueLength) {
          try {
            List<AdapterCall> newElements = ctrl.run(new DatabaseTransaction<List<AdapterCall>>() {
              @Override
              public List<AdapterCall> run(Connection con) throws Exception {
                Selector s = persistence.createSelector();
                return s.dequeue(con, adapterIds, transientQueueLength-queue.size());
              }
            });
            if (!newElements.isEmpty())
              waitMillis = 1;
            queue.addAll(
              newElements
            );
          } catch (Exception e) {
            logger.error("Dequeue error",e);
          }
        }
      }
      stopped = true;
      synchronized (waitingThreads) {
        for (Thread t : waitingThreads) {
          t.interrupt();
        }
      }
    }
  }
 

  public NonTransactionalAdapterQueue(Collection<String> adapterIds, AdapterCallPersisterFactory persistence, int transientQueueLength, TransactionController ctrl, Batcher batcher) {
    this (adapterIds, persistence, transientQueueLength, transientQueueLength, ctrl, batcher);
  }
 
  @SuppressWarnings("SC_START_IN_CTOR")
  public NonTransactionalAdapterQueue(Collection<String> adapterIds, AdapterCallPersisterFactory persistence, int transientQueueLength, int triggerReloadQueueLength, TransactionController ctrl, Batcher batcher) {
    this.transientQueueLength = transientQueueLength;
    this.triggerReloadQueueLength = triggerReloadQueueLength;
    this.persistence = persistence;
    this.adapterIds = new ArrayList<String>(adapterIds);
    this.ctrl = ctrl;
    this.batcher = batcher;
    this.queue = new PriorityBlockingQueue<AdapterCall>(transientQueueLength, new Comparator<AdapterCall>() {

      @Override
      public int compare(AdapterCall o1, AdapterCall o2) {
        if (o1.getPriority() < o2.getPriority())
          return -1;
        if (o1.getPriority() > o2.getPriority())
          return 1;
        return 0;
      }
     
    });
    this.reloadThread = new ReloadThread();
    this.reloadThread.start();
    this.triggerReload();
  }
 
 
  public AdapterCall dequeue() throws InterruptedException {
    synchronized (waitingThreads) {
      waitingThreads.add(Thread.currentThread());
    }
    AdapterCall c = null;
    try {
      while (run) {
        try {
          c = queue.take();
          break;
        } catch (InterruptedException ex) {
          if (isRunning()) /* interrupt from unknown origin */
            continue;
        }
      }
     
      if (c == null) {
        c = queue.poll();
        if (c == null)
          throw new InterruptedException();
      }
    } finally {
      synchronized (waitingThreads) {
        waitingThreads.remove(Thread.currentThread());
      }
    }
    if (queue.size() < triggerReloadQueueLength && run)
      triggerReload();
    return c;
  }
 
  public void finished(AdapterCall c) {
    batcher.submitBatchCommand(persistence.createDeleteCommand(c));
  }
 
  protected boolean isRunning() {
    return !stopped;
  }
 
  public void shutdown() {
    run = false;
    reloadThread.interrupt();
    try {
      reloadThread.join();
    } catch (InterruptedException e) {
      Thread.currentThread().interrupt();
    }
  }

  private void triggerReload() {
    synchronized (reloadLock) {
      reloadLock.notify();
    }
  }
 
 
  public static abstract class DefaultWorkerThread extends Thread {
   
    final NonTransactionalAdapterQueue queue;
   
    public DefaultWorkerThread(NonTransactionalAdapterQueue queue) {
      this.queue = queue;
    }
   
    @Override
    public void run() {
      while (queue.isRunning()) {
        try {
          AdapterCall c = queue.dequeue();
          try {
            handle(c);
          } finally {
            queue.finished(c);
          }
        } catch (InterruptedException e) {
        }
      }
     
    }

    protected abstract void handle(AdapterCall c);
   
  }

}
TOP

Related Classes of de.scoopgmbh.copper.persistent.adapter.NonTransactionalAdapterQueue$DefaultWorkerThread

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.