/**
   * Checks for explicit events configuration.
   *
   * @param ignite Grid instance.
   * @return {@code true} if all task events explicitly specified in configuration.
   */
  public static boolean checkExplicitTaskMonitoring(Ignite ignite) {
    int[] evts = ignite.configuration().getIncludeEventTypes();

    if (F.isEmpty(evts)) return false;

    for (int evt : VISOR_TASK_EVTS) {
      if (!F.contains(evts, evt)) return false;
    }

    return true;
  }
  /**
   * @param nodeId Sender node ID.
   * @param req Dht atomic update request.
   * @param res Dht atomic update response.
   */
  public void processDhtAtomicUpdateRequest(
      UUID nodeId, GridDhtAtomicUpdateRequest req, GridDhtAtomicUpdateResponse res) {
    GridCacheVersion ver = req.writeVersion();

    assert ver != null;

    Collection<KeyCacheObject> backupKeys = req.keys();

    boolean intercept = req.forceTransformBackups() && ctx.config().getInterceptor() != null;

    String taskName = ctx.kernalContext().task().resolveTaskName(req.taskNameHash());

    for (int i = 0; i < req.nearSize(); i++) {
      KeyCacheObject key = req.nearKey(i);

      try {
        while (true) {
          try {
            GridCacheEntryEx entry = peekEx(key);

            if (entry == null) {
              res.addNearEvicted(key);

              break;
            }

            if (F.contains(backupKeys, key)) { // Reader became backup.
              if (entry.markObsolete(ver)) removeEntry(entry);

              break;
            }

            CacheObject val = req.nearValue(i);
            EntryProcessor<Object, Object, Object> entryProcessor = req.nearEntryProcessor(i);

            GridCacheOperation op =
                entryProcessor != null ? TRANSFORM : (val != null) ? UPDATE : DELETE;

            long ttl = req.nearTtl(i);
            long expireTime = req.nearExpireTime(i);

            GridCacheUpdateAtomicResult updRes =
                entry.innerUpdate(
                    ver,
                    nodeId,
                    nodeId,
                    op,
                    op == TRANSFORM ? entryProcessor : val,
                    op == TRANSFORM ? req.invokeArguments() : null,
                    /*write-through*/ false,
                    /*read-through*/ false,
                    /*retval*/ false,
                    req.keepBinary(),
                    null,
                    /*event*/ true,
                    /*metrics*/ true,
                    /*primary*/ false,
                    /*check version*/ !req.forceTransformBackups(),
                    req.topologyVersion(),
                    CU.empty0(),
                    DR_NONE,
                    ttl,
                    expireTime,
                    null,
                    false,
                    intercept,
                    req.subjectId(),
                    taskName,
                    null,
                    null);

            if (updRes.removeVersion() != null) ctx.onDeferredDelete(entry, updRes.removeVersion());

            break;
          } catch (GridCacheEntryRemovedException ignored) {
            if (log.isDebugEnabled())
              log.debug("Got removed entry while updating near value (will retry): " + key);
          }
        }
      } catch (IgniteCheckedException e) {
        res.addFailedKey(
            key, new IgniteCheckedException("Failed to update near cache key: " + key, e));
      }
    }
  }
  /**
   * @param req Update request.
   * @param res Update response.
   */
  public void processNearAtomicUpdateResponse(
      GridNearAtomicUpdateRequest req, GridNearAtomicUpdateResponse res) {
    if (F.size(res.failedKeys()) == req.keys().size()) return;

    /*
     * Choose value to be stored in near cache: first check key is not in failed and not in skipped list,
     * then check if value was generated on primary node, if not then use value sent in request.
     */

    Collection<KeyCacheObject> failed = res.failedKeys();
    List<Integer> nearValsIdxs = res.nearValuesIndexes();
    List<Integer> skipped = res.skippedIndexes();

    GridCacheVersion ver = req.updateVersion();

    if (ver == null) ver = res.nearVersion();

    assert ver != null : "Failed to find version [req=" + req + ", res=" + res + ']';

    int nearValIdx = 0;

    String taskName = ctx.kernalContext().task().resolveTaskName(req.taskNameHash());

    for (int i = 0; i < req.keys().size(); i++) {
      if (F.contains(skipped, i)) continue;

      KeyCacheObject key = req.keys().get(i);

      if (F.contains(failed, key)) continue;

      if (ctx.affinity()
          .belongs(
              ctx.localNode(),
              ctx.affinity().partition(key),
              req.topologyVersion())) { // Reader became backup.
        GridCacheEntryEx entry = peekEx(key);

        if (entry != null && entry.markObsolete(ver)) removeEntry(entry);

        continue;
      }

      CacheObject val = null;

      if (F.contains(nearValsIdxs, i)) {
        val = res.nearValue(nearValIdx);

        nearValIdx++;
      } else {
        assert req.operation() != TRANSFORM;

        if (req.operation() != DELETE) val = req.value(i);
      }

      long ttl = res.nearTtl(i);
      long expireTime = res.nearExpireTime(i);

      if (ttl != CU.TTL_NOT_CHANGED && expireTime == CU.EXPIRE_TIME_CALCULATE)
        expireTime = CU.toExpireTime(ttl);

      try {
        processNearAtomicUpdateResponse(
            ver,
            key,
            val,
            null,
            ttl,
            expireTime,
            req.keepBinary(),
            req.nodeId(),
            req.subjectId(),
            taskName);
      } catch (IgniteCheckedException e) {
        res.addFailedKey(
            key, new IgniteCheckedException("Failed to update key in near cache: " + key, e));
      }
    }
  }