/*
 * 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.ignite.spi.collision;

import org.apache.ignite.events.EventType;
import org.apache.ignite.spi.IgniteSpi;
import org.jetbrains.annotations.Nullable;

/**
 * Collision SPI allows to regulate how grid jobs get executed when they arrive on a
 * destination node for execution. Its functionality is similar to tasks management via
 * <b>customizable</b> GCD (Great Central Dispatch) on Mac OS X as it allows developer to provide
 * custom job dispatching on a single node. In general a grid node will have multiple jobs
 * arriving to it for execution and potentially multiple jobs that are already executing or waiting
 * for execution on it. There are multiple possible strategies dealing with this situation, like
 * all jobs can proceed in parallel, or jobs can be serialized i.e., or only one job can execute
 * in any given point of time, or only certain number or types of grid jobs can proceed in
 * parallel, etc...
 * <p>
 * Collision SPI provides developer with ability to use the custom logic in determining how
 * grid jobs should be executed on a destination grid node. Ignite comes with the following
 * ready implementations for collision resolution that cover most popular strategies:
 * <ul>
 *      <li>{@link org.apache.ignite.spi.collision.fifoqueue.FifoQueueCollisionSpi}</li>
 *      <li>{@link org.apache.ignite.spi.collision.priorityqueue.PriorityQueueCollisionSpi}</li>
 *      <li>{@link org.apache.ignite.spi.collision.jobstealing.JobStealingCollisionSpi}</li>
 * </ul>
 * <b>NOTE:</b> this SPI (i.e. methods in this interface) should never be used directly. SPIs provide
 * internal view on the subsystem and is used internally by Ignite kernal. In rare use cases when
 * access to a specific implementation of this SPI is required - an instance of this SPI can be obtained
 * via {@link org.apache.ignite.Ignite#configuration()} method to check its configuration properties or call other non-SPI
 * methods. Note again that calling methods from this interface on the obtained instance can lead
 * to undefined behavior and explicitly not supported.
 */
public interface CollisionSpi extends IgniteSpi {
    /**
     * This is a callback called:
     * <ul>
     *      <li>new grid job arrived</li>
     *      <li>executing job finished its execution</li>
     *      <li>topology changed</li>
     *     <li>periodically (on {@link EventType#EVT_NODE_METRICS_UPDATED})</li>
     * </ul>
     * When new job arrives it is added to the end of the wait list and this
     * method is called. When job finished its execution, it is removed from the active list and
     * this method is called (i.e., when grid job is finished it will not appear in any list
     * in collision resolution).
     * <p>
     * Implementation of this method should act on all lists, each of which contains collision
     * job contexts that define a set of operations available during collision resolution. Refer
     * to {@link CollisionContext} and {@link CollisionJobContext} documentation for
     * more information.
     *
     * @param ctx Collision context which contains all collision lists.
     */
    public void onCollision(CollisionContext ctx);

    /**
     * Listener to be set for notification of external collision events (e.g. job stealing).
     * Once grid receives such notification, it will immediately invoke collision SPI.
     * <p>
     * Ignite uses this listener to enable job stealing from overloaded to underloaded nodes.
     * However, you can also utilize it, for instance, to provide time based collision
     * resolution. To achieve this, you most likely would mark some job by setting a certain
     * attribute in job context (see {@link org.apache.ignite.compute.ComputeJobContext}) for a job that requires
     * time-based scheduling and set some timer in your SPI implementation that would wake up
     * after a certain period of time. Once this period is reached, you would notify this
     * listener that a collision resolution should take place. Then inside of your collision
     * resolution logic, you would find the marked waiting job and activate it.
     * <p>
     * Note that most collision SPI's might not have external collisions. In that case,
     * they should simply ignore this method and do nothing when listener is set.
     *
     * @param lsnr Listener for external collision events.
     */
    public void setExternalCollisionListener(@Nullable CollisionExternalListener lsnr);
}
