コード例 #1
0
  /** @throws Exception If failed. */
  public void testDisabledRest() throws Exception {
    restEnabled = false;

    final Grid g = startGrid("disabled-rest");

    try {
      Thread.sleep(2 * TOP_REFRESH_FREQ);

      // As long as we have round robin load balancer this will cause every node to be queried.
      for (int i = 0; i < NODES_CNT + 1; i++)
        assertEquals(NODES_CNT + 1, client.compute().refreshTopology(false, false).size());

      final GridClientData data = client.data(PARTITIONED_CACHE_NAME);

      // Check rest-disabled node is unavailable.
      try {
        String affKey;

        do {
          affKey = UUID.randomUUID().toString();
        } while (!data.affinity(affKey).equals(g.localNode().id()));

        data.put(affKey, "asdf");

        assertEquals("asdf", cache(0, PARTITIONED_CACHE_NAME).get(affKey));
      } catch (GridServerUnreachableException e) {
        // Thrown for direct client-node connections.
        assertTrue(
            "Unexpected exception message: " + e.getMessage(),
            e.getMessage()
                .startsWith("No available endpoints to connect (is rest enabled for this node?)"));
      } catch (GridClientException e) {
        // Thrown for routed client-router-node connections.
        String msg = e.getMessage();

        assertTrue(
            "Unexpected exception message: " + msg,
            protocol() == GridClientProtocol.TCP
                ? msg.contains("No available endpoints to connect (is rest enabled for this node?)")
                : // TCP router.
                msg.startsWith(
                    "No available nodes on the router for destination node ID")); // HTTP router.
      }

      // Check rest-enabled nodes are available.
      String affKey;

      do {
        affKey = UUID.randomUUID().toString();
      } while (data.affinity(affKey).equals(g.localNode().id()));

      data.put(affKey, "fdsa");

      assertEquals("fdsa", cache(0, PARTITIONED_CACHE_NAME).get(affKey));
    } finally {
      restEnabled = true;

      G.stop(g.name(), true);
    }
  }
コード例 #2
0
  /** @throws Exception If failed. */
  @SuppressWarnings({"ObjectEquality"})
  public void testDifferentTasks() throws Exception {
    Grid grid1 = null;
    Grid grid2 = null;

    try {
      grid1 = startGrid(1, new GridSpringResourceContextImpl(new GenericApplicationContext()));
      grid2 = startGrid(2, new GridSpringResourceContextImpl(new GenericApplicationContext()));

      // Execute different tasks.
      grid1.compute().execute(SharedResourceTask1.class, null).get();
      grid1.compute().execute(SharedResourceTask2.class, null).get();

      // In ISOLATED_CLASSLOADER mode tasks should have the class
      // loaders because they have the same CL locally and thus the same
      // resources.
      // So 1 resource locally and 1 remotely
      assert task1Rsrc1 == task2Rsrc1;
      assert task1Rsrc2 == task2Rsrc2;
      assert task1Rsrc3 == task2Rsrc3;
      assert task1Rsrc4 == task2Rsrc4;

      checkUsageCount(createClss, UserResource1.class, 4);
      checkUsageCount(createClss, UserResource2.class, 4);

      checkUsageCount(deployClss, UserResource1.class, 4);
      checkUsageCount(deployClss, UserResource2.class, 4);
    } finally {
      GridTestUtils.close(grid1, log());
      GridTestUtils.close(grid2, log());
    }

    checkUsageCount(undeployClss, UserResource1.class, 4);
    checkUsageCount(undeployClss, UserResource2.class, 4);
  }
コード例 #3
0
  /** @throws Exception If failed. */
  @SuppressWarnings("unchecked")
  public void testCancel() throws Exception {
    Grid grid = G.grid(getTestGridName());

    grid.compute()
        .localDeployTask(GridCancelTestTask.class, U.detectClassLoader(GridCancelTestTask.class));

    GridComputeTaskFuture<?> fut = grid.compute().execute(GridCancelTestTask.class.getName(), null);

    // Wait until jobs begin execution.
    boolean await = startSignal.await(WAIT_TIME, TimeUnit.MILLISECONDS);

    assert await : "Jobs did not start.";

    info("Test task result: " + fut);

    assert fut != null;

    // Only first job should successfully complete.
    Object res = fut.get();
    assert (Integer) res == 1;

    // Wait for all jobs to finish.
    await = stopSignal.await(WAIT_TIME, TimeUnit.MILLISECONDS);
    assert await : "Jobs did not stop.";

    // One is definitely processed. But there might be some more processed or cancelled or processed
    // and cancelled.
    // Thus total number should be at least SPLIT_COUNT and at most (SPLIT_COUNT - 1) *2 +1
    assert (cancelCnt + processedCnt) >= SPLIT_COUNT
            && (cancelCnt + processedCnt) <= (SPLIT_COUNT - 1) * 2 + 1
        : "Invalid cancel count value: " + cancelCnt;
  }
コード例 #4
0
  /** @throws Exception If failed. */
  public void testInvalidateFlag() throws Exception {
    GridEx g0 = grid(0);

    GridCache<String, String> cache = g0.cache(PARTITIONED_CACHE_NAME);

    String key = null;

    for (int i = 0; i < 10_000; i++) {
      if (!cache.affinity().isPrimaryOrBackup(g0.localNode(), String.valueOf(i))) {
        key = String.valueOf(i);

        break;
      }
    }

    assertNotNull(key);

    cache.put(key, key); // Create entry in near cache, it is invalidated if INVALIDATE flag is set.

    assertNotNull(cache.peek(key));

    GridClientData d = client.data(PARTITIONED_CACHE_NAME);

    d.flagsOn(GridClientCacheFlag.INVALIDATE).put(key, "zzz");

    for (Grid g : G.allGrids()) {
      cache = g.cache(PARTITIONED_CACHE_NAME);

      if (cache.affinity().isPrimaryOrBackup(g.localNode(), key))
        assertEquals("zzz", cache.peek(key));
      else assertNull(cache.peek(key));
    }
  }
コード例 #5
0
  /** @throws Exception If failed. */
  public void testProjectionRun() throws Exception {
    GridClientCompute dflt = client.compute();

    Collection<? extends GridClientNode> nodes = dflt.nodes();

    assertEquals(NODES_CNT, nodes.size());

    for (int i = 0; i < NODES_CNT; i++) {
      Grid g = grid(i);

      assert g != null;

      GridClientNode clientNode = dflt.node(g.localNode().id());

      assertNotNull("Client node for " + g.localNode().id() + " was not found", clientNode);

      GridClientCompute prj = dflt.projection(clientNode);

      String res = prj.execute(TestTask.class.getName(), null);

      assertNotNull(res);

      assertEquals(g.localNode().id().toString(), res);
    }
  }
コード例 #6
0
  /**
   * Ensure that {@link GridComputeJobMasterLeaveAware} callback is invoked on job which is
   * initiated by master and is currently running on it.
   *
   * @throws Exception If failed.
   */
  public void testLocalJobOnMaster() throws Exception {
    invokeLatch = new CountDownLatch(1);
    jobLatch = new CountDownLatch(1);

    Grid g = startGrid(0);

    g.compute().execute(new TestTask(1), null);

    jobLatch.await();

    // Count down the latch in a separate thread.
    new Thread(
            new Runnable() {
              @Override
              public void run() {
                try {
                  U.sleep(500);
                } catch (GridInterruptedException ignore) {
                  // No-op.
                }

                latch.countDown();
              }
            })
        .start();

    stopGrid(0, true);

    latch.countDown();

    assert invokeLatch.await(5000, MILLISECONDS);
  }
コード例 #7
0
  /**
   * Listen to events coming from all grid nodes.
   *
   * @throws GridException If failed.
   */
  private static void remoteListen() throws GridException {
    Grid g = GridGain.grid();

    GridCache<Integer, String> cache = g.cache(CACHE_NAME);

    // Register remote event listeners on all nodes running cache.
    GridFuture<?> fut =
        g.forCache(CACHE_NAME)
            .events()
            .remoteListen(
                // This optional local callback is called for each event notification
                // that passed remote predicate filter.
                new GridBiPredicate<UUID, GridCacheEvent>() {
                  @Override
                  public boolean apply(UUID nodeId, GridCacheEvent evt) {
                    System.out.println();
                    System.out.println(
                        "Received event [evt="
                            + evt.name()
                            + ", key="
                            + evt.key()
                            + ", oldVal="
                            + evt.oldValue()
                            + ", newVal="
                            + evt.newValue());

                    return true; // Return true to continue listening.
                  }
                },
                // Remote filter which only accepts events for keys that are
                // greater or equal than 10 and if local node is primary for this key.
                new GridPredicate<GridCacheEvent>() {
                  /** Auto-inject grid instance. */
                  @GridInstanceResource private Grid g;

                  @Override
                  public boolean apply(GridCacheEvent evt) {
                    Integer key = evt.key();

                    return key >= 10
                        && g.cache(CACHE_NAME).affinity().isPrimary(g.localNode(), key);
                  }
                },
                // Types of events for which listeners are registered.
                EVT_CACHE_OBJECT_PUT,
                EVT_CACHE_OBJECT_READ,
                EVT_CACHE_OBJECT_REMOVED);

    // Wait until event listeners are subscribed on all nodes.
    fut.get();

    int keyCnt = 20;

    // Generate cache events.
    for (int i = 0; i < keyCnt; i++) cache.putx(i, Integer.toString(i));
  }
コード例 #8
0
  /** @throws Exception If failed. */
  @SuppressWarnings({"ObjectEquality"})
  public void testUndeployedTask() throws Exception {
    Grid grid1 = null;
    Grid grid2 = null;

    try {
      grid1 = startGrid(1, new GridSpringResourceContextImpl(new GenericApplicationContext()));
      grid2 = startGrid(2, new GridSpringResourceContextImpl(new GenericApplicationContext()));

      // Execute tasks.
      grid1.compute().execute(SharedResourceTask1.class, null).get();
      grid1.compute().execute(SharedResourceTask2.class, null).get();

      grid1.compute().undeployTask(SharedResourceTask1.class.getName());

      // Wait until resources get undeployed remotely
      // because undeploy is asynchronous apply.
      Thread.sleep(3000);

      // 1 local and 1 remote resource instances
      checkUsageCount(createClss, UserResource1.class, 4);
      checkUsageCount(deployClss, UserResource1.class, 4);
      checkUsageCount(createClss, UserResource2.class, 4);
      checkUsageCount(deployClss, UserResource2.class, 4);
      checkUsageCount(undeployClss, UserResource1.class, 4);
      checkUsageCount(undeployClss, UserResource2.class, 4);

      grid1.compute().undeployTask(SharedResourceTask2.class.getName());

      // Wait until resources get undeployed remotely
      // because undeploy is asynchronous apply.
      Thread.sleep(3000);

      // We undeployed last task for this class loader and resources.
      // All resources should be undeployed.
      checkUsageCount(undeployClss, UserResource1.class, 4);
      checkUsageCount(undeployClss, UserResource2.class, 4);

      // Execute the same tasks.
      grid1.compute().execute(SharedResourceTask1.class, null).get();
      grid1.compute().execute(SharedResourceTask2.class, null).get();

      // 2 new resources.
      checkUsageCount(createClss, UserResource1.class, 8);
      checkUsageCount(deployClss, UserResource1.class, 8);
      checkUsageCount(createClss, UserResource2.class, 8);
      checkUsageCount(deployClss, UserResource2.class, 8);
    } finally {
      GridTestUtils.close(grid1, log());
      GridTestUtils.close(grid2, log());
    }

    checkUsageCount(undeployClss, UserResource1.class, 8);
    checkUsageCount(undeployClss, UserResource2.class, 8);
  }
コード例 #9
0
  /** @throws Exception If failed. */
  public void testTopologyListener() throws Exception {
    final Collection<UUID> added = new ArrayList<>(1);
    final Collection<UUID> rmvd = new ArrayList<>(1);

    final CountDownLatch addedLatch = new CountDownLatch(1);
    final CountDownLatch rmvLatch = new CountDownLatch(1);

    assertEquals(NODES_CNT, client.compute().refreshTopology(false, false).size());

    GridClientTopologyListener lsnr =
        new GridClientTopologyListener() {
          @Override
          public void onNodeAdded(GridClientNode node) {
            added.add(node.nodeId());

            addedLatch.countDown();
          }

          @Override
          public void onNodeRemoved(GridClientNode node) {
            rmvd.add(node.nodeId());

            rmvLatch.countDown();
          }
        };

    client.addTopologyListener(lsnr);

    try {
      Grid g = startGrid(NODES_CNT + 1);

      UUID id = g.localNode().id();

      assertTrue(addedLatch.await(2 * TOP_REFRESH_FREQ, MILLISECONDS));

      assertEquals(1, added.size());
      assertEquals(id, F.first(added));

      stopGrid(NODES_CNT + 1);

      assertTrue(rmvLatch.await(2 * TOP_REFRESH_FREQ, MILLISECONDS));

      assertEquals(1, rmvd.size());
      assertEquals(id, F.first(rmvd));
    } finally {
      client.removeTopologyListener(lsnr);

      stopGrid(NODES_CNT + 1);
    }
  }
コード例 #10
0
    /** {@inheritDoc} */
    @Override
    protected Collection<? extends GridComputeJob> split(int gridSize, Object arg)
        throws GridException {
      Collection<GridComputeJobAdapter> jobs = new ArrayList<>(gridSize);

      this.gridSize = gridSize;

      final String locNodeId = grid.localNode().id().toString();

      for (int i = 0; i < gridSize; i++) {
        jobs.add(
            new GridComputeJobAdapter() {
              @SuppressWarnings("OverlyStrongTypeCast")
              @Override
              public Object execute() {
                try {
                  Thread.sleep(1000);
                } catch (InterruptedException ignored) {
                  Thread.currentThread().interrupt();
                }

                return new GridBiTuple<>(locNodeId, 1);
              }
            });
      }

      return jobs;
    }
コード例 #11
0
  /**
   * Sends optional message. If message is {@code null} - it's no-op.
   *
   * @param nodeId ID of the node to send message to.
   * @param respMsg Message to send.
   * @throws GridException Thrown in case of any errors.
   */
  private void send(UUID nodeId, @Nullable Object respMsg) throws GridException {
    assert nodeId != null;

    if (respMsg != null) {
      GridNode node = grid.node(nodeId);

      if (node != null) grid.forNode(node).message().send(null, respMsg); // Can still fail.
      else
        throw new GridException(
            "Failed to send message since destination node has "
                + "left topology (ignoring) [nodeId="
                + nodeId
                + ", respMsg="
                + respMsg
                + ']');
    }
  }
コード例 #12
0
  /** @throws Exception If failed. */
  public void testSameTaskFromTwoNodesLeft() throws Exception {
    Grid grid1 = null;
    Grid grid2 = null;
    Grid grid3 = null;

    try {
      grid1 = startGrid(1, new GridSpringResourceContextImpl(new GenericApplicationContext()));
      grid2 = startGrid(2, new GridSpringResourceContextImpl(new GenericApplicationContext()));
      grid3 = startGrid(3, new GridSpringResourceContextImpl(new GenericApplicationContext()));

      grid1.compute().execute(SharedResourceTask1.class, null).get();
      grid2.compute().execute(SharedResourceTask1.class, null).get();

      checkUsageCount(createClss, UserResource1.class, 6);
      checkUsageCount(deployClss, UserResource1.class, 6);
      checkUsageCount(createClss, UserResource2.class, 6);
      checkUsageCount(deployClss, UserResource2.class, 6);

      checkUsageCount(undeployClss, UserResource1.class, 0);
      checkUsageCount(undeployClss, UserResource2.class, 0);

      GridTestUtils.close(grid1, log());

      // Wait until other nodes get notified
      // this grid1 left.
      Thread.sleep(1000);

      // Undeployment happened only on Grid1.
      checkUsageCount(undeployClss, UserResource1.class, 2);
      checkUsageCount(undeployClss, UserResource2.class, 2);

      GridTestUtils.close(grid2, log());

      // Wait until resources get undeployed remotely
      // because undeploy is asynchronous apply.
      Thread.sleep(1000);

      // Grid1 and Grid2
      checkUsageCount(undeployClss, UserResource1.class, 4);
      checkUsageCount(undeployClss, UserResource2.class, 4);
    } finally {
      GridTestUtils.close(grid1, log());
      GridTestUtils.close(grid2, log());
      GridTestUtils.close(grid3, log());
    }
  }
コード例 #13
0
  /** @throws Exception If failed. */
  @SuppressWarnings("unchecked")
  public void testRedeployedTask() throws Exception {
    Grid grid = startGrid(0, new GridSpringResourceContextImpl(new GenericApplicationContext()));

    try {
      // Execute same task with different class loaders. Second execution should redeploy first one.
      grid.compute().execute(SharedResourceTask1.class, null).get();

      checkUsageCount(createClss, UserResource1.class, 2);
      checkUsageCount(createClss, UserResource2.class, 2);

      checkUsageCount(deployClss, UserResource1.class, 2);
      checkUsageCount(deployClss, UserResource2.class, 2);

      // Change class loader of the task. So it's just implicit redeploy.
      ClassLoader tstClsLdr =
          new GridTestClassLoader(
              null,
              getClass().getClassLoader(),
              SharedResourceTask1.class.getName(),
              GridResourceSharedUndeploySelfTest.SharedResourceTask1.GridSharedJob1.class.getName(),
              GridResourceSharedUndeploySelfTest.class.getName());

      Class<? extends GridComputeTask<Object, Object>> taskCls =
          (Class<? extends GridComputeTask<Object, Object>>)
              tstClsLdr.loadClass(SharedResourceTask1.class.getName());

      grid.compute().execute(taskCls, null).get();

      // Old resources should be undeployed at this point.
      checkUsageCount(undeployClss, UserResource1.class, 2);
      checkUsageCount(undeployClss, UserResource2.class, 2);

      // We should detect redeployment and create new resources.
      checkUsageCount(createClss, UserResource1.class, 4);
      checkUsageCount(createClss, UserResource2.class, 4);

      checkUsageCount(deployClss, UserResource1.class, 4);
      checkUsageCount(deployClss, UserResource2.class, 4);
    } finally {
      GridTestUtils.close(grid, log());
    }

    checkUsageCount(undeployClss, UserResource1.class, 4);
    checkUsageCount(undeployClss, UserResource2.class, 4);
  }
コード例 #14
0
  /** @throws Exception If failed. */
  public void testDifferentTaskNameLocally() throws Exception {
    Grid grid = startGrid(0, new GridSpringResourceContextImpl(new GenericApplicationContext()));

    // Versions are different - should not share
    // 2 resource created locally
    try {
      grid.compute().execute(SharedResourceTask1Version1.class, null).get();

      try {
        grid.compute().execute(SharedResourceTask1Version2.class, null).get();

        assert false : "SharedResourceTask4 should not be allowed to deploy.";
      } catch (GridException e) {
        info("Received expected exception: " + e);
      }
    } finally {
      GridTestUtils.close(grid, log());
    }
  }
コード例 #15
0
  /** @throws Exception If failed. */
  public void testSameTaskLocally() throws Exception {
    Grid grid = startGrid(0, new GridSpringResourceContextImpl(new GenericApplicationContext()));

    try {
      // Execute the same task twice.
      // 1 resource created locally
      grid.compute().execute(SharedResourceTask1.class, null).get();
      grid.compute().execute(SharedResourceTask1.class, null).get();

      checkUsageCount(createClss, UserResource1.class, 2);
      checkUsageCount(createClss, UserResource2.class, 2);

      checkUsageCount(deployClss, UserResource1.class, 2);
      checkUsageCount(deployClss, UserResource2.class, 2);
    } finally {
      GridTestUtils.close(grid, log());
    }

    checkUsageCount(undeployClss, UserResource1.class, 2);
    checkUsageCount(undeployClss, UserResource2.class, 2);
  }
コード例 #16
0
  /**
   * Tests that failover don't pick local node if it has been excluded from topology.
   *
   * @throws Exception If failed.
   */
  @SuppressWarnings({"WaitNotInLoop", "UnconditionalWait", "unchecked"})
  public void testFailoverTopology() throws Exception {
    try {
      Grid grid1 = startGrid(1);
      Grid grid2 = startGrid(2);

      assert grid1 != null;
      assert grid2 != null;

      grid1.compute().localDeployTask(JobTask.class, JobTask.class.getClassLoader());

      try {
        GridComputeTaskFuture<String> fut;

        synchronized (mux) {
          fut = grid1.compute().execute(JobTask.class, null);

          mux.wait();
        }

        stopAndCancelGrid(2);

        String res = fut.get();

        info("Task result: " + res);
      } catch (GridException e) {
        info("Got unexpected grid exception: " + e);
      }

      info("Failed over: " + failCnt.get());

      assert failCnt.get() == 1
          : "Invalid fail over counter [expected=1, actual=" + failCnt.get() + ']';
    } finally {
      stopGrid(1);

      // Stopping stopped instance just in case.
      stopGrid(2);
    }
  }
コード例 #17
0
  /**
   * Listen to events that happen only on local node.
   *
   * @throws GridException If failed.
   */
  private static void localListen() throws GridException {
    Grid g = GridGain.grid();

    // Register event listener for all local task execution events.
    g.events()
        .localListen(
            new GridPredicate<GridEvent>() {
              @Override
              public boolean apply(GridEvent evt) {
                GridTaskEvent taskEvt = (GridTaskEvent) evt;

                System.out.println();
                System.out.println(
                    "Git event notification [evt="
                        + evt.name()
                        + ", taskName="
                        + taskEvt.taskName()
                        + ']');

                return true;
              }
            },
            EVTS_TASK_EXECUTION);

    // Generate task events.
    g.compute()
        .withName("example-event-task")
        .run(
            new GridRunnable() {
              @Override
              public void run() {
                System.out.println();
                System.out.println("Executing sample job.");
              }
            })
        .get();
  }
コード例 #18
0
  /** @throws Exception If failed. */
  public void testSameTaskFromTwoNodesUndeploy() throws Exception {
    Grid grid1 = null;
    Grid grid2 = null;
    Grid grid3 = null;

    try {
      grid1 = startGrid(1, new GridSpringResourceContextImpl(new GenericApplicationContext()));
      grid2 = startGrid(2, new GridSpringResourceContextImpl(new GenericApplicationContext()));
      grid3 = startGrid(3, new GridSpringResourceContextImpl(new GenericApplicationContext()));

      grid1.compute().execute(SharedResourceTask1.class, null).get();
      grid2.compute().execute(SharedResourceTask1.class, null).get();

      checkUsageCount(createClss, UserResource1.class, 6);
      checkUsageCount(deployClss, UserResource1.class, 6);
      checkUsageCount(createClss, UserResource2.class, 6);
      checkUsageCount(deployClss, UserResource2.class, 6);

      checkUsageCount(undeployClss, UserResource1.class, 0);
      checkUsageCount(undeployClss, UserResource2.class, 0);

      grid1.compute().undeployTask(SharedResourceTask1.class.getName());

      // Wait until resources get undeployed remotely
      // because undeploy is asynchronous apply.
      Thread.sleep(3000);

      checkUsageCount(undeployClss, UserResource1.class, 6);
      checkUsageCount(undeployClss, UserResource2.class, 6);

      grid2.compute().undeployTask(SharedResourceTask1.class.getName());

      // Wait until resources get undeployed remotely
      // because undeploy is asynchronous apply.
      Thread.sleep(3000);

      // All Tasks from originating nodes were undeployed. All resources should be cleaned up.
      checkUsageCount(undeployClss, UserResource1.class, 6);
      checkUsageCount(undeployClss, UserResource2.class, 6);
    } finally {
      GridTestUtils.close(grid1, log());
      GridTestUtils.close(grid2, log());
      GridTestUtils.close(grid3, log());
    }
  }
コード例 #19
0
  /** @throws Exception If failed. */
  public void testAffinityExecute() throws Exception {
    GridClientCompute dflt = client.compute();

    GridClientData data = client.data(PARTITIONED_CACHE_NAME);

    Collection<? extends GridClientNode> nodes = dflt.nodes();

    assertEquals(NODES_CNT, nodes.size());

    for (int i = 0; i < NODES_CNT; i++) {
      Grid g = grid(i);

      assert g != null;

      int affinityKey = -1;

      for (int key = 0; key < 10000; key++) {
        if (g.localNode().id().equals(data.affinity(key))) {
          affinityKey = key;

          break;
        }
      }

      if (affinityKey == -1)
        throw new Exception("Unable to found key for which node is primary: " + g.localNode().id());

      GridClientNode clientNode = dflt.node(g.localNode().id());

      assertNotNull("Client node for " + g.localNode().id() + " was not found", clientNode);

      String res =
          dflt.affinityExecute(TestTask.class.getName(), PARTITIONED_CACHE_NAME, affinityKey, null);

      assertNotNull(res);

      assertEquals(g.localNode().id().toString(), res);
    }
  }
コード例 #20
0
  /** {@inheritDoc} */
  @Nullable
  @Override
  public final Map<? extends GridComputeJob, GridNode> map(
      List<GridNode> subgrid, @Nullable GridGgfsTaskArgs<T> args) throws GridException {
    assert grid != null;
    assert args != null;

    GridGgfs ggfs = grid.ggfs(args.ggfsName());
    GridGgfsProcessorAdapter ggfsProc = ((GridKernal) grid).context().ggfs();

    Map<GridComputeJob, GridNode> splitMap = new HashMap<>();

    Map<UUID, GridNode> nodes = mapSubgrid(subgrid);

    for (GridGgfsPath path : args.paths()) {
      GridGgfsFile file = ggfs.info(path);

      if (file == null) {
        if (args.skipNonExistentFiles()) continue;
        else
          throw new GridException("Failed to process GGFS file because it doesn't exist: " + path);
      }

      Collection<GridGgfsBlockLocation> aff =
          ggfs.affinity(path, 0, file.length(), args.maxRangeLength());

      long totalLen = 0;

      for (GridGgfsBlockLocation loc : aff) {
        GridNode node = null;

        for (UUID nodeId : loc.nodeIds()) {
          node = nodes.get(nodeId);

          if (node != null) break;
        }

        if (node == null)
          throw new GridException(
              "Failed to find any of block affinity nodes in subgrid [loc="
                  + loc
                  + ", subgrid="
                  + subgrid
                  + ']');

        GridGgfsJob job =
            createJob(path, new GridGgfsFileRange(file.path(), loc.start(), loc.length()), args);

        if (job != null) {
          GridComputeJob jobImpl =
              ggfsProc.createJob(
                  job, ggfs.name(), file.path(), loc.start(), loc.length(), args.recordResolver());

          splitMap.put(jobImpl, node);
        }

        totalLen += loc.length();
      }

      assert totalLen == file.length();
    }

    return splitMap;
  }