org.apache.ignite.spi.collision.jobstealing

## Class JobStealingCollisionSpi

- java.lang.Object
- - org.apache.ignite.spi.IgniteSpiAdapter
  - - org.apache.ignite.spi.collision.jobstealing.JobStealingCollisionSpi

All Implemented Interfaces:
  CollisionSpi, JobStealingCollisionSpiMBean, IgniteSpi, IgniteSpiManagementMBean

    @IgniteSpiMultipleInstancesSupport(value=true)
    @IgniteSpiConsistencyChecked(optional=true)
    public class JobStealingCollisionSpi
    extends IgniteSpiAdapter
    implements CollisionSpi, JobStealingCollisionSpiMBean

Collision SPI that supports job stealing from over-utilized nodes to under-utilized nodes. This SPI is especially useful if you have some jobs within task complete fast, and others sitting in the waiting queue on slower nodes. In such case, the waiting jobs will be stolen from slower node and moved to the fast under-utilized node.

The design and ideas for this SPI are significantly influenced by Java Fork/Join Framework authored by Doug Lea and planned for Java 7. `GridJobStealingCollisionSpi` took similar concepts and applied them to the grid (as opposed to within VM support planned in Java 7).

Quite often grids are deployed across many computers some of which will always be more powerful than others. This SPI helps you avoid jobs being stuck at a slower node, as they will be stolen by a faster node. In the following picture when Node3 becomes free, it steals Job13 and Job23 from Node1 and Node2 respectively.

Note that this SPI must always be used in conjunction with `JobStealingFailoverSpi`. Also note that job metrics update should be enabled in order for this SPI to work properly (i.e. `IgniteConfiguration#getMetricsUpdateFrequency()` should be set to `0` or greater value). The responsibility of Job Stealing Failover SPI is to properly route stolen jobs to the nodes that initially requested (stole) these jobs. The SPI maintains a counter of how many times a jobs was stolen and hence traveled to another node. `JobStealingCollisionSpi` checks this counter and will not allow a job to be stolen if this counter exceeds a certain threshold `setMaximumStealingAttempts(int)`.

# Configuration

In order to use this SPI, you should configure your grid instance to use `JobStealingCollisionSpi` either from Spring XML file or directly. The following configuration parameters are supported:

## Mandatory

This SPI has no mandatory configuration parameters.

## Optional

The following configuration parameters are optional:

- Maximum number of active jobs that will be allowed by this SPI to execute concurrently (see `setActiveJobsThreshold(int)`).
- Maximum number of waiting jobs. Once waiting queue size goes below this number, this SPI will attempt to steal jobs from over-utilized nodes by sending "steal" requests (see `setWaitJobsThreshold(int)`).
- Steal message expire time. If no response was received from a node to which steal request was sent, then request will be considered lost and will be resent, potentially to another node (see `setMessageExpireTime(long)`).
- Maximum number of stealing attempts for the job (see `setMaximumStealingAttempts(int)`).
- Whether stealing enabled or not (see `setStealingEnabled(boolean)`).
- Enables stealing to/from only nodes that have these attributes set (see `setStealingAttributes(Map)`).

Below is example of configuring this SPI from Java code:

     JobStealingCollisionSpi spi = new JobStealingCollisionSpi();

     // Configure number of waiting jobs
     // in the queue for job stealing.
     spi.setWaitJobsThreshold(10);

     // Configure message expire time (in milliseconds).
     spi.setMessageExpireTime(500);

     // Configure stealing attempts number.
     spi.setMaximumStealingAttempts(10);

     // Configure number of active jobs that are allowed to execute
     // in parallel. This number should usually be equal to the number
     // of threads in the pool (default is 100).
     spi.setActiveJobsThreshold(50);

     // Enable stealing.
     spi.setStealingEnabled(true);

     // Set stealing attribute to steal from/to nodes that have it.
     spi.setStealingAttributes(Collections.singletonMap("node.segment", "foobar"));

     IgniteConfiguration cfg = new IgniteConfiguration();

     // Override default Collision SPI.
     cfg.setCollisionSpi(spi);

Here is an example of how this SPI can be configured from Spring XML configuration:

     <property name="collisionSpi">
         <bean class="org.apache.ignite.spi.collision.jobstealing.JobStealingCollisionSpi">
             <property name="activeJobsThreshold" value="100"/>
             <property name="waitJobsThreshold" value="0"/>
             <property name="messageExpireTime" value="1000"/>
             <property name="maximumStealingAttempts" value="10"/>
             <property name="stealingEnabled" value="true"/>
             <property name="stealingAttributes">
                 <map>
                     <entry key="node.segment" value="foobar"/>
                 </map>
             </property>
         </bean>
     </property>

For information about Spring framework visit www.springframework.org

### Field Summary

Fields
`static String` `ACTIVE_JOBS_THRESHOLD_NODE_ATTR` Threshold of maximum jobs executing concurrently.
`static int` `DFLT_ACTIVE_JOBS_THRESHOLD` Default number of parallel jobs allowed (value is `95` which is slightly less same as default value of threads in the execution thread pool to allow some extra threads for system processing).
`static int` `DFLT_JOB_PRIORITY` Default start value for job priority (value is `0`).
`static int` `DFLT_MAX_STEALING_ATTEMPTS` Maximum number of attempts to steal job by another node (default is `5`).
`static long` `DFLT_MSG_EXPIRE_TIME` Default steal message expire time in milliseconds (value is `1000`).
`static int` `DFLT_WAIT_JOBS_THRESHOLD` Default threshold of waiting jobs.
`static String` `MAX_STEALING_ATTEMPT_ATTR` Maximum stealing attempts attribute name.
`static String` `MSG_EXPIRE_TIME_ATTR` Stealing request expiration time attribute name.
`static String` `STEALING_ATTEMPT_COUNT_ATTR` Name of job context attribute containing current stealing attempt count.
`static String` `STEALING_PRIORITY_ATTR` Stealing priority attribute name.
`static String` `THIEF_NODE_ATTR` Job context attribute for storing thief node UUID (this attribute is used in job stealing failover SPI).
`static String` `WAIT_JOBS_THRESHOLD_NODE_ATTR` Threshold of maximum jobs on waiting queue.

### Fields inherited from class org.apache.ignite.spi.IgniteSpiAdapter

`gridName, ignite, nodeId`

### Constructor Summary

Constructors
Constructor and Description
`JobStealingCollisionSpi()`

### Method Summary

Methods
`int` `getActiveJobsThreshold()` Gets number of jobs that can be executed in parallel.
`protected List<String>` `getConsistentAttributeNames()` Returns back a list of attributes that should be consistent for this SPI.
`int` `getCurrentActiveJobsNumber()` Gets current number of jobs that are being executed.
`int` `getCurrentHeldJobsNumber()` Gets number of currently `'held'` jobs.
`int` `getCurrentJobsToStealNumber()` Gets current number of jobs to be stolen.
`int` `getCurrentRunningJobsNumber()`
`int` `getCurrentWaitJobsNumber()` Gets current number of jobs that wait for the execution.
`int` `getMaximumStealingAttempts()` Gets maximum number of attempts to steal job by another node.
`long` `getMessageExpireTime()` Message expire time configuration parameter.
`Map<String,Object>` `getNodeAttributes()` This method is called before SPI starts (before method `IgniteSpi.spiStart(String)` is called).
`Map<String,? extends Serializable>` `getStealingAttributes()` Configuration parameter to enable stealing to/from only nodes that have these attributes set (see `ClusterNode.attribute(String)` and `IgniteConfiguration.getUserAttributes()` methods).
`int` `getTotalStolenJobsNumber()` Gets total number of stolen jobs.
`int` `getWaitJobsThreshold()` Gets job count threshold at which this node will start stealing jobs from other nodes.
`boolean` `isStealingEnabled()` Gets flag indicating whether this node should attempt to steal jobs from other nodes.
`void` `onCollision(CollisionContext ctx)` This is a callback called when either new grid job arrived or executing job finished its execution.
`void` `onContextDestroyed0()` Method to be called in the beginning of onContextDestroyed() method.
`protected void` `onContextInitialized0(IgniteSpiContext spiCtx)` Method to be called in the end of onContextInitialized method.
`void` `setActiveJobsThreshold(int activeJobsThreshold)` Sets number of jobs that can be executed in parallel.
`void` `setExternalCollisionListener(CollisionExternalListener extLsnr)` Listener to be set for notification of external collision events (e.g. job stealing).
`void` `setMaximumStealingAttempts(int maxStealingAttempts)` Gets maximum number of attempts to steal job by another node.
`void` `setMessageExpireTime(long msgExpireTime)` Message expire time configuration parameter.
`void` `setStealingAttributes(Map<String,? extends Serializable> stealAttrs)` Configuration parameter to enable stealing to/from only nodes that have these attributes set (see `ClusterNode.attribute(String)` and `IgniteConfiguration.getUserAttributes()` methods).
`void` `setStealingEnabled(boolean isStealingEnabled)` Gets flag indicating whether this node should attempt to steal jobs from other nodes.
`void` `setWaitJobsThreshold(int waitJobsThreshold)` Sets job count threshold at which this node will start stealing jobs from other nodes.
`void` `spiStart(String gridName)` This method is called to start SPI.
`void` `spiStop()` This method is called to stop SPI.
`String` `toString()`

### Methods inherited from class org.apache.ignite.spi.IgniteSpiAdapter

`addTimeoutObject, assertParameter, checkConfigurationConsistency0, configInfo, createSpiAttributeName, getExceptionRegistry, getIgniteHome, getLocalNodeId, getName, getSpiContext, getStartTimestamp, getStartTimestampFormatted, getUpTime, getUpTimeFormatted, injectables, injectResources, isNodeStopping, onContextDestroyed, onContextInitialized, registerMBean, removeTimeoutObject, setName, startInfo, startStopwatch, stopInfo, unregisterMBean`

### Methods inherited from class java.lang.Object

`clone, equals, finalize, getClass, hashCode, notify, notifyAll, wait, wait, wait`

### Methods inherited from interface org.apache.ignite.spi.IgniteSpi

`getName, onContextDestroyed, onContextInitialized`

### Methods inherited from interface org.apache.ignite.spi.IgniteSpiManagementMBean

`getIgniteHome, getLocalNodeId, getName, getStartTimestamp, getStartTimestampFormatted, getUpTime, getUpTimeFormatted`

### Field Detail

#### DFLT_MAX_STEALING_ATTEMPTS

    public static final int DFLT_MAX_STEALING_ATTEMPTS

Maximum number of attempts to steal job by another node (default is `5`).

See Also:
  Constant Field Values

#### DFLT_ACTIVE_JOBS_THRESHOLD

    public static final int DFLT_ACTIVE_JOBS_THRESHOLD

Default number of parallel jobs allowed (value is `95` which is slightly less same as default value of threads in the execution thread pool to allow some extra threads for system processing).

See Also:
  Constant Field Values

#### DFLT_MSG_EXPIRE_TIME

    public static final long DFLT_MSG_EXPIRE_TIME

Default steal message expire time in milliseconds (value is `1000`). Once this time is elapsed and no response for steal message is received, the message is considered lost and another steal message will be generated, potentially to another node.

See Also:
  Constant Field Values

#### DFLT_WAIT_JOBS_THRESHOLD

    public static final int DFLT_WAIT_JOBS_THRESHOLD

Default threshold of waiting jobs. If number of waiting jobs exceeds this threshold, then waiting jobs will become available to be stolen (value is `0`).

See Also:
  Constant Field Values

#### DFLT_JOB_PRIORITY

    public static final int DFLT_JOB_PRIORITY

Default start value for job priority (value is `0`).

See Also:
  Constant Field Values

#### THIEF_NODE_ATTR

    public static final String THIEF_NODE_ATTR

Job context attribute for storing thief node UUID (this attribute is used in job stealing failover SPI).

See Also:
  Constant Field Values

#### WAIT_JOBS_THRESHOLD_NODE_ATTR

    public static final String WAIT_JOBS_THRESHOLD_NODE_ATTR

Threshold of maximum jobs on waiting queue.

See Also:
  Constant Field Values

#### ACTIVE_JOBS_THRESHOLD_NODE_ATTR

    public static final String ACTIVE_JOBS_THRESHOLD_NODE_ATTR

Threshold of maximum jobs executing concurrently.

See Also:
  Constant Field Values

#### STEALING_ATTEMPT_COUNT_ATTR

    public static final String STEALING_ATTEMPT_COUNT_ATTR

Name of job context attribute containing current stealing attempt count. This count is incremented every time the same job gets stolen for execution.

See Also:
  `ComputeJobContext`, Constant Field Values

#### MAX_STEALING_ATTEMPT_ATTR

    public static final String MAX_STEALING_ATTEMPT_ATTR

Maximum stealing attempts attribute name.

See Also:
  Constant Field Values

#### MSG_EXPIRE_TIME_ATTR

    public static final String MSG_EXPIRE_TIME_ATTR

Stealing request expiration time attribute name.

See Also:
  Constant Field Values

#### STEALING_PRIORITY_ATTR

    public static final String STEALING_PRIORITY_ATTR

Stealing priority attribute name.

See Also:
  Constant Field Values

### Constructor Detail

#### JobStealingCollisionSpi

    public JobStealingCollisionSpi()

### Method Detail

#### setActiveJobsThreshold

    @IgniteSpiConfiguration(optional=true)
    public void setActiveJobsThreshold(int activeJobsThreshold)

Sets number of jobs that can be executed in parallel.

Specified by:
  `setActiveJobsThreshold` in interface `JobStealingCollisionSpiMBean`
Parameters:
  `activeJobsThreshold` - Number of jobs that can be executed in parallel.

#### getActiveJobsThreshold

    public int getActiveJobsThreshold()

Gets number of jobs that can be executed in parallel.

Specified by:
  `getActiveJobsThreshold` in interface `JobStealingCollisionSpiMBean`
Returns:
  Number of jobs that can be executed in parallel.

#### setWaitJobsThreshold

    @IgniteSpiConfiguration(optional=true)
    public void setWaitJobsThreshold(int waitJobsThreshold)

Sets job count threshold at which this node will start stealing jobs from other nodes.

Specified by:
  `setWaitJobsThreshold` in interface `JobStealingCollisionSpiMBean`
Parameters:
  `waitJobsThreshold` - Job count threshold.

#### getWaitJobsThreshold

    public int getWaitJobsThreshold()

Gets job count threshold at which this node will start stealing jobs from other nodes.

Specified by:
  `getWaitJobsThreshold` in interface `JobStealingCollisionSpiMBean`
Returns:
  Job count threshold.

#### setMessageExpireTime

    @IgniteSpiConfiguration(optional=true)
    public void setMessageExpireTime(long msgExpireTime)

Message expire time configuration parameter. If no response is received from a busy node to a job stealing message, then implementation will assume that message never got there, or that remote node does not have this node included into topology of any of the jobs it has.

Specified by:
  `setMessageExpireTime` in interface `JobStealingCollisionSpiMBean`
Parameters:
  `msgExpireTime` - Message expire time.

#### getMessageExpireTime

    public long getMessageExpireTime()

Message expire time configuration parameter. If no response is received from a busy node to a job stealing message, then implementation will assume that message never got there, or that remote node does not have this node included into topology of any of the jobs it has.

Specified by:
  `getMessageExpireTime` in interface `JobStealingCollisionSpiMBean`
Returns:
  Message expire time.

#### setStealingEnabled

    @IgniteSpiConfiguration(optional=true)
    public void setStealingEnabled(boolean isStealingEnabled)

Gets flag indicating whether this node should attempt to steal jobs from other nodes. If `false`, then this node will steal allow jobs to be stolen from it, but won't attempt to steal any jobs from other nodes.

Default value is `true`.

Specified by:
  `setStealingEnabled` in interface `JobStealingCollisionSpiMBean`
Parameters:
  `isStealingEnabled` - Flag indicating whether this node should attempt to steal jobs from other nodes.

#### isStealingEnabled

    public boolean isStealingEnabled()

Gets flag indicating whether this node should attempt to steal jobs from other nodes. If `false`, then this node will steal allow jobs to be stolen from it, but won't attempt to steal any jobs from other nodes.

Default value is `true`.

Specified by:
  `isStealingEnabled` in interface `JobStealingCollisionSpiMBean`
Returns:
  Flag indicating whether this node should attempt to steal jobs from other nodes.

#### setMaximumStealingAttempts

    @IgniteSpiConfiguration(optional=true)
    public void setMaximumStealingAttempts(int maxStealingAttempts)

Gets maximum number of attempts to steal job by another node. If not specified, `DFLT_MAX_STEALING_ATTEMPTS` value will be used.

Specified by:
  `setMaximumStealingAttempts` in interface `JobStealingCollisionSpiMBean`
Parameters:
  `maxStealingAttempts` - Maximum number of attempts to steal job by another node.

#### getMaximumStealingAttempts

    public int getMaximumStealingAttempts()

Gets maximum number of attempts to steal job by another node. If not specified, `DFLT_MAX_STEALING_ATTEMPTS` value will be used.

Specified by:
  `getMaximumStealingAttempts` in interface `JobStealingCollisionSpiMBean`
Returns:
  Maximum number of attempts to steal job by another node.

#### setStealingAttributes

    @IgniteSpiConfiguration(optional=true)
    public void setStealingAttributes(Map<String,? extends Serializable> stealAttrs)

Configuration parameter to enable stealing to/from only nodes that have these attributes set (see `ClusterNode.attribute(String)` and `IgniteConfiguration.getUserAttributes()` methods).

Parameters:
  `stealAttrs` - Node attributes to enable job stealing for.

#### getStealingAttributes

    public Map<String,? extends Serializable> getStealingAttributes()

Configuration parameter to enable stealing to/from only nodes that have these attributes set (see `ClusterNode.attribute(String)` and `IgniteConfiguration.getUserAttributes()` methods).

Specified by:
  `getStealingAttributes` in interface `JobStealingCollisionSpiMBean`
Returns:
  Node attributes to enable job stealing for.

#### getCurrentRunningJobsNumber

    public int getCurrentRunningJobsNumber()

Specified by:
  `getCurrentRunningJobsNumber` in interface `JobStealingCollisionSpiMBean`

#### getCurrentHeldJobsNumber

    public int getCurrentHeldJobsNumber()

Gets number of currently `'held'` jobs.

Specified by:
  `getCurrentHeldJobsNumber` in interface `JobStealingCollisionSpiMBean`
Returns:
  Number of currently `'held'` jobs.

#### getCurrentWaitJobsNumber

    public int getCurrentWaitJobsNumber()

Gets current number of jobs that wait for the execution.

Specified by:
  `getCurrentWaitJobsNumber` in interface `JobStealingCollisionSpiMBean`
Returns:
  Number of jobs that wait for execution.

#### getCurrentActiveJobsNumber

    public int getCurrentActiveJobsNumber()

Gets current number of jobs that are being executed.

Specified by:
  `getCurrentActiveJobsNumber` in interface `JobStealingCollisionSpiMBean`
Returns:
  Number of active jobs.

#### getTotalStolenJobsNumber

    public int getTotalStolenJobsNumber()

Gets total number of stolen jobs.

Specified by:
  `getTotalStolenJobsNumber` in interface `JobStealingCollisionSpiMBean`
Returns:
  Number of stolen jobs.

#### getCurrentJobsToStealNumber

    public int getCurrentJobsToStealNumber()

Gets current number of jobs to be stolen. This is outstanding requests number.

Specified by:
  `getCurrentJobsToStealNumber` in interface `JobStealingCollisionSpiMBean`
Returns:
  Number of jobs to be stolen.

#### getNodeAttributes

    public Map<String,Object> getNodeAttributes()
                                         throws IgniteSpiException

This method is called before SPI starts (before method `IgniteSpi.spiStart(String)` is called). It allows SPI implementation to add attributes to a local node. Kernal collects these attributes from all SPI implementations loaded up and then passes it to discovery SPI so that they can be exchanged with other nodes.

Specified by:
  `getNodeAttributes` in interface `IgniteSpi`
Overrides:
  `getNodeAttributes` in class `IgniteSpiAdapter`
Returns:
  Map of local node attributes this SPI wants to add.
Throws:
  `IgniteSpiException` - Throws in case of any error.

#### spiStart

    public void spiStart(String gridName)
                  throws IgniteSpiException

This method is called to start SPI. After this method returns successfully kernel assumes that SPI is fully operational.

Specified by:
  `spiStart` in interface `IgniteSpi`
Parameters:
  `gridName` - Name of grid instance this SPI is being started for (`null` for default grid).
Throws:
  `IgniteSpiException` - Throws in case of any error during SPI start.

#### spiStop

    public void spiStop()
                 throws IgniteSpiException

This method is called to stop SPI. After this method returns kernel assumes that this SPI is finished and all resources acquired by it are released.

Note that this method can be called at any point including during recovery of failed start. It should make no assumptions on what state SPI will be in when this method is called.

Specified by:
  `spiStop` in interface `IgniteSpi`
Throws:
  `IgniteSpiException` - Thrown in case of any error during SPI stop.

#### setExternalCollisionListener

    public void setExternalCollisionListener(CollisionExternalListener extLsnr)

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.

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 `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.

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.

Specified by:
  `setExternalCollisionListener` in interface `CollisionSpi`
Parameters:
  `extLsnr` - Listener for external collision events.

#### onContextInitialized0

    protected void onContextInitialized0(IgniteSpiContext spiCtx)
                                  throws IgniteSpiException

Method to be called in the end of onContextInitialized method.

Overrides:
  `onContextInitialized0` in class `IgniteSpiAdapter`
Parameters:
  `spiCtx` - SPI context.
Throws:
  `IgniteSpiException` - In case of errors.

#### onContextDestroyed0

    public void onContextDestroyed0()

Method to be called in the beginning of onContextDestroyed() method.

Overrides:
  `onContextDestroyed0` in class `IgniteSpiAdapter`

#### onCollision

    public void onCollision(CollisionContext ctx)

This is a callback called when either new grid job arrived or executing job finished its execution. 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).

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 `CollisionContext` and `CollisionJobContext` documentation for more information.

Specified by:
  `onCollision` in interface `CollisionSpi`
Parameters:
  `ctx` - Collision context which contains all collision lists.

#### getConsistentAttributeNames

    protected List<String> getConsistentAttributeNames()

Returns back a list of attributes that should be consistent for this SPI. Consistency means that remote node has to have the same attribute with the same value.

Overrides:
  `getConsistentAttributeNames` in class `IgniteSpiAdapter`
Returns:
  List or attribute names.

#### toString

    public String toString()

Overrides:
  `toString` in class `Object`

2015 Copyright © Apache Software Foundation

Follow @ApacheIgnite

Ignite Fabric | : ver. 1.2.0-incubating
Release Date | : June 16 2015