Package com.sun.sgs.impl.kernel

Source Code of com.sun.sgs.impl.kernel.TransactionSchedulerImpl$TaskConsumer

/*
* Copyright 2007-2010 Sun Microsystems, Inc.
*
* This file is part of Project Darkstar Server.
*
* Project Darkstar Server is free software: you can redistribute it
* and/or modify it under the terms of the GNU General Public License
* version 2 as published by the Free Software Foundation and
* distributed hereunder to you.
*
* Project Darkstar Server is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program.  If not, see <http://www.gnu.org/licenses/>.
*
* --
*/

package com.sun.sgs.impl.kernel;

import com.sun.sgs.app.TaskRejectedException;

import com.sun.sgs.auth.Identity;

import com.sun.sgs.kernel.schedule.ScheduledTask;
import com.sun.sgs.kernel.schedule.SchedulerQueue;
import com.sun.sgs.kernel.schedule.SchedulerRetryPolicy;

import com.sun.sgs.impl.profile.ProfileCollectorHandle;
import com.sun.sgs.impl.service.transaction.TransactionCoordinator;
import com.sun.sgs.impl.service.transaction.TransactionHandle;

import com.sun.sgs.impl.sharedutil.LoggerWrapper;
import com.sun.sgs.impl.sharedutil.PropertiesWrapper;

import com.sun.sgs.impl.util.NamedThreadFactory;

import com.sun.sgs.kernel.KernelRunnable;
import com.sun.sgs.kernel.Priority;
import com.sun.sgs.kernel.PriorityScheduler;
import com.sun.sgs.kernel.RecurringTaskHandle;
import com.sun.sgs.kernel.TaskQueue;
import com.sun.sgs.kernel.TaskReservation;
import com.sun.sgs.kernel.TransactionScheduler;

import com.sun.sgs.profile.ProfileListener;
import com.sun.sgs.profile.ProfileReport;

import com.sun.sgs.service.Transaction;

import java.beans.PropertyChangeEvent;

import java.lang.reflect.InvocationTargetException;

import java.util.LinkedList;
import java.util.Properties;
import java.util.Queue;

import java.util.concurrent.Executors;
import java.util.concurrent.ExecutorService;

import java.util.concurrent.atomic.AtomicInteger;

import java.util.logging.Level;
import java.util.logging.Logger;


/**
* Package-private implementation of {@code TransactionScheduler} that is
* used by the system for scheduling and running all transactional tasks.
* This class supports the following configuration properties:
* <dl style="margin-left: 1em">
*
* <dt> <i>Property:</i> <code><b>{@value #CONSUMER_THREADS_PROPERTY}
</b></code> <br>
<i>Default:</i> <code>{@value #DEFAULT_CONSUMER_THREADS}</code>
*
* <dd style="padding-top: .5em">The number of initial threads used to process
*      transactional tasks.<p>
*
* <dt> <i>Property:</i> <code><b>{@value #SCHEDULER_QUEUE_PROPERTY}
</b></code> <br>
<i>Default:</i> <code>{@value #DEFAULT_SCHEDULER_QUEUE}</code>
*
* <dd style="padding-top: .5em">The implementation class used to track
*      access to define which queue implementation should back this scheduler.
*      The value of this property should be the
*      name of a public, non-abstract class that implements the
*      {@link SchedulerQueue} interface, and that provides a public
*      constructor with the parameters {@link Properties}<p>
*
* <dt> <i>Property:</i> <code><b>{@value #SCHEDULER_RETRY_PROPERTY}
</b></code> <br>
<i>Default:</i> <code>{@value #DEFAULT_SCHEDULER_RETRY}</code>
*
* <dd style="padding-top: .5em">The implementation class used to define
*      which retry policy implementation to use when tasks fail or abort.
*      The value of this property should be the
*      name of a public, non-abstract class that implements the
*      {@link SchedulerRetryPolicy} interface, and that provides a public
*      constructor with the parameters {@link Properties}<p>
*
* </dl>
*/
final class TransactionSchedulerImpl
    implements TransactionScheduler, PriorityScheduler, ProfileListener
{

    // logger for this class
    private static final LoggerWrapper logger =
        new LoggerWrapper(Logger.getLogger(TransactionSchedulerImpl.
                                           class.getName()));

    /**
     * The property used to define which queue implementation should back
     * this scheduler.
     */
    public static final String SCHEDULER_QUEUE_PROPERTY =
            "com.sun.sgs.impl.kernel.scheduler.queue";

    /**
     * The default scheduler.
     */
    public static final String DEFAULT_SCHEDULER_QUEUE =
            "com.sun.sgs.impl.kernel.schedule.FIFOSchedulerQueue";

    /**
     * The property used to define which retry policy should be used in
     * this scheduler
     */
    public static final String SCHEDULER_RETRY_PROPERTY =
            "com.sun.sgs.impl.kernel.scheduler.retry";

    /**
     * The default retry policy
     */
    public static final String DEFAULT_SCHEDULER_RETRY =
            "com.sun.sgs.impl.kernel.schedule.ImmediateRetryPolicy";

    /**
     * The property used to define the default number of initial consumer
     * threads.
     */
    public static final String CONSUMER_THREADS_PROPERTY =
        "com.sun.sgs.impl.kernel.transaction.threads";

    /**
     * The default number of initial consumer threads.
     */
    public static final String DEFAULT_CONSUMER_THREADS = "4";

    // the default priority for tasks
    private static final Priority defaultPriority =
        Priority.getDefaultPriority();

    // the coordinator used to create and coordinate transactions
    private final TransactionCoordinator transactionCoordinator;

    // the backing scheduler queue used for ordering tasks
    private final SchedulerQueue backingQueue;

    // the retry policy used for this scheduler
    private final SchedulerRetryPolicy retryPolicy;

    // the collector handle used for profiling data
    private final ProfileCollectorHandle profileCollectorHandle;

    // the coordinator for all transactional object access
    private final AccessCoordinatorHandle accessCoordinator;

    // the executor service used to manage our threads
    private final ExecutorService executor;

    // the actual number of threads we're currently using
    private final AtomicInteger threadCount = new AtomicInteger(0);

    // the number of requested consumer threads
    private final int requestedThreads;

    // flag to note that this scheduler has shutdown
    private volatile boolean isShutdown = false;

    // the context we're using for the application's tasks
    private volatile KernelContext kernelContext = null;

    // the number of dependent tasks sitting in queues
    private final AtomicInteger dependencyCount = new AtomicInteger(0);


    /**
     * Creates an instance of {@code TransactionSchedulerImpl}.
     *
     * @param properties the {@code Properties} for the system
     * @param transactionCoordinator the {@code TransactionCoordinator} used
     *                               by the system to manage transactions
     * @param profileCollectorHandle the {@code ProfileCollectorHandler} used to
     *          manage collection of per-task profiling data
     * @param accessCoordinator the {@code AccessCoordinator} used by
     *                          the system to managed shared data
     *
     * @throws InvocationTargetException if there is a failure initializing
     *                                   the {@code SchedulerQueue}
     * @throws Exception if there is any failure creating the scheduler
     */
    TransactionSchedulerImpl(Properties properties,
                             TransactionCoordinator transactionCoordinator,
                             ProfileCollectorHandle profileCollectorHandle,
                             AccessCoordinatorHandle accessCoordinator)
        throws Exception
    {
        logger.log(Level.CONFIG, "Creating TransactionSchedulerImpl");
        if (properties == null) {
            throw new NullPointerException("Properties cannot be null");
        }
        if (transactionCoordinator == null) {
            throw new NullPointerException("Coordinator cannot be null");
        }
        if (profileCollectorHandle == null) {
            throw new NullPointerException("Collector handle cannot be null");
        }
  if (accessCoordinator == null) {
      throw new NullPointerException("AccessCoordinator cannot be null");
        }

        PropertiesWrapper wrappedProps = new PropertiesWrapper(properties);

        this.transactionCoordinator = transactionCoordinator;
        this.profileCollectorHandle = profileCollectorHandle;
        this.accessCoordinator = accessCoordinator;
       
        this.backingQueue = wrappedProps.getClassInstanceProperty(
                SCHEDULER_QUEUE_PROPERTY, DEFAULT_SCHEDULER_QUEUE,
                SchedulerQueue.class, new Class[]{Properties.class},
                properties);
        this.retryPolicy = wrappedProps.getClassInstanceProperty(
                SCHEDULER_RETRY_PROPERTY, DEFAULT_SCHEDULER_RETRY,
                SchedulerRetryPolicy.class, new Class[]{Properties.class},
                properties);

        // startup the requested number of consumer threads
        // NOTE: this is a simple implmentation to replicate the previous
        // behvavior, with the assumption that it will change if the
        // scheduler starts trying to add or drop consumers adaptively
        this.requestedThreads =
            Integer.parseInt(properties.getProperty(CONSUMER_THREADS_PROPERTY,
                                                    DEFAULT_CONSUMER_THREADS));
        this.executor = Executors.newCachedThreadPool(
                new NamedThreadFactory("TransactionScheduler"));
        for (int i = 0; i < requestedThreads; i++) {
            executor.submit(new TaskConsumer());
        }

        // initialize the default timeout for scheduled tasks
        ScheduledTaskImpl.Builder.setDefaultTimeout(
                transactionCoordinator.getDefaultTimeout());

        logger.log(Level.CONFIG,
                   "Created TransactionSchedulerImpl with properties:" +
                   "\n  " + SCHEDULER_RETRY_PROPERTY + "=" +
                   retryPolicy.getClass().getName() +
                   "\n  " + SCHEDULER_QUEUE_PROPERTY + "=" +
                   backingQueue.getClass().getName() +
                   "\n  " + CONSUMER_THREADS_PROPERTY + "=" + requestedThreads);
    }

    /**
     * Package-private method used to set the context being used by the kernel.
     *
     * @param kernelContext the {@code KernelContext} for this scheduler
     */
    void setContext(KernelContext kernelContext) {
        this.kernelContext = kernelContext;
    }

    /*
     * Implementations of the TransactionScheduler interface.
     */

    /**
     * {@inheritDoc}
     */
    public TaskReservation reserveTask(KernelRunnable task, Identity owner) {
        ScheduledTaskImpl t = new ScheduledTaskImpl.Builder(
                task, owner, defaultPriority).build();
        return backingQueue.reserveTask(t);
    }

    /**
     * {@inheritDoc}
     */
    public TaskReservation reserveTask(KernelRunnable task, Identity owner,
                                       long startTime)
    {
        ScheduledTaskImpl t = new ScheduledTaskImpl.Builder(
                task, owner, defaultPriority).startTime(startTime).build();
        return backingQueue.reserveTask(t);
    }

    /**
     * {@inheritDoc}
     */
    public void scheduleTask(KernelRunnable task, Identity owner) {
        backingQueue.addTask(new ScheduledTaskImpl.Builder(
                task, owner, defaultPriority).build());
    }

    /**
     * {@inheritDoc}
     */
    public void scheduleTask(KernelRunnable task, Identity owner,
                             long startTime)
    {
        backingQueue.addTask(new ScheduledTaskImpl.Builder(
                task, owner, defaultPriority).startTime(startTime).build());
    }

    /**
     * {@inheritDoc}
     */
    public RecurringTaskHandle scheduleRecurringTask(KernelRunnable task,
                                                     Identity owner,
                                                     long startTime,
                                                     long period)
    {
        ScheduledTaskImpl scheduledTask = new ScheduledTaskImpl.Builder(
                task, owner, defaultPriority).
                startTime(startTime).
                period(period).
                build();
        RecurringTaskHandle handle =
            backingQueue.createRecurringTaskHandle(scheduledTask);
        scheduledTask.setRecurringTaskHandle(handle);
        return handle;
    }

    /**
     * {@inheritDoc}
     */
    public TaskQueue createTaskQueue() {
        if (isShutdown) {
            throw new IllegalStateException("Scheduler is shutdown");
        }
        return new TaskQueueImpl();
    }

    /**
     * {@inheritDoc}
     */
    public void runTask(KernelRunnable task, Identity owner) throws Exception {
        if (isShutdown) {
            throw new IllegalStateException("Scheduler is shutdown");
        }
        if (ContextResolver.isCurrentTransaction()) {
            // we're already active in a transaction, so just run the task
            task.run();
        } else {
            // we're starting a new transaction
            ScheduledTaskImpl scheduledTask = new ScheduledTaskImpl.Builder(
                    task, owner, defaultPriority).build();
            waitForTask(scheduledTask);
        }
    }

    /*
     * Implementations of the PriorityScheduler interface.
     */

    /**
     * {@inheritDoc}
     */
    public TaskReservation reserveTask(KernelRunnable task, Identity owner,
                                       Priority priority)
    {
        ScheduledTaskImpl t = new ScheduledTaskImpl.Builder(
                task, owner, priority).build();
        return backingQueue.reserveTask(t);
    }

    /**
     * {@inheritDoc}
     */
    public void scheduleTask(KernelRunnable task, Identity owner,
                             Priority priority)
    {
        backingQueue.addTask(new ScheduledTaskImpl.Builder(
                task, owner, priority).build());
    }

    /*
     * Implementations for the ProfileListener interface.
     */

    /**
     * {@inheritDoc}
     */
    public void propertyChange(PropertyChangeEvent event) {
        // see comment in notifyThreadLeaving
    }

    /**
     * {@inheritDoc}
     */
    public void report(ProfileReport profileReport) {
        // see comment in notifyThreadLeaving
    }

    /**
     * {@inheritDoc}
     */
    public void shutdown() {
        synchronized (this) {
            if (isShutdown) {
                return; // return silently
            }
            isShutdown = true;

            executor.shutdownNow();
            backingQueue.shutdown();
        }
    }

    /*
     * Utility methods and classes.
     */

    /**
     * Private method that blocks until the task has completed, re-throwing
     * any exception resulting from the task failing.
     */
    private void waitForTask(ScheduledTaskImpl task)
        throws Exception
    {
        Throwable t = null;

        try {
            // NOTE: calling executeTask() directly means that we're trying
            // to run the transaction in the calling thread, so there are
            // actually more threads running tasks simulaneously than there
            // are threads in the scheduler pool. This could be changed to
            // hand-off the task and wait for the result if we wanted more
            // direct control over concurrent transactions
            executeTask(task, false);
            // wait for the task to complete...at this point it may have
            // already completed, or else it is being re-tried in a
            // scheduler thread
            t = task.get();
        } catch (InterruptedException ie) {
            // we were interrupted, so try to cancel the task, re-throwing
            // the interruption if that succeeds or looking at the result
            // if the task completes before it can be cancelled
            if (task.cancel(true)) {
                backingQueue.notifyCancelled(task);
                throw ie;
            }
            if (task.isCancelled()) {
                throw ie;
            }
            t = task.get();
        }

        // if the result of the task was a permananent failure, then
        // re-throw the exception
        if (t != null) {
            if (t instanceof Exception) {
                throw (Exception) t;
            }
            throw (Error) t;
        }
    }

    /**
     * Package-private method that runs the given task in a transaction that
     * is not bound by any timeout value (i.e., is bound only by the
     * {@code com.sun.sgs.txn.timeout.unbounded} property value).
     *
     * @param task the {@code KernelRunnable} to run transactionally
     * @param owner the {@code Identity} that owns the task
     *
     * @throws IllegalStateException if this method is called from an
     *                               actively running transaction
     * @throws Exception if there is any failure that does not result in
     *                   re-trying the task
     */
    void runUnboundedTask(KernelRunnable task, Identity owner)
        throws Exception
    {
        if (isShutdown) {
            throw new IllegalStateException("Scheduler is shutdown");
        }
        if (ContextResolver.isCurrentTransaction()) {
            throw new IllegalStateException("Cannot be called from within " +
                                            "an active transaction");
        }

        // NOTE: in the current system we only use this method once, and
        // that's when the application is initialized, in which case there
        // is no other task trying to run...if we decide to start using
        // this method more broadly, then it should probably use a separate
        // thread-pool so that it doesn't affect transaction latency

        ScheduledTaskImpl scheduledTask = new ScheduledTaskImpl.Builder(
                task, owner, defaultPriority).
                timeout(ScheduledTask.UNBOUNDED).
                build();
        waitForTask(scheduledTask);
    }

    /**
     * Notifies the scheduler that a thread has been started to consume
     * tasks as they become ready.
     */
    private void notifyThreadJoining() {
        profileCollectorHandle.notifyThreadAdded();
        threadCount.incrementAndGet();
    }

    /**
     * Notifies the scheduler that a thread has been interrupted and is
     * finishing its work.
     */
    private void notifyThreadLeaving() {
        profileCollectorHandle.notifyThreadRemoved();
        // NOTE: we're not yet trying to adapt the number of threads being
        // used, so we assume that threads are only lost when the system
        // wants to shutdown...in practice, this should look at some
        // threshold and see if another consumer needs to be created
        if (threadCount.decrementAndGet() == 0) {
            logger.log(Level.CONFIG, "No more threads are consuming tasks");
            shutdown();
        }
    }

    /**
     * Private {@code Runnable} used to consume tasks as they become available
     * from the {@code SchedulerQueue}. Once started, it will continue
     * running until it catches an {@code InterruptedException}.
     */
    private class TaskConsumer implements Runnable {
        /** {@inheritDoc} */
        public void run() {
            logger.log(Level.FINE, "Starting a consumer for transactions");
            notifyThreadJoining();

            try {
                while (true) {
                    // wait for the next task, at which point we may get
                    // interrupted and should therefore return
                    ScheduledTaskImpl task =
                        (ScheduledTaskImpl) (backingQueue.getNextTask(true));

                    // run the task, checking if it completed
                    if (executeTask(task, true)) {
                        // if it's a recurring task, schedule the next run
                        if (task.isRecurring()) {
                            long nextStart =
                                 task.getStartTime() + task.getPeriod();
                            task = new ScheduledTaskImpl.Builder(
                                    task).startTime(nextStart).build();
                            backingQueue.addTask(task);
                        }
                        // if it has dependent tasks, schedule the next one
                        TaskQueueImpl queue =
                                      (TaskQueueImpl) (task.getTaskQueue());
                        if (queue != null) {
                            queue.scheduleNextTask();
                        }
                    }
                }
            } catch (InterruptedException ie) {
                if (logger.isLoggable(Level.FINE)) {
                    logger.logThrow(Level.FINE, ie, "Consumer is finishing");
                }
            } catch (Exception e) {
                // this should never happen, since running the task should
                // never throw an exception that isn't handled
                logger.logThrow(Level.SEVERE, e, "Fatal error for consumer");
            } finally {
                notifyThreadLeaving();
            }
        }
    }

    /**
     * Private method that executes a single task, creating the transaction
     * state and handling re-try as appropriate. If the thread calling this
     * method is interrupted before the task can complete then this method
     * attempts to re-schedule the task to run in another thread if
     * {@code retryOnInterruption} is {@code true} and always re-throws
     * the associated {@code InterruptedException}.
     * <p>
     * This method returns {@code true} if the task was completed or failed
     * permanently, and {@code false} otherwise. If {@code false} is returned
     * then the task is scheduled to be re-tried at some point in the future,
     * possibly by another thread, by this method. The caller may query the
     * status of the task and wait for the task to complete or fail permanently
     * through the {@code ScheduledTaskImpl} interface.
     */
    private boolean executeTask(ScheduledTaskImpl task,
                                boolean retryOnInterruption)
        throws InterruptedException
    {
        logger.log(Level.FINEST, "starting a new transactional task");

        // store the current owner, and then push the new thread detail
        Identity parent = ContextResolver.getCurrentOwner();
        ContextResolver.setTaskState(kernelContext, task.getOwner());

        try {
            // keep trying to run the task until we succeed, tracking how
            // many tries it actually took
            while (true) {
                if (!task.setRunning(true)) {
                    // this task is already finished
                    return true;
                }

                // NOTE: We could report the queue sizes separately,
                // so we should figure out how we want to represent these
                int waitSize =
                    backingQueue.getReadyCount() +
                    dependencyCount.get();
                profileCollectorHandle.startTask(task.getTask(),
                                                 task.getOwner(),
                                                 task.getStartTime(),
                                                 waitSize);
                task.incrementTryCount();

                Transaction transaction = null;

                try {
                    // setup the transaction state
                    TransactionHandle handle =
                            transactionCoordinator.createTransaction(
                            task.getTimeout());
                    transaction = handle.getTransaction();
                    ContextResolver.setCurrentTransaction(transaction);
                   
                    try {
                        // notify the profiler and access coordinator
                        profileCollectorHandle.noteTransactional(
                                                    transaction.getId());
                        accessCoordinator.
                            notifyNewTransaction(transaction,
             task.getStartTime(),
                                                 task.getTryCount());

                        // run the task in the new transactional context
                        task.getTask().run();
                    } finally {
                        // regardless of the outcome, always clear the current
                        // transaction state before proceeding...
                        ContextResolver.clearCurrentTransaction(transaction);
                    }

                    // try to commit the transaction...note that there's the
                    // chance that the application code masked the orginal
                    // cause of a failure, so we'll check for that first,
                    // re-throwing the root cause in that case
                    if (transaction.isAborted()) {
                        throw transaction.getAbortCause();
                    }
                    handle.commit();

                    // the task completed successfully, so we're done
                    profileCollectorHandle.finishTask(task.getTryCount());
                    task.setDone(null);
                    return true;
                } catch (InterruptedException ie) {
                    // make sure the transaction was aborted
                    if (!transaction.isAborted()) {
                        transaction.abort(ie);
                    }
                    profileCollectorHandle.finishTask(task.getTryCount(), ie);
                    task.setLastFailure(ie);

                    // if the task didn't finish because of the interruption
                    // then we want to note that and possibly re-queue the
                    // task to run in a usable thread
                    if (task.setInterrupted() && retryOnInterruption) {
                        if (!handoff(task)) {
                            // if the task couldn't be re-queued, then there's
                            // nothing left to do but drop it
                            task.setDone(ie);
                            if (logger.isLoggable(Level.WARNING)) {
                                logger.logThrow(Level.WARNING, ie,
                                                "dropping an " +
                                                "interrupted task: {0}",
                                                task);
                            }
                        }
                    }
                    // always re-throw the interruption
                    throw ie;
                } catch (Throwable t) {
                    // make sure the transaction was aborted
                    if ((transaction != null) && (!transaction.isAborted())) {
                        transaction.abort(t);
                    }
                    profileCollectorHandle.finishTask(task.getTryCount(), t);
                    task.setLastFailure(t);

                    // some error occurred, so see if we should re-try
                    switch (retryPolicy.getRetryAction(task)) {
                        case DROP:
                            task.setDone(t);
                            if (logger.isLoggable(Level.WARNING)) {
                                if (task.isRecurring()) {
                                    logger.logThrow(Level.WARNING, t,
                                                    "skipping a recurrence " +
                                                    "of a task that failed: " +
                                                    "{0}", task);
                                } else {
                                    logger.logThrow(Level.WARNING, t,
                                                    "dropping a task that " +
                                                    "failed: {0}", task);
                                }
                            }
                            return true;
                        case RETRY_LATER:
                            task.setRunning(false);
                            if (handoff(task)) {
                                return false;
                            }
                            break;
                        case RETRY_NOW:
                            task.setRunning(false);
                            break;
                        default:
                            // we should never get here
                    }
                }
            }
        } finally {
            // always restore the previous owner before leaving...
            ContextResolver.setTaskState(kernelContext, parent);
        }
    }

    /**
     * Hands off the task to the backing queue.
     *
     * @param task the task to handoff
     * @return {@code true} if handoff was successful, {@code false} otherwise
     */
    private boolean handoff(ScheduledTaskImpl task) {
        try {
            backingQueue.addTask(task);
            return true;
        } catch (TaskRejectedException tre) {
            return false;
        }
    }

    /** Private implementation of {@code TaskQueue}. */
    private final class TaskQueueImpl implements TaskQueue {
        private final Queue<ScheduledTaskImpl> queue =
            new LinkedList<ScheduledTaskImpl>();
        private boolean inScheduler = false;
        /** {@inheritDoc} */
        public void addTask(KernelRunnable task, Identity owner) {
            ScheduledTaskImpl schedTask = new ScheduledTaskImpl.Builder(
                    task, owner, defaultPriority).build();
            schedTask.setTaskQueue(this);

            synchronized (this) {
                if (inScheduler) {
                    dependencyCount.incrementAndGet();
                    queue.offer(schedTask);
                } else {
                    inScheduler = true;
                    backingQueue.addTask(schedTask);
                }
            }
        }
        /** Private method to schedule the next task, if any. */
        void scheduleNextTask() {
            synchronized (this) {
                if (queue.isEmpty()) {
                    inScheduler = false;
                } else {
                    dependencyCount.decrementAndGet();
                    // re-set the start time before scheduling, since the
                    // task isn't really requested to start until all
                    // tasks ahead of it have run
                    ScheduledTaskImpl schedTask = queue.poll();
                    schedTask.resetStartTime();
                    backingQueue.addTask(schedTask);
                }
            }
        }
    }

}
TOP

Related Classes of com.sun.sgs.impl.kernel.TransactionSchedulerImpl$TaskConsumer

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.