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
- links to