/*
* 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/>.
*
* Sun designates this particular file as subject to the "Classpath"
* exception as provided by Sun in the LICENSE file that accompanied
* this code.
*
* --
*/
package com.sun.sgs.kernel;
import com.sun.sgs.app.TaskRejectedException;
import com.sun.sgs.auth.Identity;
/**
* This interface is used to schedule transactional tasks for immediate,
* delayed, or periodic execution. Transactional tasks are short-lived:
* typically on the order of a few 10s of milliseconds) and not longer than
* the value of the property {@code com.sun.sgs.txn.timeout}. All tasks run
* through an implementation of {@code TransactionScheduler} will run
* transactionally, and may be re-tried in the event of failure.
* <p>
* Many methods will make a best effort to schedule a given task to run, but
* based on the policy of the implementation, the task and its owner, may be
* unable to accept the given task. In this case {@code TaskRejectedException}
* is thrown. To ensure that a task will be accepted, methods are provided to
* get a {@code TaskReservation}. This is especially useful for {@code Service}
* methods working within a transaction that need to ensure that a task will
* be accepted before they can commit.
* <p>
* If the result of running a task via the {@code reserveTask} or
* {@code scheduleTask} methods is an {@code Exception} which implements
* {@code ExceptionRetryStatus}, then its {@code shouldRetry} method is
* called to decide if the task should be re-tried. It is up to the scheduler
* implementation's policy to decide how and when tasks are re-run, but all
* failing tasks run through a {@code TransactionScheduler} that wish to be
* re-tried will eventually be re-run given available resources.
* <p>
* Note that re-try is handled slightly differently for {@code runTask}. See
* the documentation on that method for more details.
*/
public interface TransactionScheduler {
/**
* Reserves the ability to run the given task.
*
* @param task the {@code KernelRunnable} to execute
* @param owner the entity on who's behalf this task is run
*
* @return a {@code TaskReservation} for the task
*
* @throws TaskRejectedException if a reservation cannot be made
*/
TaskReservation reserveTask(KernelRunnable task, Identity owner);
/**
* Reserves the ability to run the given task at a specified point in
* the future. The {@code startTime} is a value in milliseconds
* measured from 1/1/1970.
*
* @param task the {@code KernelRunnable} to execute
* @param owner the entity on who's behalf this task is run
* @param startTime the time at which to start the task
*
* @return a {@code TaskReservation} for the task
*
* @throws TaskRejectedException if a reservation cannot be made
*/
TaskReservation reserveTask(KernelRunnable task, Identity owner,
long startTime);
/**
* Schedules a task to run as soon as possible based on the specific
* scheduler implementation.
*
* @param task the {@code KernelRunnable} to execute
* @param owner the entity on who's behalf this task is run
*
* @throws TaskRejectedException if the given task is not accepted
*/
void scheduleTask(KernelRunnable task, Identity owner);
/**
* Schedules a task to run at a specified point in the future. The
* {@code startTime} is a value in milliseconds measured from
* 1/1/1970. If the starting time has already passed, then the task is
* run immediately.
*
* @param task the {@code KernelRunnable} to execute
* @param owner the entity on who's behalf this task is run
* @param startTime the time at which to start the task
*
* @throws TaskRejectedException if the given task is not accepted
*/
void scheduleTask(KernelRunnable task, Identity owner, long startTime);
/**
* Schedules a task to start running at a specified point in the future,
* and continuing running on a regular period starting from that
* initial point. Unlike the other {@code scheduleTask} methods, this
* method will never fail to accept to the task so there is no need for
* a reservation. Note, however, that the task will not actually start
* executing until {@code start} is called on the returned
* {@code RecurringTaskHandle}.
* <p>
* At each execution point the scheduler will make a best effort to run
* the task, but based on available resources scheduling the task may
* fail. Regardless, the scheduler will always try again at the next
* execution time.
*
* @param task the {@code KernelRunnable} to execute
* @param owner the entity on who's behalf this task is run
* @param startTime the time at which to start the task
* @param period the length of time in milliseconds between each
* recurring task execution
*
* @return a {@code RecurringTaskHandle} used to manage the
* recurring task
*
* @throws IllegalArgumentException if {@code period} is less than or
* equal to zero
*/
RecurringTaskHandle scheduleRecurringTask(KernelRunnable task,
Identity owner,
long startTime,
long period);
/**
* Runs the given task synchronously, returning when the task has
* completed or throwing an exception if the task fails. It is up to the
* {@code TransactionScheduler} implementation to decide when to run this
* task, so the task may be run immediately or it might be queued behind
* waiting tasks. The task may be handed off to another thread of control
* for execution. In all cases, the caller will block until the task
* completes or fails permanently.
* <p>
* As with all methods of {@code TransactionScheduler}, tasks run with
* {@code runTask} will be run transactionally. If the caller is not
* in an active transaction, then a transaction is created to run the
* task. If the caller is already part of an active transaction, then
* the task is run as part of that transaction, and the {@code owner}
* paramater is ignored.
* <p>
* When the caller is not part of an active transaction, then when the
* given task completes it will also attempt to commit. If committing
* the transaction fails, normal re-try behavior is applied. If the
* task requests to be re-tried, then it will be re-run according to the
* scheduler implementation's policy. In this case, {@code runTask}
* will not return until the task finally succeeds, or is no longer
* re-tried.
* <p>
* In the event that the caller is part of an active transaction, then
* there is no re-try applied in the case of a failure, and the
* transaction is not committed if the task completes successfully. This
* is because the system does not support nested transactions, and so
* the decision to commit or re-try is left to the active transaction.
*
* @param task the {@code KernelRunnable} to execute
* @param owner the entity on who's behalf this task is run
*
* @throws TaskRejectedException if the given task is not accepted
* @throws InterruptedException if the calling thread is interrupted and
* the associated task does not complete
* @throws Exception if the task fails and is not re-tried
*/
void runTask(KernelRunnable task, Identity owner) throws Exception;
/**
* Creates a new {@code TaskQueue} to use in scheduling dependent
* tasks. Each task added to the queue will be run in a separate
* transaction. Re-try is applied to each transaction, and the next
* task in the queue is run only after the current task either
* completes successfully or fails permanently.
*
* @return a new {@code TaskQueue}
*/
TaskQueue createTaskQueue();
}