/** {@inheritDoc} */
  @Override
  public void spiStop() throws GridSpiException {
    unregisterMBean();

    // Ack ok stop.
    if (log.isDebugEnabled()) log.debug(stopInfo());
  }
  /**
   * Gets job priority. At first tries to get from job context. If job context has no priority, then
   * tries to get from task session. If task session has no priority default one will be used.
   *
   * @param ctx Collision job context.
   * @return Job priority.
   */
  private int getJobPriority(GridCollisionJobContext ctx) {
    assert ctx != null;

    Integer p = null;

    GridJobContext jctx = ctx.getJobContext();

    try {
      p = (Integer) jctx.getAttribute(jobAttrKey);
    } catch (ClassCastException e) {
      LT.error(
          log,
          e,
          "Type of job context priority attribute '"
              + jobAttrKey
              + "' is not java.lang.Integer [type="
              + jctx.getAttribute(jobAttrKey).getClass()
              + ']');
    }

    if (p == null) {
      GridTaskSession ses = ctx.getTaskSession();

      try {
        p = (Integer) ses.getAttribute(taskAttrKey);
      } catch (ClassCastException e) {
        LT.error(
            log,
            e,
            "Type of task session priority attribute '"
                + taskAttrKey
                + "' is not java.lang.Integer [type="
                + ses.getAttribute(taskAttrKey).getClass()
                + ']');
      }

      if (p == null) {
        if (log.isDebugEnabled()) {
          log.debug(
              "Failed get priority from job context attribute '"
                  + jobAttrKey
                  + "' and task session attribute '"
                  + taskAttrKey
                  + "' (will use default priority): "
                  + dfltPriority);
        }

        p = dfltPriority;
      }
    }

    assert p != null;

    return p;
  }
  /** {@inheritDoc} */
  @Override
  public void spiStart(String gridName) throws GridSpiException {
    assertParameter(parallelJobsNum > 0, "parallelJobsNum > 0");
    assertParameter(waitJobsNum >= 0, "waitingJobsNum >= 0");
    assertParameter(taskAttrKey != null, "taskAttrKey != null");
    assertParameter(jobAttrKey != null, "jobAttrKey != null");

    // Start SPI start stopwatch.
    startStopwatch();

    // Ack parameters.
    if (log.isDebugEnabled()) {
      log.debug(configInfo("parallelJobsNum", parallelJobsNum));
      log.debug(configInfo("taskAttrKey", taskAttrKey));
      log.debug(configInfo("jobAttrKey", jobAttrKey));
      log.debug(configInfo("dfltPriority", dfltPriority));
      log.debug(configInfo("starvationInc", starvationInc));
      log.debug(configInfo("preventStarvation", preventStarvation));
    }

    registerMBean(gridName, this, GridPriorityQueueCollisionSpiMBean.class);

    // Ack start.
    if (log.isDebugEnabled()) log.debug(startInfo());
  }
  /** @throws GridException If operation failed. */
  private void initializeLatch() throws GridException {
    if (initGuard.compareAndSet(false, true)) {
      try {
        internalLatch =
            CU.outTx(
                new Callable<CountDownLatch>() {
                  @Override
                  public CountDownLatch call() throws Exception {
                    GridCacheTx tx =
                        CU.txStartInternal(ctx, latchView, PESSIMISTIC, REPEATABLE_READ);

                    try {
                      GridCacheCountDownLatchValue val = latchView.get(key);

                      if (val == null) {
                        if (log.isDebugEnabled())
                          log.debug("Failed to find count down latch with given name: " + name);

                        assert cnt == 0;

                        return new CountDownLatch(cnt);
                      }

                      tx.commit();

                      return new CountDownLatch(val.get());
                    } finally {
                      tx.end();
                    }
                  }
                },
                ctx);

        if (log.isDebugEnabled()) log.debug("Initialized internal latch: " + internalLatch);
      } finally {
        initLatch.countDown();
      }
    } else {
      try {
        initLatch.await();
      } catch (InterruptedException ignored) {
        throw new GridException("Thread has been interrupted.");
      }

      if (internalLatch == null)
        throw new GridException("Internal latch has not been properly initialized.");
    }
  }