Package org.apache.jetspeed.aggregator.impl

Source Code of org.apache.jetspeed.aggregator.impl.WorkerMonitorImpl$RenderingJobTimeoutMonitor

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements.  See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.jetspeed.aggregator.impl;

import java.security.AccessControlContext;
import java.security.AccessController;
import java.util.Iterator;
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
import java.util.LinkedList;
import java.util.Collections;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.jetspeed.aggregator.RenderingJob;
import org.apache.jetspeed.aggregator.Worker;
import org.apache.jetspeed.aggregator.WorkerMonitor;
import org.apache.jetspeed.aggregator.PortletContent;
import org.apache.jetspeed.util.Queue;
import org.apache.jetspeed.util.FIFOQueue;

import org.apache.pluto.om.window.PortletWindow;
import org.apache.pluto.om.common.ObjectID;

/**
* The WorkerMonitor is responsible for dispatching jobs to workers
* It uses an Apache HTTPd configuration style of min/max/spare workers
* threads to throttle the rendering work.
* If jobs come in faster that processing, they are stored in a queue
* which is flushed periodically by a QueueMonitor.
*
* @author <a href="mailto:raphael@apache.org">Rapha\u00ebl Luta</a>
* @author <a href="mailto:taylor@apache.org">David Sean Taylor </a>
* @version $Id: WorkerMonitorImpl.java 516448 2007-03-09 16:25:47Z ate $
*/
public class WorkerMonitorImpl implements WorkerMonitor
{
    public WorkerMonitorImpl(int minWorkers, int maxWorkers, int spareWorkers, int maxJobsPerWorker)
    {
        this.minWorkers = minWorkers;
        this.maxWorkers = maxWorkers;
        this.spareWorkers = spareWorkers;
        this.maxJobsPerWorker = maxJobsPerWorker;
    }
   
    /** Commons logging */
    protected final static Log log = LogFactory.getLog(WorkerMonitorImpl.class);

    /** Static counters for identifying workers */
    protected static long sCount = 0;

    /** Count of running jobs **/
    protected int runningJobs = 0;
   
    /** Minimum number of wokers to create */
    protected int minWorkers = 5;

    /** Maximum number of workers */
    protected int maxWorkers = 50;

    /** Minimum amount of spare workers */
    protected int spareWorkers = 3;

    /** Maximum of job processed by a worker before being released */
    protected int maxJobsPerWorker = 10;

    /** Stack containing currently idle workers */
    protected Stack workers = new Stack();

    /** The thread group used to group all worker threads */
    protected ThreadGroup tg = new ThreadGroup("Workers");

    /** Job queue */
    protected Queue queue;

    /** Workers to be monitored for timeout checking */
    protected List workersMonitored = Collections.synchronizedList(new LinkedList());

    /** Renering Job Timeout monitor */
    protected RenderingJobTimeoutMonitor jobMonitor = null;

    public void start()
    {
        addWorkers(this.minWorkers);
        setQueue(new FIFOQueue());

        jobMonitor = new RenderingJobTimeoutMonitor(1000);
        jobMonitor.start();
    }

    public void stop()
    {   
      if (jobMonitor != null)
        jobMonitor.endThread();
      jobMonitor = null;
     
    }
   
    public void setQueue(Queue queue)
    {
        this.queue = queue;
    }

    /**
     * Create the request number of workers and add them to
     * list of available workers.
     *
     * @param wCount the number of workers to create
     */
    protected synchronized void addWorkers(int wCount)
    {
        int wCurrent = this.tg.activeCount();

        if (wCurrent < maxWorkers)
        {
            if (wCurrent + wCount > maxWorkers)
            {
                wCount = maxWorkers - wCurrent;
            }

            log.info("Creating "+ wCount +" workers -> "+ (wCurrent + wCount));

            for (int i = 0; i < wCount; ++i)
            {
                Worker worker = new WorkerImpl(this, this.tg, "WORKER_" + (++sCount));
                worker.start();
                workers.push(worker);
            }
        }
    }

    /**
     * Retrieves an idle worker
     *
     * @return a Worker from the idle pool or null if non available
     */
    public Worker getWorker()
    {
        synchronized(this.workers)
        {
            if (this.workers.size() < spareWorkers)
            {
                addWorkers(spareWorkers);
            }

            if (this.workers.size() == 0)
            {
                return null;
            }

            return (Worker)workers.pop();
        }
    }

    /**
     * Assign a job to a worker and execute it or queue the job if no
     * worker is available.
     *
     * @param job the Job to process
     */
    public void process(RenderingJob job)
    {
        Worker worker = this.getWorker();

        AccessControlContext context = AccessController.getContext();
        if (worker==null)
        {
            queue.push(job);
            queue.push(context);
        }
        else
        {
            try
            {
                synchronized (worker)
                {
                    worker.setJob(job, context);

                    if (job.getTimeout() > 0) {
                        workersMonitored.add(worker);
                    }

                    worker.notify();
                    runningJobs++;
                }
            }
            catch (Throwable t)
            {
                log.error("Worker exception", t);
            }
        }
    }

    /**
     * Put back the worker in the idle queue unless there are pending jobs and
     * worker can still be committed to a new job before being released.
     */
    public void release(Worker worker)
    {
        // if worker can still proces some jobs assign the first
        // backlog job to this worker, else reset job count and put
        // it on the idle queue.

        long jobTimeout = 0;

        RenderingJob oldJob = (RenderingJob) worker.getJob();
        if (oldJob != null)
        {
            jobTimeout = oldJob.getTimeout();
        }

        synchronized (worker)
        {
            if ((worker.getJobCount()<this.maxJobsPerWorker)&&(queue.size()>0))
            {
                RenderingJob job = (RenderingJob)queue.pop();
                AccessControlContext context = (AccessControlContext)queue.pop();
                worker.setJob(job, context);
                runningJobs--;
                return;
            }
            else
            {
                worker.setJob(null);
                worker.resetJobCount();
                runningJobs--;
            }
        }

        if (jobTimeout > 0) {
            workersMonitored.remove(worker);
        }

        synchronized (this.workers)
        {
            this.workers.push(worker);
        }
    }

    public int getQueuedJobsCount()
    {
        return queue.size();
    }
   
    /**
     * Returns a snapshot of the available jobs
     * @return available jobs
     */
    public int getAvailableJobsCount()
    {
        return workers.size();
    }
   
    public int getRunningJobsCount()
    {
        return this.tg.activeCount();
    }
   
    class RenderingJobTimeoutMonitor extends Thread {

        long interval = 1000;
        boolean shouldRun = true;
       
        RenderingJobTimeoutMonitor(long interval) {
            super("RenderingJobTimeoutMonitor");

            if (interval > 0) {
                this.interval = interval;
            }
        }
        /**
         * Thread.stop() is deprecated.
         * This method achieves the same by setting the run varaible "shouldRun" to false and interrupting the Thread,
         * effectively causing the thread to shutdown correctly.
         *
         */
        public void endThread()
        {
          shouldRun = false;
          this.interrupt();
        }
       
        public void run() {
            while (shouldRun) {
                try
                {
                    // Because a timeout worker can be removed
                    // in the workersMonitored collection during iterating,
                    // copy timeout workers in the following collection to kill later.

                    List timeoutWorkers = new ArrayList();

                    synchronized (workersMonitored)
                    {
                        for (Iterator it = workersMonitored.iterator(); it.hasNext(); )
                        {
                            WorkerImpl worker = (WorkerImpl) it.next();
                            RenderingJob job = (RenderingJob) worker.getJob();
                           
                            if ((null != job) && (job.isTimeout()))
                            {
                                timeoutWorkers.add(worker);
                            }
                        }
                    }

                    // Now, we can kill the timeout worker(s).
                    for (Iterator it = timeoutWorkers.iterator(); it.hasNext(); )
                    {
                        WorkerImpl worker = (WorkerImpl) it.next();
                        RenderingJob job = (RenderingJob) worker.getJob();

                        // If the job is just completed, then do not kill the worker.
                        if ((null != job) && (job.isTimeout()))
                        {
                            killJob(worker, job);
                        }
                    }
                }
                catch (Exception e)
                {
                    log.error("Exception during job monitoring.", e);
                }
              
                try
                {
                    synchronized (this)
                    {
                        wait(this.interval);
                    }
                }
                catch (InterruptedException e)
                {
                    ;
                }
            }
        }

        public void killJob(WorkerImpl worker, RenderingJob job) {
            try {
                if (log.isWarnEnabled()) {
                    PortletWindow window = job.getWindow();
                    ObjectID windowId = (null != window ? window.getId() : null);
                    log.warn("Portlet Rendering job to be interrupted by timeout (" + job.getTimeout() + "ms): " + windowId);
                }

                int waitCount = 0;
                PortletContent content = job.getPortletContent();

                while (!content.isComplete()) {
                    if (++waitCount > 10) {
                        break;
                    }

                    worker.interrupt();

                    synchronized (content) {
                        content.wait();
                    }
                }
            } catch (Exception e) {
                log.error("Exceptiong during job killing.", e);
            }
        }

    }
}
TOP

Related Classes of org.apache.jetspeed.aggregator.impl.WorkerMonitorImpl$RenderingJobTimeoutMonitor

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.