Uploaded image for project: 'Ignite'
  1. Ignite
  2. IGNITE-14459

Affinity call may fail if called upon merged exchanges

    XMLWordPrintableJSON

Details

    • Improvement
    • Status: Resolved
    • Major
    • Resolution: Fixed
    • None
    • 2.13
    • compute

    Description

      When exchanges are merged, intermediate affinity assignments are not filled. At the same time, when a client chooses topology to run affinity call on, it may take a non-completed exchange version. As a result, when the affinity fetch task arrives on a node, it will look up a non-existing assignment, resulting in "Getting affinity for topology version earlier than affinity is calculated" exception.

      CacheAffinityCallSelfTest.testAffinityCallNoServerNode is flaky because of this bug.

      The following test case for CacheAffinityCallSelfTest demonstrates the issue:

          /**
           * @throws Exception if failed.
           */
          @Test
          public void testAffinityCallMergedExchanges() throws Exception {
              startGrids(SRVS);
      
              final Integer key = 1;
      
              final IgniteEx client = startClientGrid(SRVS);
      
              assertTrue(client.configuration().isClientMode());
              assertNull(client.context().cache().cache(CACHE_NAME));
      
              try {
                  grid(0).context().cache().context().exchange().mergeExchangesTestWaitVersion(
                      new AffinityTopologyVersion(SRVS + 3, 0),
                      null
                  );
      
                  IgniteInternalFuture<IgniteEx> fut1 = GridTestUtils.runAsync(() -> startGrid(SRVS + 1));
      
                  assertTrue(GridTestUtils.waitForCondition(() -> client.context().cache().context()
                      .exchange().lastTopologyFuture()
                      .initialVersion().equals(new AffinityTopologyVersion(SRVS + 2, 0)), 5_000));
      
                  assertFalse(fut1.isDone());
      
                  // The future should not complete until second node is started.
                  IgniteInternalFuture<Object> fut2 = GridTestUtils.runAsync(() ->
                      client.compute().affinityCall(CACHE_NAME, key, new CheckCallable(key, null)));
      
                  startGrid(SRVS + 2);
      
                  fut1.get();
                  fut2.get();
              }
              finally {
                  stopAllGrids();
              }
          }
      

      Attachments

        Issue Links

          Activity

            People

              agoncharuk Alexey Goncharuk
              agoncharuk Alexey Goncharuk
              Votes:
              0 Vote for this issue
              Watchers:
              4 Start watching this issue

              Dates

                Created:
                Updated:
                Resolved:

                Time Tracking

                  Estimated:
                  Original Estimate - Not Specified
                  Not Specified
                  Remaining:
                  Remaining Estimate - 0h
                  0h
                  Logged:
                  Time Spent - 20m
                  20m