From 1740273da20568067a1a524dab000c79f8068d3d Mon Sep 17 00:00:00 2001 From: Vladimir Steshin Date: Thu, 11 Jun 2026 12:23:26 +0300 Subject: [PATCH 01/18] impl --- .../internal/managers/communication/UnknownMessageException.java | 0 .../apache/ignite/plugin/extensions/communication/Message.java | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename modules/{core => commons}/src/main/java/org/apache/ignite/internal/managers/communication/UnknownMessageException.java (100%) rename modules/{core => commons}/src/main/java/org/apache/ignite/plugin/extensions/communication/Message.java (100%) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/UnknownMessageException.java b/modules/commons/src/main/java/org/apache/ignite/internal/managers/communication/UnknownMessageException.java similarity index 100% rename from modules/core/src/main/java/org/apache/ignite/internal/managers/communication/UnknownMessageException.java rename to modules/commons/src/main/java/org/apache/ignite/internal/managers/communication/UnknownMessageException.java diff --git a/modules/core/src/main/java/org/apache/ignite/plugin/extensions/communication/Message.java b/modules/commons/src/main/java/org/apache/ignite/plugin/extensions/communication/Message.java similarity index 100% rename from modules/core/src/main/java/org/apache/ignite/plugin/extensions/communication/Message.java rename to modules/commons/src/main/java/org/apache/ignite/plugin/extensions/communication/Message.java From baa147367a3876e08e30661b87fa6251cdd61290 Mon Sep 17 00:00:00 2001 From: Vladimir Steshin Date: Fri, 12 Jun 2026 12:43:24 +0300 Subject: [PATCH 02/18] in-progress --- ...utedOperationContextAttributeRegistry.java | 83 +++++++++++++++++++ .../thread/context/OperationContext.java | 2 +- .../context/OperationContextAttribute.java | 1 + .../ignite/spi/discovery/tcp/ClientImpl.java | 14 +++- .../ignite/spi/discovery/tcp/ServerImpl.java | 26 ++++-- .../messages/InetSocketAddressMessage.java | 1 - .../messages/TcpDiscoveryAbstractMessage.java | 6 ++ .../OperationContextAttributesTest.java | 76 ++++++++++++++++- 8 files changed, 199 insertions(+), 10 deletions(-) create mode 100644 modules/commons/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextAttributeRegistry.java diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextAttributeRegistry.java b/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextAttributeRegistry.java new file mode 100644 index 0000000000000..93c4ddb621c34 --- /dev/null +++ b/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextAttributeRegistry.java @@ -0,0 +1,83 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ignite.internal.thread.context; + +import java.util.HashMap; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import org.apache.ignite.IgniteException; +import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.plugin.extensions.communication.Message; +import org.jetbrains.annotations.Nullable; + +/** */ +public class DistributedOperationContextAttributeRegistry { + /** */ + private static final DistributedOperationContextAttributeRegistry INSTANCE = new DistributedOperationContextAttributeRegistry(); + + /** Attributes by their id. */ + private final Map> attributes = new ConcurrentHashMap<>(); + + /** */ + public static DistributedOperationContextAttributeRegistry instance() { + return INSTANCE; + } + + /** */ + public void register(byte id, OperationContextAttribute attr) { + assert id >= 0; + + if(attributes.size() == OperationContextAttribute.MAX_ATTR_CNT) + throw new IgniteException("Maximum number of attributes is exceeded [" + OperationContextAttribute.MAX_ATTR_CNT + "]."); + + if (attributes.putIfAbsent(id, attr) != null) + throw new IgniteException("Duplicated attribute id: " + id); + } + + /** @return Values for all registered operation context attributes. */ + public @Nullable Map collectContext() { + Map res = null; + + for (Map.Entry> e : attributes.entrySet()) { + OperationContextAttribute attr = e.getValue(); + + Message curVal = OperationContext.get(attr); + + if (!Objects.equals(attr.initialValue(), curVal)) { + if (res == null) + res = new HashMap<>(attributes.size(), 1.0f); + + res.put(e.getKey(), curVal); + } + } + + return res; + } + + /** */ + public Scope restoreContext(Map res) { + if (F.isEmpty(res)) + return Scope.NOOP_SCOPE; + + OperationContext.ContextUpdater updater = OperationContext.ContextUpdater.create(); + + res.forEach((id, attr) -> updater.set((OperationContextAttribute)attributes.get(id), attr)); + + return updater.apply(); + } +} diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/OperationContext.java b/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/OperationContext.java index 6953d8b853891..4a8f556781cf7 100644 --- a/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/OperationContext.java +++ b/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/OperationContext.java @@ -322,7 +322,7 @@ private static class AttributeValueHolder { } /** Allows to change multiple attribute values in a single update operation and skip updates that changes nothing. */ - private static class ContextUpdater { + static class ContextUpdater { /** */ private static final int INIT_UPDATES_CAPACITY = 3; diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/OperationContextAttribute.java b/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/OperationContextAttribute.java index 499d241d9ccba..f5f20066a3d2f 100644 --- a/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/OperationContextAttribute.java +++ b/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/OperationContextAttribute.java @@ -18,6 +18,7 @@ package org.apache.ignite.internal.thread.context; import java.util.concurrent.atomic.AtomicInteger; +import org.apache.ignite.plugin.extensions.communication.Message; import org.jetbrains.annotations.Nullable; /** diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java index a0e1a20048786..3476ba8785843 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java @@ -70,6 +70,8 @@ import org.apache.ignite.internal.processors.tracing.messages.SpanContainer; import org.apache.ignite.internal.processors.tracing.messages.TraceableMessage; import org.apache.ignite.internal.processors.tracing.messages.TraceableMessagesTable; +import org.apache.ignite.internal.thread.context.DistributedOperationContextAttributeRegistry; +import org.apache.ignite.internal.thread.context.Scope; import org.apache.ignite.internal.util.future.GridFutureAdapter; import org.apache.ignite.internal.util.tostring.GridToStringExclude; import org.apache.ignite.internal.util.typedef.F; @@ -1310,6 +1312,8 @@ private class SocketWriter extends IgniteSpiThread { * @param msg Message. */ private void sendMessage(TcpDiscoveryAbstractMessage msg) { + msg.opCtxAttrs = DistributedOperationContextAttributeRegistry.instance().collectContext(); + synchronized (mux) { queue.add(msg); @@ -2001,7 +2005,15 @@ else if (discoMsg instanceof TcpDiscoveryCheckFailedMessage) } } - processDiscoveryMessage((TcpDiscoveryAbstractMessage)msg); + TcpDiscoveryAbstractMessage msg0 = (TcpDiscoveryAbstractMessage)msg; + + if (F.isEmpty(msg0.opCtxAttrs)) + processDiscoveryMessage(msg0); + else { + try (Scope ignored = DistributedOperationContextAttributeRegistry.instance().restoreContext(msg0.opCtxAttrs)) { + processDiscoveryMessage(msg0); + } + } } } } diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java index 82c012c2a1a94..a32bf95fd1bc5 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java @@ -95,6 +95,8 @@ import org.apache.ignite.internal.processors.tracing.messages.SpanContainer; import org.apache.ignite.internal.processors.tracing.messages.TraceableMessage; import org.apache.ignite.internal.processors.tracing.messages.TraceableMessagesTable; +import org.apache.ignite.internal.thread.context.DistributedOperationContextAttributeRegistry; +import org.apache.ignite.internal.thread.context.Scope; import org.apache.ignite.internal.thread.pool.IgniteThreadPoolExecutor; import org.apache.ignite.internal.util.GridBoundedLinkedHashSet; import org.apache.ignite.internal.util.GridConcurrentHashSet; @@ -3046,6 +3048,9 @@ void addMessage(TcpDiscoveryAbstractMessage msg, boolean ignoreHighPriority, boo return; } + if (!fromSocket) + msg.opCtxAttrs = DistributedOperationContextAttributeRegistry.instance().collectContext(); + if (msg instanceof TraceableMessage) { TraceableMessage tMsg = (TraceableMessage)msg; @@ -3173,11 +3178,8 @@ protected void runTasks() { task.run(); } - /** {@inheritDoc} */ - @Override protected void processMessage(TcpDiscoveryAbstractMessage msg) { - if (msg == WAKEUP) - return; - + /** */ + private void processMessage0(TcpDiscoveryAbstractMessage msg) { notifiedDiscovery.set(false); if (msg instanceof TraceableMessage) { @@ -3315,6 +3317,20 @@ else if (msg instanceof TcpDiscoveryAuthFailedMessage) } } + /** {@inheritDoc} */ + @Override protected void processMessage(TcpDiscoveryAbstractMessage msg) { + if (msg == WAKEUP) + return; + + if (F.isEmpty(msg.opCtxAttrs)) + processMessage0(msg); + else { + try (Scope ignored = DistributedOperationContextAttributeRegistry.instance().restoreContext(msg.opCtxAttrs)) { + processMessage0(msg); + } + } + } + /** * Processes authentication failed message. * diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/InetSocketAddressMessage.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/InetSocketAddressMessage.java index f23e36f200d27..d76279fb28082 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/InetSocketAddressMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/InetSocketAddressMessage.java @@ -52,7 +52,6 @@ public int port() { return port; } - /** {@inheritDoc} */ @Override public String toString() { return S.toString(InetSocketAddressMessage.class, this); diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryAbstractMessage.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryAbstractMessage.java index 7a97763c36b25..e04f1d856c0ec 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryAbstractMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryAbstractMessage.java @@ -19,6 +19,7 @@ import java.io.Externalizable; import java.util.HashSet; +import java.util.Map; import java.util.Set; import java.util.UUID; import org.apache.ignite.internal.Order; @@ -76,6 +77,11 @@ public abstract class TcpDiscoveryAbstractMessage implements Message { @Order(4) Set failedNodes; + /** Operation context attributes: id -> attribute value. */ + @GridToStringInclude + @Order(5) + public @Nullable Map opCtxAttrs; + /** * Default no-arg constructor for {@link Externalizable} interface. */ diff --git a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java index 9de906b27290c..e6454be489cc7 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java @@ -17,6 +17,7 @@ package org.apache.ignite.internal.thread.context; +import java.net.InetAddress; import java.util.ArrayList; import java.util.Collections; import java.util.LinkedList; @@ -35,9 +36,17 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; +import org.apache.ignite.Ignite; import org.apache.ignite.IgniteException; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.events.Event; +import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.managers.communication.GridIoPolicy; +import org.apache.ignite.internal.managers.discovery.CustomEventListener; +import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; +import org.apache.ignite.internal.processors.cache.DynamicCacheChangeBatch; import org.apache.ignite.internal.processors.timeout.GridTimeoutObject; import org.apache.ignite.internal.processors.timeout.GridTimeoutProcessor; import org.apache.ignite.internal.thread.context.concurrent.IgniteCompletableFuture; @@ -48,20 +57,24 @@ import org.apache.ignite.internal.thread.pool.IgniteStripedThreadPoolExecutor; import org.apache.ignite.internal.thread.pool.IgniteThreadPoolExecutor; import org.apache.ignite.internal.util.future.GridFutureAdapter; +import org.apache.ignite.internal.util.typedef.G; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.internal.util.worker.queue.IgniteAsyncObjectHandler; import org.apache.ignite.internal.util.worker.queue.IgniteDelayedObjectHandler; import org.apache.ignite.lang.IgniteClosure; import org.apache.ignite.lang.IgniteInClosure; import org.apache.ignite.lang.IgniteOutClosure; +import org.apache.ignite.lang.IgnitePredicate; import org.apache.ignite.lang.IgniteRunnable; import org.apache.ignite.lang.IgniteUuid; +import org.apache.ignite.spi.discovery.tcp.messages.InetSocketAddressMessage; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; import org.apache.ignite.thread.IgniteThread; import org.junit.Test; import org.springframework.lang.NonNull; import static java.util.concurrent.TimeUnit.MILLISECONDS; +import static org.apache.ignite.internal.events.DiscoveryCustomEvent.EVT_DISCOVERY_CUSTOM_EVT; import static org.apache.ignite.testframework.GridTestUtils.assertThrowsAnyCause; import static org.apache.ignite.testframework.GridTestUtils.assertThrowsWithCause; @@ -85,6 +98,9 @@ public class OperationContextAttributesTest extends GridCommonAbstractTest { /** */ private int beforeTestReservedAttrIds; + /** */ + private IgnitePredicate evtLsnr; + /** {@inheritDoc} */ @Override protected void beforeTest() throws Exception { super.beforeTest(); @@ -98,6 +114,8 @@ public class OperationContextAttributesTest extends GridCommonAbstractTest { @Override protected void afterTest() throws Exception { super.afterTest(); + stopAllGrids(); + if (poolToShutdownAfterTest != null) poolToShutdownAfterTest.shutdownNow(); @@ -105,6 +123,16 @@ public class OperationContextAttributesTest extends GridCommonAbstractTest { OperationContextAttribute.ID_GEN.set(beforeTestReservedAttrIds); } + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { + IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); + + if (evtLsnr != null) + cfg.setLocalEventListeners(Collections.singletonMap(evtLsnr, new int[] {EVT_DISCOVERY_CUSTOM_EVT})); + + return cfg; + } + /** */ @Test public void testNotAttachedAttribute() { @@ -808,6 +836,51 @@ public void testContextAwareDelayQueue() throws Exception { } } + /** */ + @Test + public void testSendAttributesByDiscovery() throws Exception { + byte attrId = (byte)(OperationContextAttribute.MAX_ATTR_CNT + 1); + + InetSocketAddressMessage dfltAttrVal = new InetSocketAddressMessage(InetAddress.getLoopbackAddress(), 80); + + OperationContextAttribute attr = OperationContextAttribute.newInstance(); + + DistributedOperationContextAttributeRegistry.instance().register(attrId, attr); + + startGrids(2); + Ignite cli = startClientGrid(); + + CountDownLatch clientLatch = new CountDownLatch(1); + CountDownLatch srvrLatch = new CountDownLatch(1); + + for (int i = 1; i < G.allGrids().size(); ++i) { + int i0 = i; + + grid(i).context().discovery().setCustomEventListener( + DynamicCacheChangeBatch.class, new CustomEventListener<>() { + @Override public void onCustomEvent(AffinityTopologyVersion topVer, ClusterNode snd, + DynamicCacheChangeBatch msg) { + + if (grid(i0).localNode().isClient()) + clientLatch.countDown(); + else + srvrLatch.countDown(); + } + }); + } + + InetSocketAddressMessage newAttrVal = new InetSocketAddressMessage(dfltAttrVal.address(), 443); + + assertFalse(newAttrVal.equals(dfltAttrVal)); + + try (Scope ignored = OperationContext.set(attr, newAttrVal)) { + grid(0).createCache(defaultCacheConfiguration()); + } + + assertTrue(clientLatch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); + assertTrue(srvrLatch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); + } + /** */ private void doContextAwareExecutorServiceTest(ExecutorService pool) throws Exception { CountDownLatch poolUnblockedLatch = blockPool(pool); @@ -923,9 +996,8 @@ public AttributeValueChecker(String expStrAttrVal, Integer expIntAttrVal) { /** */ static void assertAllCreatedChecksPassed() throws Exception { - for (AttributeValueChecker check : CHECKS) { + for (AttributeValueChecker check : CHECKS) check.get(5_000, MILLISECONDS); - } } /** */ From 9f8e09d8a01167e5b8bb7a6b576353850cc792a4 Mon Sep 17 00:00:00 2001 From: Vladimir Steshin Date: Sun, 14 Jun 2026 20:39:02 +0300 Subject: [PATCH 03/18] raw --- ...utedOperationContextAttributeRegistry.java | 2 +- .../context/OperationContextAttribute.java | 1 - .../OperationContextAttributesTest.java | 59 +++++++++++++++---- 3 files changed, 50 insertions(+), 12 deletions(-) diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextAttributeRegistry.java b/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextAttributeRegistry.java index 93c4ddb621c34..4d9e9c0fd6698 100644 --- a/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextAttributeRegistry.java +++ b/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextAttributeRegistry.java @@ -42,7 +42,7 @@ public static DistributedOperationContextAttributeRegistry instance() { public void register(byte id, OperationContextAttribute attr) { assert id >= 0; - if(attributes.size() == OperationContextAttribute.MAX_ATTR_CNT) + if (attributes.size() == OperationContextAttribute.MAX_ATTR_CNT) throw new IgniteException("Maximum number of attributes is exceeded [" + OperationContextAttribute.MAX_ATTR_CNT + "]."); if (attributes.putIfAbsent(id, attr) != null) diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/OperationContextAttribute.java b/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/OperationContextAttribute.java index f5f20066a3d2f..499d241d9ccba 100644 --- a/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/OperationContextAttribute.java +++ b/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/OperationContextAttribute.java @@ -18,7 +18,6 @@ package org.apache.ignite.internal.thread.context; import java.util.concurrent.atomic.AtomicInteger; -import org.apache.ignite.plugin.extensions.communication.Message; import org.jetbrains.annotations.Nullable; /** diff --git a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java index e6454be489cc7..e82721c10b114 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java @@ -36,12 +36,10 @@ import java.util.function.Consumer; import java.util.function.Function; import java.util.function.Supplier; -import org.apache.ignite.Ignite; import org.apache.ignite.IgniteException; import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.events.Event; -import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.managers.communication.GridIoPolicy; import org.apache.ignite.internal.managers.discovery.CustomEventListener; @@ -77,6 +75,7 @@ import static org.apache.ignite.internal.events.DiscoveryCustomEvent.EVT_DISCOVERY_CUSTOM_EVT; import static org.apache.ignite.testframework.GridTestUtils.assertThrowsAnyCause; import static org.apache.ignite.testframework.GridTestUtils.assertThrowsWithCause; +import static org.apache.ignite.testframework.GridTestUtils.waitForCondition; /** */ public class OperationContextAttributesTest extends GridCommonAbstractTest { @@ -848,12 +847,15 @@ public void testSendAttributesByDiscovery() throws Exception { DistributedOperationContextAttributeRegistry.instance().register(attrId, attr); startGrids(2); - Ignite cli = startClientGrid(); + startClientGrid(2); - CountDownLatch clientLatch = new CountDownLatch(1); - CountDownLatch srvrLatch = new CountDownLatch(1); + CountDownLatch coordLatch = new CountDownLatch(3); + CountDownLatch srvrLatch = new CountDownLatch(3); + CountDownLatch clientLatch = new CountDownLatch(3); - for (int i = 1; i < G.allGrids().size(); ++i) { + InetSocketAddressMessage valToSend = new InetSocketAddressMessage(dfltAttrVal.address(), 443); + + for (int i = 0; i < G.allGrids().size(); ++i) { int i0 = i; grid(i).context().discovery().setCustomEventListener( @@ -861,24 +863,61 @@ public void testSendAttributesByDiscovery() throws Exception { @Override public void onCustomEvent(AffinityTopologyVersion topVer, ClusterNode snd, DynamicCacheChangeBatch msg) { + InetSocketAddressMessage receivedVal = OperationContext.get(attr); + + assertNotNull(receivedVal); + + assertFalse(dfltAttrVal.port() == receivedVal.port()); + + assertEquals(receivedVal.port(), valToSend.port()); + assertEquals(receivedVal.address(), valToSend.address()); + if (grid(i0).localNode().isClient()) clientLatch.countDown(); + else if (grid(i0).localNode().order() == 1) + coordLatch.countDown(); else srvrLatch.countDown(); } }); } - InetSocketAddressMessage newAttrVal = new InetSocketAddressMessage(dfltAttrVal.address(), 443); + assertFalse(valToSend.equals(dfltAttrVal)); - assertFalse(newAttrVal.equals(dfltAttrVal)); + assertNull(OperationContext.get(attr)); - try (Scope ignored = OperationContext.set(attr, newAttrVal)) { + // Send from a coordinator. + try (Scope ignored = OperationContext.set(attr, valToSend)) { grid(0).createCache(defaultCacheConfiguration()); } - assertTrue(clientLatch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); + assertTrue(waitForCondition(() -> coordLatch.getCount() == 2, getTestTimeout())); + assertTrue(waitForCondition(() -> srvrLatch.getCount() == 2, getTestTimeout())); + assertTrue(waitForCondition(() -> clientLatch.getCount() == 2, getTestTimeout())); + + assertNull(OperationContext.get(attr)); + + // Send from a server. + try (Scope ignored = OperationContext.set(attr, valToSend)) { + grid(1).destroyCache(DEFAULT_CACHE_NAME); + } + + assertTrue(waitForCondition(() -> coordLatch.getCount() == 1, getTestTimeout())); + assertTrue(waitForCondition(() -> srvrLatch.getCount() == 1, getTestTimeout())); + assertTrue(waitForCondition(() -> clientLatch.getCount() == 1, getTestTimeout())); + + assertNull(OperationContext.get(attr)); + + // Send from a client. + try (Scope ignored = OperationContext.set(attr, valToSend)) { + grid(2).createCache(defaultCacheConfiguration()); + } + + assertNull(OperationContext.get(attr)); + + assertTrue(coordLatch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); assertTrue(srvrLatch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); + assertTrue(clientLatch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); } /** */ From 9f4ccecbea9382da2a1da57cd5d595d6c9966045 Mon Sep 17 00:00:00 2001 From: Vladimir Steshin Date: Mon, 15 Jun 2026 20:42:00 +0300 Subject: [PATCH 04/18] impl --- ...utedOperationContextAttributeRegistry.java | 21 +++++++++---------- .../UnknownMessageException.java | 0 .../extensions/communication/Message.java | 0 3 files changed, 10 insertions(+), 11 deletions(-) rename modules/{commons => core}/src/main/java/org/apache/ignite/internal/managers/communication/UnknownMessageException.java (100%) rename modules/{commons => core}/src/main/java/org/apache/ignite/plugin/extensions/communication/Message.java (100%) diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextAttributeRegistry.java b/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextAttributeRegistry.java index 4d9e9c0fd6698..d81b0d1d321cb 100644 --- a/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextAttributeRegistry.java +++ b/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextAttributeRegistry.java @@ -22,7 +22,6 @@ import java.util.concurrent.ConcurrentHashMap; import org.apache.ignite.IgniteException; import org.apache.ignite.internal.util.typedef.F; -import org.apache.ignite.plugin.extensions.communication.Message; import org.jetbrains.annotations.Nullable; /** */ @@ -31,7 +30,7 @@ public class DistributedOperationContextAttributeRegistry { private static final DistributedOperationContextAttributeRegistry INSTANCE = new DistributedOperationContextAttributeRegistry(); /** Attributes by their id. */ - private final Map> attributes = new ConcurrentHashMap<>(); + private final Map> attributes = new ConcurrentHashMap<>(); /** */ public static DistributedOperationContextAttributeRegistry instance() { @@ -39,7 +38,7 @@ public static DistributedOperationContextAttributeRegistry instance() { } /** */ - public void register(byte id, OperationContextAttribute attr) { + public void register(byte id, OperationContextAttribute attr) { assert id >= 0; if (attributes.size() == OperationContextAttribute.MAX_ATTR_CNT) @@ -50,19 +49,19 @@ public void register(byte id, OperationContextAttribute a } /** @return Values for all registered operation context attributes. */ - public @Nullable Map collectContext() { - Map res = null; + public @Nullable Map collectContext() { + Map res = null; - for (Map.Entry> e : attributes.entrySet()) { - OperationContextAttribute attr = e.getValue(); + for (Map.Entry> e : attributes.entrySet()) { + OperationContextAttribute attr = e.getValue(); - Message curVal = OperationContext.get(attr); + Object curVal = OperationContext.get(attr); if (!Objects.equals(attr.initialValue(), curVal)) { if (res == null) res = new HashMap<>(attributes.size(), 1.0f); - res.put(e.getKey(), curVal); + res.put(e.getKey(), (T)curVal); } } @@ -70,13 +69,13 @@ public void register(byte id, OperationContextAttribute a } /** */ - public Scope restoreContext(Map res) { + public Scope restoreContext(Map res) { if (F.isEmpty(res)) return Scope.NOOP_SCOPE; OperationContext.ContextUpdater updater = OperationContext.ContextUpdater.create(); - res.forEach((id, attr) -> updater.set((OperationContextAttribute)attributes.get(id), attr)); + res.forEach((id, attr) -> updater.set((OperationContextAttribute)attributes.get(id), attr)); return updater.apply(); } diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/managers/communication/UnknownMessageException.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/UnknownMessageException.java similarity index 100% rename from modules/commons/src/main/java/org/apache/ignite/internal/managers/communication/UnknownMessageException.java rename to modules/core/src/main/java/org/apache/ignite/internal/managers/communication/UnknownMessageException.java diff --git a/modules/commons/src/main/java/org/apache/ignite/plugin/extensions/communication/Message.java b/modules/core/src/main/java/org/apache/ignite/plugin/extensions/communication/Message.java similarity index 100% rename from modules/commons/src/main/java/org/apache/ignite/plugin/extensions/communication/Message.java rename to modules/core/src/main/java/org/apache/ignite/plugin/extensions/communication/Message.java From ca46b5dac534124c308226da05c78bbfab2f70f4 Mon Sep 17 00:00:00 2001 From: Vladimir Steshin Date: Tue, 16 Jun 2026 17:05:21 +0300 Subject: [PATCH 05/18] fix --- .../internal/codegen/MessageProcessorTest.java | 10 ---------- .../context/OperationContextAttributesTest.java | 17 ----------------- 2 files changed, 27 deletions(-) diff --git a/modules/core/src/test/java/org/apache/ignite/internal/codegen/MessageProcessorTest.java b/modules/core/src/test/java/org/apache/ignite/internal/codegen/MessageProcessorTest.java index e1e2e38dbbf5c..9495d39125ff7 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/codegen/MessageProcessorTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/codegen/MessageProcessorTest.java @@ -33,12 +33,8 @@ import org.apache.ignite.cache.QueryIndex; import org.apache.ignite.cache.QueryIndexType; import org.apache.ignite.internal.MessageProcessor; -import org.apache.ignite.internal.Order; import org.apache.ignite.internal.cache.query.QueryIndexMessage; import org.apache.ignite.internal.util.CommonUtils; -import org.apache.ignite.internal.util.typedef.F; -import org.apache.ignite.lang.IgniteUuid; -import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.plugin.extensions.communication.mappers.DefaultEnumMapper; import org.apache.ignite.transactions.TransactionIsolation; import org.junit.Test; @@ -363,13 +359,7 @@ static Compilation compile(Processor proc, String... srcFiles) { for (String srcFile: srcFiles) input.add(javaFile(srcFile)); - File igniteCoreJar = jarForClass(Message.class); - File igniteCodegenJar = jarForClass(Order.class); - File igniteBinaryApiJar = jarForClass(IgniteUuid.class); - File igniteCommonsJar = jarForClass(CommonUtils.class); - return Compiler.javac() - .withClasspath(F.asList(igniteCoreJar, igniteCodegenJar, igniteBinaryApiJar, igniteCommonsJar)) .withProcessors(proc) .compile(input); } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java index e82721c10b114..a67ebefa1cef1 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java @@ -38,8 +38,6 @@ import java.util.function.Supplier; import org.apache.ignite.IgniteException; import org.apache.ignite.cluster.ClusterNode; -import org.apache.ignite.configuration.IgniteConfiguration; -import org.apache.ignite.events.Event; import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.managers.communication.GridIoPolicy; import org.apache.ignite.internal.managers.discovery.CustomEventListener; @@ -62,7 +60,6 @@ import org.apache.ignite.lang.IgniteClosure; import org.apache.ignite.lang.IgniteInClosure; import org.apache.ignite.lang.IgniteOutClosure; -import org.apache.ignite.lang.IgnitePredicate; import org.apache.ignite.lang.IgniteRunnable; import org.apache.ignite.lang.IgniteUuid; import org.apache.ignite.spi.discovery.tcp.messages.InetSocketAddressMessage; @@ -72,7 +69,6 @@ import org.springframework.lang.NonNull; import static java.util.concurrent.TimeUnit.MILLISECONDS; -import static org.apache.ignite.internal.events.DiscoveryCustomEvent.EVT_DISCOVERY_CUSTOM_EVT; import static org.apache.ignite.testframework.GridTestUtils.assertThrowsAnyCause; import static org.apache.ignite.testframework.GridTestUtils.assertThrowsWithCause; import static org.apache.ignite.testframework.GridTestUtils.waitForCondition; @@ -97,9 +93,6 @@ public class OperationContextAttributesTest extends GridCommonAbstractTest { /** */ private int beforeTestReservedAttrIds; - /** */ - private IgnitePredicate evtLsnr; - /** {@inheritDoc} */ @Override protected void beforeTest() throws Exception { super.beforeTest(); @@ -122,16 +115,6 @@ public class OperationContextAttributesTest extends GridCommonAbstractTest { OperationContextAttribute.ID_GEN.set(beforeTestReservedAttrIds); } - /** {@inheritDoc} */ - @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { - IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); - - if (evtLsnr != null) - cfg.setLocalEventListeners(Collections.singletonMap(evtLsnr, new int[] {EVT_DISCOVERY_CUSTOM_EVT})); - - return cfg; - } - /** */ @Test public void testNotAttachedAttribute() { From a431736a670deffedc781112fdfd6124bfa09e0a Mon Sep 17 00:00:00 2001 From: Vladimir Steshin Date: Tue, 16 Jun 2026 17:12:58 +0300 Subject: [PATCH 06/18] fix --- .../OperationContextAttributesTest.java | 27 +++++++++---------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java index a67ebefa1cef1..3adde80ed4aec 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java @@ -848,25 +848,24 @@ public void testSendAttributesByDiscovery() throws Exception { InetSocketAddressMessage receivedVal = OperationContext.get(attr); - assertNotNull(receivedVal); - - assertFalse(dfltAttrVal.port() == receivedVal.port()); - - assertEquals(receivedVal.port(), valToSend.port()); - assertEquals(receivedVal.address(), valToSend.address()); - - if (grid(i0).localNode().isClient()) - clientLatch.countDown(); - else if (grid(i0).localNode().order() == 1) - coordLatch.countDown(); - else - srvrLatch.countDown(); + if (receivedVal != null) { + assertFalse(dfltAttrVal.port() == receivedVal.port()); + + assertEquals(receivedVal.port(), valToSend.port()); + assertEquals(receivedVal.address(), valToSend.address()); + + if (grid(i0).localNode().isClient()) + clientLatch.countDown(); + else if (grid(i0).localNode().order() == 1) + coordLatch.countDown(); + else + srvrLatch.countDown(); + } } }); } assertFalse(valToSend.equals(dfltAttrVal)); - assertNull(OperationContext.get(attr)); // Send from a coordinator. From 1987030a0b85fa0ce730b60afd2639c4c661be84 Mon Sep 17 00:00:00 2001 From: Vladimir Steshin Date: Wed, 17 Jun 2026 13:50:35 +0300 Subject: [PATCH 07/18] review fixes --- ...utedOperationContextAttributeRegistry.java | 32 ++++++++++++---- .../context/OperationContextAttribute.java | 2 +- .../ignite/internal/CoreMessagesProvider.java | 4 ++ .../internal/OperationContexMessage.java | 37 +++++++++++++++++++ .../ignite/spi/discovery/tcp/ClientImpl.java | 7 ++-- .../ignite/spi/discovery/tcp/ServerImpl.java | 9 +++-- .../spi/discovery/tcp/TcpDiscoveryImpl.java | 24 ++++++++++++ .../messages/TcpDiscoveryAbstractMessage.java | 6 +-- .../OperationContextAttributesTest.java | 2 +- 9 files changed, 105 insertions(+), 18 deletions(-) create mode 100644 modules/core/src/main/java/org/apache/ignite/internal/OperationContexMessage.java diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextAttributeRegistry.java b/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextAttributeRegistry.java index d81b0d1d321cb..9208fb5add00d 100644 --- a/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextAttributeRegistry.java +++ b/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextAttributeRegistry.java @@ -16,6 +16,7 @@ */ package org.apache.ignite.internal.thread.context; +import java.util.Collections; import java.util.HashMap; import java.util.Map; import java.util.Objects; @@ -48,17 +49,25 @@ public void register(byte id, OperationContextAttribute attr) { throw new IgniteException("Duplicated attribute id: " + id); } - /** @return Values for all registered operation context attributes. */ - public @Nullable Map collectContext() { - Map res = null; + /** + * TODO : Declare distributed attributes as 'extends Message' after https://issues.apache.org/jira/browse/IGNITE-28766 + * @return Values for all registered operation context attributes. + * */ + public Map collectContext(@Nullable Class checkValuesType) { + Map res = Collections.emptyMap(); for (Map.Entry> e : attributes.entrySet()) { OperationContextAttribute attr = e.getValue(); Object curVal = OperationContext.get(attr); + if (curVal != null && checkValuesType != null && !checkValuesType.isAssignableFrom(curVal.getClass())) { + throw new IgniteException("To distribute operation context attributes they have to be a " + + checkValuesType.getSimpleName()); + } + if (!Objects.equals(attr.initialValue(), curVal)) { - if (res == null) + if (res == Collections.EMPTY_MAP) res = new HashMap<>(attributes.size(), 1.0f); res.put(e.getKey(), (T)curVal); @@ -69,13 +78,22 @@ public void register(byte id, OperationContextAttribute attr) { } /** */ - public Scope restoreContext(Map res) { - if (F.isEmpty(res)) + public Scope restoreContext(int idBitmask, Object[] values) { + if (F.isEmpty(values) || idBitmask == 0) return Scope.NOOP_SCOPE; OperationContext.ContextUpdater updater = OperationContext.ContextUpdater.create(); - res.forEach((id, attr) -> updater.set((OperationContextAttribute)attributes.get(id), attr)); + for (byte attrId = 0; attrId < OperationContextAttribute.MAX_ATTR_CNT; attrId++) { + assert attrId < Integer.SIZE; + + int mask = 1 << attrId; + + if ((mask & idBitmask) == 0) + continue; + + updater.set((OperationContextAttribute)attributes.get(attrId), values[attrId]); + } return updater.apply(); } diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/OperationContextAttribute.java b/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/OperationContextAttribute.java index 499d241d9ccba..373a72ee3b278 100644 --- a/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/OperationContextAttribute.java +++ b/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/OperationContextAttribute.java @@ -32,7 +32,7 @@ public class OperationContextAttribute { static final AtomicInteger ID_GEN = new AtomicInteger(); /** */ - static final int MAX_ATTR_CNT = Integer.SIZE; + public static final int MAX_ATTR_CNT = Integer.SIZE; /** */ private final int bitmask; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java b/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java index 9da592635d229..4d4caff06d126 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java @@ -666,6 +666,10 @@ public CoreMessagesProvider(Marshaller dfltMarsh, Marshaller schemaAwareMarsh, C withNoSchema(PartitionHashRecord.class); withNoSchema(TransactionsHashRecord.class); + // [13400 - 13600]: Operation context messages. + msgIdx = 13400; + withNoSchema(OperationContexMessage.class); + assert msgIdx <= MAX_MESSAGE_ID; } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/OperationContexMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/OperationContexMessage.java new file mode 100644 index 0000000000000..d45bf3a578602 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/OperationContexMessage.java @@ -0,0 +1,37 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.ignite.internal; + +import org.apache.ignite.internal.thread.context.OperationContext; +import org.apache.ignite.plugin.extensions.communication.Message; + +/** ransport for {@link OperationContext} attributes. */ +public class OperationContexMessage implements Message { + /** Values of operation context attributes. */ + @Order(0) + public Message[] vals; + + /** Bitmask of effective attributes ids. */ + @Order(1) + public int idBitmask; + + /** Empty constructor for serialization purposes. */ + public OperationContexMessage() { + // No-op. + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java index 3476ba8785843..ce2911a83392e 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java @@ -1312,7 +1312,7 @@ private class SocketWriter extends IgniteSpiThread { * @param msg Message. */ private void sendMessage(TcpDiscoveryAbstractMessage msg) { - msg.opCtxAttrs = DistributedOperationContextAttributeRegistry.instance().collectContext(); + fillOperationContextAttributes(msg); synchronized (mux) { queue.add(msg); @@ -2007,10 +2007,11 @@ else if (discoMsg instanceof TcpDiscoveryCheckFailedMessage) TcpDiscoveryAbstractMessage msg0 = (TcpDiscoveryAbstractMessage)msg; - if (F.isEmpty(msg0.opCtxAttrs)) + if (msg0.opCtxMsg == null) processDiscoveryMessage(msg0); else { - try (Scope ignored = DistributedOperationContextAttributeRegistry.instance().restoreContext(msg0.opCtxAttrs)) { + try (Scope ignored = DistributedOperationContextAttributeRegistry.instance() + .restoreContext(msg0.opCtxMsg.idBitmask, msg0.opCtxMsg.vals)) { processDiscoveryMessage(msg0); } } diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java index a32bf95fd1bc5..e27de173ec6c2 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java @@ -81,6 +81,7 @@ import org.apache.ignite.internal.IgniteInterruptedCheckedException; import org.apache.ignite.internal.IgniteNodeAttributes; import org.apache.ignite.internal.IgnitionEx; +import org.apache.ignite.internal.OperationContexMessage; import org.apache.ignite.internal.events.DiscoveryCustomEvent; import org.apache.ignite.internal.managers.communication.UnknownMessageException; import org.apache.ignite.internal.managers.discovery.DiscoveryServerOnlyCustomMessage; @@ -3049,7 +3050,7 @@ void addMessage(TcpDiscoveryAbstractMessage msg, boolean ignoreHighPriority, boo } if (!fromSocket) - msg.opCtxAttrs = DistributedOperationContextAttributeRegistry.instance().collectContext(); + fillOperationContextAttributes(msg); if (msg instanceof TraceableMessage) { TraceableMessage tMsg = (TraceableMessage)msg; @@ -3322,10 +3323,12 @@ else if (msg instanceof TcpDiscoveryAuthFailedMessage) if (msg == WAKEUP) return; - if (F.isEmpty(msg.opCtxAttrs)) + if (msg.opCtxMsg == null) processMessage0(msg); else { - try (Scope ignored = DistributedOperationContextAttributeRegistry.instance().restoreContext(msg.opCtxAttrs)) { + OperationContexMessage cm = msg.opCtxMsg; + + try (Scope ignored = DistributedOperationContextAttributeRegistry.instance().restoreContext(cm.idBitmask, cm.vals)) { processMessage0(msg); } } diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryImpl.java index 789f3d0adb107..097a9a496c7eb 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryImpl.java @@ -37,15 +37,19 @@ import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.internal.ClusterMetricsSnapshot; import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.OperationContexMessage; import org.apache.ignite.internal.processors.cache.CacheMetricsSnapshot; import org.apache.ignite.internal.processors.cluster.CacheMetricsMessage; import org.apache.ignite.internal.processors.cluster.NodeFullMetricsMessage; import org.apache.ignite.internal.processors.cluster.NodeMetricsMessage; import org.apache.ignite.internal.processors.tracing.NoopTracing; import org.apache.ignite.internal.processors.tracing.Tracing; +import org.apache.ignite.internal.thread.context.DistributedOperationContextAttributeRegistry; +import org.apache.ignite.internal.thread.context.OperationContextAttribute; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.LT; import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.spi.IgniteSpiContext; import org.apache.ignite.spi.IgniteSpiException; import org.apache.ignite.spi.IgniteSpiThread; @@ -450,6 +454,26 @@ public void processCacheMetricsMessage(TcpDiscoveryMetricsUpdateMessage msg, lon } } + /** */ + protected static void fillOperationContextAttributes(TcpDiscoveryAbstractMessage msg) { + DistributedOperationContextAttributeRegistry.instance().collectContext(Message.class).forEach((attrId, msgVal) -> { + assert attrId >= 0 && attrId < OperationContextAttribute.MAX_ATTR_CNT; + + if (msg.opCtxMsg == null) { + msg.opCtxMsg = new OperationContexMessage(); + + msg.opCtxMsg.vals = new Message[OperationContextAttribute.MAX_ATTR_CNT]; + } + + int mask = 1 << attrId; + + assert (msg.opCtxMsg.idBitmask & mask) == 0; + + msg.opCtxMsg.idBitmask |= mask; + msg.opCtxMsg.vals[attrId] = msgVal; + }); + } + /** * @param addrs Addresses. */ diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryAbstractMessage.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryAbstractMessage.java index e04f1d856c0ec..1f624f7775af8 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryAbstractMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryAbstractMessage.java @@ -19,9 +19,9 @@ import java.io.Externalizable; import java.util.HashSet; -import java.util.Map; import java.util.Set; import java.util.UUID; +import org.apache.ignite.internal.OperationContexMessage; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.util.tostring.GridToStringExclude; import org.apache.ignite.internal.util.tostring.GridToStringInclude; @@ -77,10 +77,10 @@ public abstract class TcpDiscoveryAbstractMessage implements Message { @Order(4) Set failedNodes; - /** Operation context attributes: id -> attribute value. */ + /** Operation context attributes message. */ @GridToStringInclude @Order(5) - public @Nullable Map opCtxAttrs; + public @Nullable OperationContexMessage opCtxMsg; /** * Default no-arg constructor for {@link Externalizable} interface. diff --git a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java index e82721c10b114..e42fe31c83f07 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java @@ -838,7 +838,7 @@ public void testContextAwareDelayQueue() throws Exception { /** */ @Test public void testSendAttributesByDiscovery() throws Exception { - byte attrId = (byte)(OperationContextAttribute.MAX_ATTR_CNT + 1); + byte attrId = (byte)(OperationContextAttribute.MAX_ATTR_CNT - 1); InetSocketAddressMessage dfltAttrVal = new InetSocketAddressMessage(InetAddress.getLoopbackAddress(), 80); From d293eb032a9b0c0f0969bbf927c9cb98f61fc4d2 Mon Sep 17 00:00:00 2001 From: Vladimir Steshin Date: Wed, 17 Jun 2026 16:03:40 +0300 Subject: [PATCH 08/18] fix --- ...ibutedOperationContextAttributeRegistry.java | 3 ++- .../context/OperationContextAttributesTest.java | 17 ----------------- 2 files changed, 2 insertions(+), 18 deletions(-) diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextAttributeRegistry.java b/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextAttributeRegistry.java index 9208fb5add00d..a6fb4d41de982 100644 --- a/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextAttributeRegistry.java +++ b/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextAttributeRegistry.java @@ -51,8 +51,9 @@ public void register(byte id, OperationContextAttribute attr) { /** * TODO : Declare distributed attributes as 'extends Message' after https://issues.apache.org/jira/browse/IGNITE-28766 + * * @return Values for all registered operation context attributes. - * */ + */ public Map collectContext(@Nullable Class checkValuesType) { Map res = Collections.emptyMap(); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java index e42fe31c83f07..19b3a5d39a636 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java @@ -38,8 +38,6 @@ import java.util.function.Supplier; import org.apache.ignite.IgniteException; import org.apache.ignite.cluster.ClusterNode; -import org.apache.ignite.configuration.IgniteConfiguration; -import org.apache.ignite.events.Event; import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.managers.communication.GridIoPolicy; import org.apache.ignite.internal.managers.discovery.CustomEventListener; @@ -62,7 +60,6 @@ import org.apache.ignite.lang.IgniteClosure; import org.apache.ignite.lang.IgniteInClosure; import org.apache.ignite.lang.IgniteOutClosure; -import org.apache.ignite.lang.IgnitePredicate; import org.apache.ignite.lang.IgniteRunnable; import org.apache.ignite.lang.IgniteUuid; import org.apache.ignite.spi.discovery.tcp.messages.InetSocketAddressMessage; @@ -72,7 +69,6 @@ import org.springframework.lang.NonNull; import static java.util.concurrent.TimeUnit.MILLISECONDS; -import static org.apache.ignite.internal.events.DiscoveryCustomEvent.EVT_DISCOVERY_CUSTOM_EVT; import static org.apache.ignite.testframework.GridTestUtils.assertThrowsAnyCause; import static org.apache.ignite.testframework.GridTestUtils.assertThrowsWithCause; import static org.apache.ignite.testframework.GridTestUtils.waitForCondition; @@ -97,9 +93,6 @@ public class OperationContextAttributesTest extends GridCommonAbstractTest { /** */ private int beforeTestReservedAttrIds; - /** */ - private IgnitePredicate evtLsnr; - /** {@inheritDoc} */ @Override protected void beforeTest() throws Exception { super.beforeTest(); @@ -122,16 +115,6 @@ public class OperationContextAttributesTest extends GridCommonAbstractTest { OperationContextAttribute.ID_GEN.set(beforeTestReservedAttrIds); } - /** {@inheritDoc} */ - @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { - IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); - - if (evtLsnr != null) - cfg.setLocalEventListeners(Collections.singletonMap(evtLsnr, new int[] {EVT_DISCOVERY_CUSTOM_EVT})); - - return cfg; - } - /** */ @Test public void testNotAttachedAttribute() { From fd24a9734eca9d7267146fb3c70edd8b3b6cde03 Mon Sep 17 00:00:00 2001 From: Vladimir Steshin Date: Wed, 17 Jun 2026 16:20:19 +0300 Subject: [PATCH 09/18] raw --- .../OperationContextAttributesTest.java | 84 +++++++++++++++++++ 1 file changed, 84 insertions(+) diff --git a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java index 35374f64b08b4..35de4503f23e5 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java @@ -902,6 +902,90 @@ else if (grid(i0).localNode().order() == 1) assertTrue(clientLatch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); } + /** */ + @Test + public void testSendAttributesByCommunication() throws Exception { + byte attrId = (byte)(OperationContextAttribute.MAX_ATTR_CNT - 1); + + InetSocketAddressMessage dfltAttrVal = new InetSocketAddressMessage(InetAddress.getLoopbackAddress(), 80); + + OperationContextAttribute attr = OperationContextAttribute.newInstance(); + + DistributedOperationContextAttributeRegistry.instance().register(attrId, attr); + + startGrids(2); + startClientGrid(2); + + CountDownLatch coordLatch = new CountDownLatch(3); + CountDownLatch srvrLatch = new CountDownLatch(3); + CountDownLatch clientLatch = new CountDownLatch(3); + + InetSocketAddressMessage valToSend = new InetSocketAddressMessage(dfltAttrVal.address(), 443); + + for (int i = 0; i < G.allGrids().size(); ++i) { + int i0 = i; + + grid(i).context().io().addMessageListener().setCustomEventListener( + DynamicCacheChangeBatch.class, new CustomEventListener<>() { + @Override public void onCustomEvent(AffinityTopologyVersion topVer, ClusterNode snd, + DynamicCacheChangeBatch msg) { + + InetSocketAddressMessage receivedVal = OperationContext.get(attr); + + if (receivedVal != null) { + assertFalse(dfltAttrVal.port() == receivedVal.port()); + + assertEquals(receivedVal.port(), valToSend.port()); + assertEquals(receivedVal.address(), valToSend.address()); + + if (grid(i0).localNode().isClient()) + clientLatch.countDown(); + else if (grid(i0).localNode().order() == 1) + coordLatch.countDown(); + else + srvrLatch.countDown(); + } + } + }); + } + + assertFalse(valToSend.equals(dfltAttrVal)); + assertNull(OperationContext.get(attr)); + + // Send from a coordinator. + try (Scope ignored = OperationContext.set(attr, valToSend)) { + grid(0).createCache(defaultCacheConfiguration()); + } + + assertTrue(waitForCondition(() -> coordLatch.getCount() == 2, getTestTimeout())); + assertTrue(waitForCondition(() -> srvrLatch.getCount() == 2, getTestTimeout())); + assertTrue(waitForCondition(() -> clientLatch.getCount() == 2, getTestTimeout())); + + assertNull(OperationContext.get(attr)); + + // Send from a server. + try (Scope ignored = OperationContext.set(attr, valToSend)) { + grid(1).destroyCache(DEFAULT_CACHE_NAME); + } + + assertTrue(waitForCondition(() -> coordLatch.getCount() == 1, getTestTimeout())); + assertTrue(waitForCondition(() -> srvrLatch.getCount() == 1, getTestTimeout())); + assertTrue(waitForCondition(() -> clientLatch.getCount() == 1, getTestTimeout())); + + assertNull(OperationContext.get(attr)); + + // Send from a client. + try (Scope ignored = OperationContext.set(attr, valToSend)) { + grid(2).createCache(defaultCacheConfiguration()); + } + + assertNull(OperationContext.get(attr)); + + assertTrue(coordLatch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); + assertTrue(srvrLatch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); + assertTrue(clientLatch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); + } + /** */ private void doContextAwareExecutorServiceTest(ExecutorService pool) throws Exception { CountDownLatch poolUnblockedLatch = blockPool(pool); From 1395cafed69003dc49d235837e0d010c68d729a7 Mon Sep 17 00:00:00 2001 From: Vladimir Steshin Date: Wed, 17 Jun 2026 16:40:08 +0300 Subject: [PATCH 10/18] review fixes --- ...utedOperationContextAttributeRegistry.java | 15 +++++++----- .../internal/OperationContexMessage.java | 2 +- .../spi/discovery/tcp/TcpDiscoveryImpl.java | 24 ++++++++++++------- .../OperationContextAttributesTest.java | 8 ++----- 4 files changed, 28 insertions(+), 21 deletions(-) diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextAttributeRegistry.java b/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextAttributeRegistry.java index a6fb4d41de982..c347d486f6603 100644 --- a/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextAttributeRegistry.java +++ b/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextAttributeRegistry.java @@ -27,6 +27,9 @@ /** */ public class DistributedOperationContextAttributeRegistry { + /** */ + public static final byte MAX_DISTRIBUTED_ATTR_ID = 7; + /** */ private static final DistributedOperationContextAttributeRegistry INSTANCE = new DistributedOperationContextAttributeRegistry(); @@ -79,21 +82,21 @@ public Map collectContext(@Nullable Class checkValuesType) { } /** */ - public Scope restoreContext(int idBitmask, Object[] values) { + public Scope restoreContext(byte idBitmask, Object[] values) { if (F.isEmpty(values) || idBitmask == 0) return Scope.NOOP_SCOPE; - OperationContext.ContextUpdater updater = OperationContext.ContextUpdater.create(); + assert values.length <= MAX_DISTRIBUTED_ATTR_ID; - for (byte attrId = 0; attrId < OperationContextAttribute.MAX_ATTR_CNT; attrId++) { - assert attrId < Integer.SIZE; + OperationContext.ContextUpdater updater = OperationContext.ContextUpdater.create(); - int mask = 1 << attrId; + for (byte attrId = 0, idx = 0; attrId < Byte.SIZE; ++attrId) { + byte mask = (byte)(1 << attrId); if ((mask & idBitmask) == 0) continue; - updater.set((OperationContextAttribute)attributes.get(attrId), values[attrId]); + updater.set((OperationContextAttribute)attributes.get(attrId), values[idx++]); } return updater.apply(); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/OperationContexMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/OperationContexMessage.java index d45bf3a578602..4435ed7ec38d5 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/OperationContexMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/OperationContexMessage.java @@ -28,7 +28,7 @@ public class OperationContexMessage implements Message { /** Bitmask of effective attributes ids. */ @Order(1) - public int idBitmask; + public byte idBitmask; /** Empty constructor for serialization purposes. */ public OperationContexMessage() { diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryImpl.java index 097a9a496c7eb..849bc71c3b1ee 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryImpl.java @@ -45,7 +45,6 @@ import org.apache.ignite.internal.processors.tracing.NoopTracing; import org.apache.ignite.internal.processors.tracing.Tracing; import org.apache.ignite.internal.thread.context.DistributedOperationContextAttributeRegistry; -import org.apache.ignite.internal.thread.context.OperationContextAttribute; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.LT; import org.apache.ignite.internal.util.typedef.internal.U; @@ -456,22 +455,31 @@ public void processCacheMetricsMessage(TcpDiscoveryMetricsUpdateMessage msg, lon /** */ protected static void fillOperationContextAttributes(TcpDiscoveryAbstractMessage msg) { - DistributedOperationContextAttributeRegistry.instance().collectContext(Message.class).forEach((attrId, msgVal) -> { - assert attrId >= 0 && attrId < OperationContextAttribute.MAX_ATTR_CNT; + Map attrs = DistributedOperationContextAttributeRegistry.instance().collectContext(Message.class); + + if(F.isEmpty(attrs)) + return; + + int idx = 0; + + for (Map.Entry e : attrs.entrySet()) { + byte attrId = e.getKey(); + Message msgVal = e.getValue(); + + assert attrId >= 0 && attrId <= DistributedOperationContextAttributeRegistry.MAX_DISTRIBUTED_ATTR_ID; if (msg.opCtxMsg == null) { msg.opCtxMsg = new OperationContexMessage(); - - msg.opCtxMsg.vals = new Message[OperationContextAttribute.MAX_ATTR_CNT]; + msg.opCtxMsg.vals = new Message[attrs.size()]; } - int mask = 1 << attrId; + byte mask = (byte)(1 << attrId); assert (msg.opCtxMsg.idBitmask & mask) == 0; msg.opCtxMsg.idBitmask |= mask; - msg.opCtxMsg.vals[attrId] = msgVal; - }); + msg.opCtxMsg.vals[idx++] = msgVal; + } } /** diff --git a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java index 19b3a5d39a636..20125f1773c23 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java @@ -821,7 +821,7 @@ public void testContextAwareDelayQueue() throws Exception { /** */ @Test public void testSendAttributesByDiscovery() throws Exception { - byte attrId = (byte)(OperationContextAttribute.MAX_ATTR_CNT - 1); + byte attrId = DistributedOperationContextAttributeRegistry.MAX_DISTRIBUTED_ATTR_ID; InetSocketAddressMessage dfltAttrVal = new InetSocketAddressMessage(InetAddress.getLoopbackAddress(), 80); @@ -866,10 +866,9 @@ else if (grid(i0).localNode().order() == 1) } assertFalse(valToSend.equals(dfltAttrVal)); - assertNull(OperationContext.get(attr)); - // Send from a coordinator. + // Send from the coordinator. try (Scope ignored = OperationContext.set(attr, valToSend)) { grid(0).createCache(defaultCacheConfiguration()); } @@ -877,7 +876,6 @@ else if (grid(i0).localNode().order() == 1) assertTrue(waitForCondition(() -> coordLatch.getCount() == 2, getTestTimeout())); assertTrue(waitForCondition(() -> srvrLatch.getCount() == 2, getTestTimeout())); assertTrue(waitForCondition(() -> clientLatch.getCount() == 2, getTestTimeout())); - assertNull(OperationContext.get(attr)); // Send from a server. @@ -888,7 +886,6 @@ else if (grid(i0).localNode().order() == 1) assertTrue(waitForCondition(() -> coordLatch.getCount() == 1, getTestTimeout())); assertTrue(waitForCondition(() -> srvrLatch.getCount() == 1, getTestTimeout())); assertTrue(waitForCondition(() -> clientLatch.getCount() == 1, getTestTimeout())); - assertNull(OperationContext.get(attr)); // Send from a client. @@ -897,7 +894,6 @@ else if (grid(i0).localNode().order() == 1) } assertNull(OperationContext.get(attr)); - assertTrue(coordLatch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); assertTrue(srvrLatch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); assertTrue(clientLatch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); From d0f8b329b4c13c8848c6b74fc343de05a37dceab Mon Sep 17 00:00:00 2001 From: Vladimir Steshin Date: Wed, 17 Jun 2026 17:30:47 +0300 Subject: [PATCH 11/18] raw --- .../OperationContextAttributesTest.java | 65 ++++++++++++++++++- 1 file changed, 63 insertions(+), 2 deletions(-) diff --git a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java index 20125f1773c23..f5d208487cf25 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java @@ -22,6 +22,7 @@ import java.util.Collections; import java.util.LinkedList; import java.util.List; +import java.util.UUID; import java.util.concurrent.Callable; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; @@ -38,8 +39,11 @@ import java.util.function.Supplier; import org.apache.ignite.IgniteException; import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.internal.GridTopic; import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.managers.communication.GridIoPolicy; +import org.apache.ignite.internal.managers.communication.GridMessageListener; +import org.apache.ignite.internal.managers.communication.IgniteIoTestMessage; import org.apache.ignite.internal.managers.discovery.CustomEventListener; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.DynamicCacheChangeBatch; @@ -849,9 +853,7 @@ public void testSendAttributesByDiscovery() throws Exception { InetSocketAddressMessage receivedVal = OperationContext.get(attr); assertNotNull(receivedVal); - assertFalse(dfltAttrVal.port() == receivedVal.port()); - assertEquals(receivedVal.port(), valToSend.port()); assertEquals(receivedVal.address(), valToSend.address()); @@ -899,6 +901,65 @@ else if (grid(i0).localNode().order() == 1) assertTrue(clientLatch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); } + /** */ + @Test + public void testSendAttributesByCommunication() throws Exception { + byte attrId = DistributedOperationContextAttributeRegistry.MAX_DISTRIBUTED_ATTR_ID; + + InetSocketAddressMessage dfltAttrVal = new InetSocketAddressMessage(InetAddress.getLoopbackAddress(), 80); + + OperationContextAttribute attr = OperationContextAttribute.newInstance(); + + DistributedOperationContextAttributeRegistry.instance().register(attrId, attr); + + startGrids(2); + startClientGrid(2); + + CountDownLatch coordLatch = new CountDownLatch(2); + CountDownLatch srvrLatch = new CountDownLatch(2); + CountDownLatch clientLatch = new CountDownLatch(2); + + InetSocketAddressMessage attrValToSend = new InetSocketAddressMessage(dfltAttrVal.address(), 443); + + for (int i = 0; i < G.allGrids().size(); ++i) { + int i0 = i; + + grid(i).context().io().addMessageListener(GridTopic.TOPIC_IO_TEST, new GridMessageListener() { + @Override public void onMessage(UUID nodeId, Object msg, byte plc) { + if(msg instanceof IgniteIoTestMessage) { + InetSocketAddressMessage receivedVal = OperationContext.get(attr); + + assertNotNull(receivedVal); + assertFalse(dfltAttrVal.port() == receivedVal.port()); + assertEquals(receivedVal.port(), attrValToSend.port()); + assertEquals(receivedVal.address(), attrValToSend.address()); + + if (grid(i0).localNode().isClient()) + clientLatch.countDown(); + else if (grid(i0).localNode().order() == 1) + coordLatch.countDown(); + else + srvrLatch.countDown(); + } + } + }); + } + + assertFalse(attrValToSend.equals(dfltAttrVal)); + assertNull(OperationContext.get(attr)); + + // Send from the coordinator. + try (Scope ignored = OperationContext.set(attr, attrValToSend)) { + grid(0).context().io().sendIoTest(grid(1).localNode(), null, false); + grid(0).context().io().sendIoTest(grid(1).localNode(), null, true); + } + + assertTrue(waitForCondition(() -> coordLatch.getCount() == 2, getTestTimeout())); + assertTrue(waitForCondition(() -> srvrLatch.getCount() == 2, getTestTimeout())); + assertTrue(waitForCondition(() -> clientLatch.getCount() == 2, getTestTimeout())); + assertNull(OperationContext.get(attr)); + } + /** */ private void doContextAwareExecutorServiceTest(ExecutorService pool) throws Exception { CountDownLatch poolUnblockedLatch = blockPool(pool); From 9560c0dd77d371b29d9e4824548db50b418c048a Mon Sep 17 00:00:00 2001 From: Vladimir Steshin Date: Wed, 17 Jun 2026 19:29:28 +0300 Subject: [PATCH 12/18] impl --- .../ignite/internal/CoreMessagesProvider.java | 2 +- .../internal/OperationContexMessage.java | 31 +++++++++++++++++ .../managers/communication/GridIoManager.java | 28 +++++++++++++--- .../managers/communication/GridIoMessage.java | 6 ++++ .../util/nio/GridNioRecoveryDescriptor.java | 2 +- .../tcp/TcpCommunicationSpi.java | 4 +-- .../ignite/spi/discovery/tcp/ClientImpl.java | 5 ++- .../ignite/spi/discovery/tcp/ServerImpl.java | 7 ++-- .../spi/discovery/tcp/TcpDiscoveryImpl.java | 32 ------------------ .../codegen/MessageProcessorTest.java | 10 ++++++ .../OperationContextAttributesTest.java | 33 ++++++++++++++++--- 11 files changed, 112 insertions(+), 48 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java b/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java index 4d4caff06d126..f2a37b3e336f0 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java @@ -666,7 +666,7 @@ public CoreMessagesProvider(Marshaller dfltMarsh, Marshaller schemaAwareMarsh, C withNoSchema(PartitionHashRecord.class); withNoSchema(TransactionsHashRecord.class); - // [13400 - 13600]: Operation context messages. + // [13400 - 13500]: Operation context messages. msgIdx = 13400; withNoSchema(OperationContexMessage.class); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/OperationContexMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/OperationContexMessage.java index 4435ed7ec38d5..5c0e1d9fe1692 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/OperationContexMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/OperationContexMessage.java @@ -17,8 +17,11 @@ package org.apache.ignite.internal; +import java.util.Map; import org.apache.ignite.internal.thread.context.OperationContext; +import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.plugin.extensions.communication.Message; +import org.jetbrains.annotations.Nullable; /** ransport for {@link OperationContext} attributes. */ public class OperationContexMessage implements Message { @@ -34,4 +37,32 @@ public class OperationContexMessage implements Message { public OperationContexMessage() { // No-op. } + + /** */ + public static @Nullable OperationContexMessage instance(Map attrs) { + if (F.isEmpty(attrs)) + return null; + + OperationContexMessage res = new OperationContexMessage(); + + res.vals = new Message[attrs.size()]; + + int idx = 0; + + for (Map.Entry e : attrs.entrySet()) { + byte attrId = e.getKey(); + Message msgVal = e.getValue(); + + assert attrId >= 0 && attrId < Byte.SIZE; + + byte mask = (byte)(1 << attrId); + + assert (res.idBitmask & mask) == 0; + + res.idBitmask |= mask; + res.vals[idx++] = msgVal; + } + + return res; + } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java index 3acf503561ad8..fe93bd978087e 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java @@ -83,6 +83,7 @@ import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.IgniteKernal; import org.apache.ignite.internal.NodeStoppingException; +import org.apache.ignite.internal.OperationContexMessage; import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException; import org.apache.ignite.internal.direct.DirectMessageReader; import org.apache.ignite.internal.direct.DirectMessageWriter; @@ -102,6 +103,7 @@ import org.apache.ignite.internal.processors.tracing.MTC.TraceSurroundings; import org.apache.ignite.internal.processors.tracing.Span; import org.apache.ignite.internal.processors.tracing.SpanTags; +import org.apache.ignite.internal.thread.context.DistributedOperationContextAttributeRegistry; import org.apache.ignite.internal.thread.context.Scope; import org.apache.ignite.internal.util.GridBoundedConcurrentLinkedHashSet; import org.apache.ignite.internal.util.IgniteUtils; @@ -455,10 +457,20 @@ public void resetMetrics() { ioMetric.register(RCVD_BYTES_CNT, spi::getReceivedBytesCount, "Received bytes count."); - getSpi().setListener(commLsnr = new CommunicationListenerEx() { + getSpi().setListener(commLsnr = new CommunicationListenerEx<>() { @Override public void onMessage(UUID nodeId, Object msg, IgniteRunnable msgC) { try { - onMessage0(nodeId, (GridIoMessage)msg, msgC); + GridIoMessage msg0 = (GridIoMessage)msg; + + if (!locNodeId.equals(nodeId) && msg0.opCtxMsg != null) { + OperationContexMessage cm = msg0.opCtxMsg; + + try (Scope ignored = DistributedOperationContextAttributeRegistry.instance().restoreContext(cm.idBitmask, cm.vals)) { + onMessage0(nodeId, msg0, msgC); + } + } + else + onMessage0(nodeId, msg0, msgC); } catch (ClassCastException ignored) { U.error(log, "Communication manager received message of unknown type (will ignore): " + @@ -2037,16 +2049,22 @@ private long getInverseConnectionWaitTimeout() { long timeout, boolean skipOnTimeout ) { + GridIoMessage res; + if (ctx.security().enabled()) { UUID secSubjId = null; if (!ctx.security().isDefaultContext()) secSubjId = ctx.security().securityContext().subject().id(); - return new GridIoSecurityAwareMessage(secSubjId, plc, topic, msg, ordered, timeout, skipOnTimeout); - } + res = new GridIoSecurityAwareMessage(secSubjId, plc, topic, msg, ordered, timeout, skipOnTimeout); + } else + res = new GridIoMessage(plc, topic, msg, ordered, timeout, skipOnTimeout); + + res.opCtxMsg = OperationContexMessage.instance(DistributedOperationContextAttributeRegistry.instance() + .collectContext(Message.class)); - return new GridIoMessage(plc, topic, msg, ordered, timeout, skipOnTimeout); + return res; } /** diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessage.java index 8cc6c106cf22e..f6a099481ac2b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessage.java @@ -19,6 +19,7 @@ import org.apache.ignite.internal.ExecutorAwareMessage; import org.apache.ignite.internal.GridTopicMessage; +import org.apache.ignite.internal.OperationContexMessage; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.cache.GridCacheMessage; import org.apache.ignite.internal.processors.datastreamer.DataStreamerRequest; @@ -64,6 +65,11 @@ public class GridIoMessage implements Message, SpanTransport { @Order(6) byte[] span; + /** Effective operation context attributes. */ + @Order(7) + @GridToStringInclude + public @Nullable OperationContexMessage opCtxMsg; + /** * Default constructor. */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/nio/GridNioRecoveryDescriptor.java b/modules/core/src/main/java/org/apache/ignite/internal/util/nio/GridNioRecoveryDescriptor.java index 1cedb7d800ee4..06afe2292a7aa 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/util/nio/GridNioRecoveryDescriptor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/util/nio/GridNioRecoveryDescriptor.java @@ -108,7 +108,7 @@ public GridNioRecoveryDescriptor( ClusterNode node, IgniteLogger log ) { - assert !node.isLocal() : node; + // assert !node.isLocal() : "Nio to local node [" + node + "]."; assert queueLimit > 0; msgReqs = new ArrayDeque<>(queueLimit); diff --git a/modules/core/src/main/java/org/apache/ignite/spi/communication/tcp/TcpCommunicationSpi.java b/modules/core/src/main/java/org/apache/ignite/spi/communication/tcp/TcpCommunicationSpi.java index 3078e20a0e9fc..f9ab18727eada 100755 --- a/modules/core/src/main/java/org/apache/ignite/spi/communication/tcp/TcpCommunicationSpi.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/communication/tcp/TcpCommunicationSpi.java @@ -616,7 +616,7 @@ private void dumpInfo(StringBuilder sb, UUID dstNodeId) { ctxInitLatch, client, igniteExSupplier, - new CommunicationListener() { + new CommunicationListener<>() { @Override public void onMessage(UUID nodeId, Message msg, IgniteRunnable msgC) { notifyListener(nodeId, msg, msgC); } @@ -651,7 +651,7 @@ private void dumpInfo(StringBuilder sb, UUID dstNodeId) { getWorkersRegistry(ignite), ignite instanceof IgniteEx ? ((IgniteEx)ignite).context().metric() : null, this::createTcpClient, - new CommunicationListenerEx() { + new CommunicationListenerEx<>() { @Override public void onMessage(UUID nodeId, Message msg, IgniteRunnable msgC) { notifyListener(nodeId, msg, msgC); } diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java index ce2911a83392e..3cdb322951d3e 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java @@ -64,6 +64,7 @@ import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.IgniteInterruptedCheckedException; import org.apache.ignite.internal.IgniteNodeAttributes; +import org.apache.ignite.internal.OperationContexMessage; import org.apache.ignite.internal.managers.discovery.DiscoveryServerOnlyCustomMessage; import org.apache.ignite.internal.processors.tracing.Span; import org.apache.ignite.internal.processors.tracing.SpanTags; @@ -83,6 +84,7 @@ import org.apache.ignite.internal.worker.WorkersRegistry; import org.apache.ignite.lang.IgniteInClosure; import org.apache.ignite.lang.IgniteUuid; +import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.spi.IgniteSpiAdapter; import org.apache.ignite.spi.IgniteSpiContext; import org.apache.ignite.spi.IgniteSpiException; @@ -1312,7 +1314,8 @@ private class SocketWriter extends IgniteSpiThread { * @param msg Message. */ private void sendMessage(TcpDiscoveryAbstractMessage msg) { - fillOperationContextAttributes(msg); + msg.opCtxMsg = OperationContexMessage.instance(DistributedOperationContextAttributeRegistry.instance() + .collectContext(Message.class)); synchronized (mux) { queue.add(msg); diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java index e27de173ec6c2..3d87de1a320f7 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java @@ -121,6 +121,7 @@ import org.apache.ignite.lang.IgniteInClosure; import org.apache.ignite.lang.IgniteProductVersion; import org.apache.ignite.lang.IgniteUuid; +import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.plugin.security.SecurityCredentials; import org.apache.ignite.spi.IgniteNodeValidationResult; import org.apache.ignite.spi.IgniteSpiContext; @@ -3049,8 +3050,10 @@ void addMessage(TcpDiscoveryAbstractMessage msg, boolean ignoreHighPriority, boo return; } - if (!fromSocket) - fillOperationContextAttributes(msg); + if (!fromSocket) { + msg.opCtxMsg = OperationContexMessage.instance(DistributedOperationContextAttributeRegistry.instance() + .collectContext(Message.class)); + } if (msg instanceof TraceableMessage) { TraceableMessage tMsg = (TraceableMessage)msg; diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryImpl.java index 849bc71c3b1ee..789f3d0adb107 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryImpl.java @@ -37,18 +37,15 @@ import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.internal.ClusterMetricsSnapshot; import org.apache.ignite.internal.IgniteEx; -import org.apache.ignite.internal.OperationContexMessage; import org.apache.ignite.internal.processors.cache.CacheMetricsSnapshot; import org.apache.ignite.internal.processors.cluster.CacheMetricsMessage; import org.apache.ignite.internal.processors.cluster.NodeFullMetricsMessage; import org.apache.ignite.internal.processors.cluster.NodeMetricsMessage; import org.apache.ignite.internal.processors.tracing.NoopTracing; import org.apache.ignite.internal.processors.tracing.Tracing; -import org.apache.ignite.internal.thread.context.DistributedOperationContextAttributeRegistry; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.LT; import org.apache.ignite.internal.util.typedef.internal.U; -import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.spi.IgniteSpiContext; import org.apache.ignite.spi.IgniteSpiException; import org.apache.ignite.spi.IgniteSpiThread; @@ -453,35 +450,6 @@ public void processCacheMetricsMessage(TcpDiscoveryMetricsUpdateMessage msg, lon } } - /** */ - protected static void fillOperationContextAttributes(TcpDiscoveryAbstractMessage msg) { - Map attrs = DistributedOperationContextAttributeRegistry.instance().collectContext(Message.class); - - if(F.isEmpty(attrs)) - return; - - int idx = 0; - - for (Map.Entry e : attrs.entrySet()) { - byte attrId = e.getKey(); - Message msgVal = e.getValue(); - - assert attrId >= 0 && attrId <= DistributedOperationContextAttributeRegistry.MAX_DISTRIBUTED_ATTR_ID; - - if (msg.opCtxMsg == null) { - msg.opCtxMsg = new OperationContexMessage(); - msg.opCtxMsg.vals = new Message[attrs.size()]; - } - - byte mask = (byte)(1 << attrId); - - assert (msg.opCtxMsg.idBitmask & mask) == 0; - - msg.opCtxMsg.idBitmask |= mask; - msg.opCtxMsg.vals[idx++] = msgVal; - } - } - /** * @param addrs Addresses. */ diff --git a/modules/core/src/test/java/org/apache/ignite/internal/codegen/MessageProcessorTest.java b/modules/core/src/test/java/org/apache/ignite/internal/codegen/MessageProcessorTest.java index 9495d39125ff7..e1e2e38dbbf5c 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/codegen/MessageProcessorTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/codegen/MessageProcessorTest.java @@ -33,8 +33,12 @@ import org.apache.ignite.cache.QueryIndex; import org.apache.ignite.cache.QueryIndexType; import org.apache.ignite.internal.MessageProcessor; +import org.apache.ignite.internal.Order; import org.apache.ignite.internal.cache.query.QueryIndexMessage; import org.apache.ignite.internal.util.CommonUtils; +import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.lang.IgniteUuid; +import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.plugin.extensions.communication.mappers.DefaultEnumMapper; import org.apache.ignite.transactions.TransactionIsolation; import org.junit.Test; @@ -359,7 +363,13 @@ static Compilation compile(Processor proc, String... srcFiles) { for (String srcFile: srcFiles) input.add(javaFile(srcFile)); + File igniteCoreJar = jarForClass(Message.class); + File igniteCodegenJar = jarForClass(Order.class); + File igniteBinaryApiJar = jarForClass(IgniteUuid.class); + File igniteCommonsJar = jarForClass(CommonUtils.class); + return Compiler.javac() + .withClasspath(F.asList(igniteCoreJar, igniteCodegenJar, igniteBinaryApiJar, igniteCommonsJar)) .withProcessors(proc) .compile(input); } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java index f5d208487cf25..1646bcff0ead9 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java @@ -916,7 +916,7 @@ public void testSendAttributesByCommunication() throws Exception { startClientGrid(2); CountDownLatch coordLatch = new CountDownLatch(2); - CountDownLatch srvrLatch = new CountDownLatch(2); + CountDownLatch srvrLatch = new CountDownLatch(4); CountDownLatch clientLatch = new CountDownLatch(2); InetSocketAddressMessage attrValToSend = new InetSocketAddressMessage(dfltAttrVal.address(), 443); @@ -948,15 +948,40 @@ else if (grid(i0).localNode().order() == 1) assertFalse(attrValToSend.equals(dfltAttrVal)); assertNull(OperationContext.get(attr)); - // Send from the coordinator. + // From the coordinator to a server. try (Scope ignored = OperationContext.set(attr, attrValToSend)) { grid(0).context().io().sendIoTest(grid(1).localNode(), null, false); grid(0).context().io().sendIoTest(grid(1).localNode(), null, true); } assertTrue(waitForCondition(() -> coordLatch.getCount() == 2, getTestTimeout())); - assertTrue(waitForCondition(() -> srvrLatch.getCount() == 2, getTestTimeout())); - assertTrue(waitForCondition(() -> clientLatch.getCount() == 2, getTestTimeout())); + assertNull(OperationContext.get(attr)); + + // From a server to the coordinator. + try (Scope ignored = OperationContext.set(attr, attrValToSend)) { + grid(1).context().io().sendIoTest(grid(0).localNode(), null, false); + grid(1).context().io().sendIoTest(grid(0).localNode(), null, true); + } + + assertTrue(coordLatch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); + assertNull(OperationContext.get(attr)); + + // From a client to a server. + try (Scope ignored = OperationContext.set(attr, attrValToSend)) { + grid(2).context().io().sendIoTest(grid(1).localNode(), null, false); + grid(2).context().io().sendIoTest(grid(1).localNode(), null, true); + } + + assertTrue(srvrLatch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); + assertNull(OperationContext.get(attr)); + + // From a server to a client. + try (Scope ignored = OperationContext.set(attr, attrValToSend)) { + grid(1).context().io().sendIoTest(grid(2).localNode(), null, false); + grid(1).context().io().sendIoTest(grid(2).localNode(), null, true); + } + + assertTrue(clientLatch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); assertNull(OperationContext.get(attr)); } From 92bbdb429f548cfe4aea83fee657731b8ab6ae89 Mon Sep 17 00:00:00 2001 From: Vladimir Steshin Date: Wed, 17 Jun 2026 20:09:39 +0300 Subject: [PATCH 13/18] improvement --- .../util/nio/GridNioRecoveryDescriptor.java | 2 +- .../OperationContextAttributesTest.java | 27 +++++++++++++------ 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/nio/GridNioRecoveryDescriptor.java b/modules/core/src/main/java/org/apache/ignite/internal/util/nio/GridNioRecoveryDescriptor.java index 06afe2292a7aa..1cedb7d800ee4 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/util/nio/GridNioRecoveryDescriptor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/util/nio/GridNioRecoveryDescriptor.java @@ -108,7 +108,7 @@ public GridNioRecoveryDescriptor( ClusterNode node, IgniteLogger log ) { - // assert !node.isLocal() : "Nio to local node [" + node + "]."; + assert !node.isLocal() : node; assert queueLimit > 0; msgReqs = new ArrayDeque<>(queueLimit); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java index 1646bcff0ead9..6e91ce9394da7 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java @@ -41,6 +41,7 @@ import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.internal.GridTopic; import org.apache.ignite.internal.IgniteInternalFuture; +import org.apache.ignite.internal.managers.communication.GridIoManager; import org.apache.ignite.internal.managers.communication.GridIoPolicy; import org.apache.ignite.internal.managers.communication.GridMessageListener; import org.apache.ignite.internal.managers.communication.IgniteIoTestMessage; @@ -950,8 +951,8 @@ else if (grid(i0).localNode().order() == 1) // From the coordinator to a server. try (Scope ignored = OperationContext.set(attr, attrValToSend)) { - grid(0).context().io().sendIoTest(grid(1).localNode(), null, false); - grid(0).context().io().sendIoTest(grid(1).localNode(), null, true); + io(0).sendIoTest(node(1), null, false); + io(0).sendIoTest(node(1), null, true); } assertTrue(waitForCondition(() -> coordLatch.getCount() == 2, getTestTimeout())); @@ -959,8 +960,8 @@ else if (grid(i0).localNode().order() == 1) // From a server to the coordinator. try (Scope ignored = OperationContext.set(attr, attrValToSend)) { - grid(1).context().io().sendIoTest(grid(0).localNode(), null, false); - grid(1).context().io().sendIoTest(grid(0).localNode(), null, true); + io(1).sendIoTest(node(0), null, false); + io(1).sendIoTest(node(0), null, true); } assertTrue(coordLatch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); @@ -968,8 +969,8 @@ else if (grid(i0).localNode().order() == 1) // From a client to a server. try (Scope ignored = OperationContext.set(attr, attrValToSend)) { - grid(2).context().io().sendIoTest(grid(1).localNode(), null, false); - grid(2).context().io().sendIoTest(grid(1).localNode(), null, true); + io(2).sendIoTest(node(1), null, false); + io(2).sendIoTest(node(1), null, true); } assertTrue(srvrLatch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); @@ -977,14 +978,24 @@ else if (grid(i0).localNode().order() == 1) // From a server to a client. try (Scope ignored = OperationContext.set(attr, attrValToSend)) { - grid(1).context().io().sendIoTest(grid(2).localNode(), null, false); - grid(1).context().io().sendIoTest(grid(2).localNode(), null, true); + io(1).sendIoTest(node(2), null, false); + io(1).sendIoTest(node(2), null, true); } assertTrue(clientLatch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); assertNull(OperationContext.get(attr)); } + /** @return a {@link ClusterNode} with {@link ClusterNode#isLocal()} == {@code false} to avoid some asserts/checks. */ + private ClusterNode node(int nodeIdx) { + return grid(0).cluster().node(grid(nodeIdx).localNode().id()); + } + + /** */ + private GridIoManager io(int nodeIdx) { + return grid(nodeIdx).context().io(); + } + /** */ private void doContextAwareExecutorServiceTest(ExecutorService pool) throws Exception { CountDownLatch poolUnblockedLatch = blockPool(pool); From 8ef05111f75bfe152ee3ae5d77b6d741ed254ec6 Mon Sep 17 00:00:00 2001 From: Vladimir Steshin Date: Wed, 17 Jun 2026 20:16:01 +0300 Subject: [PATCH 14/18] checkstyle --- .../internal/managers/communication/GridIoManager.java | 8 ++++---- .../thread/context/OperationContextAttributesTest.java | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java index fe93bd978087e..043bb4df1b5e2 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java @@ -463,9 +463,8 @@ public void resetMetrics() { GridIoMessage msg0 = (GridIoMessage)msg; if (!locNodeId.equals(nodeId) && msg0.opCtxMsg != null) { - OperationContexMessage cm = msg0.opCtxMsg; - - try (Scope ignored = DistributedOperationContextAttributeRegistry.instance().restoreContext(cm.idBitmask, cm.vals)) { + try (Scope ignored = DistributedOperationContextAttributeRegistry.instance() + .restoreContext(msg0.opCtxMsg.idBitmask, msg0.opCtxMsg.vals)) { onMessage0(nodeId, msg0, msgC); } } @@ -2058,7 +2057,8 @@ private long getInverseConnectionWaitTimeout() { secSubjId = ctx.security().securityContext().subject().id(); res = new GridIoSecurityAwareMessage(secSubjId, plc, topic, msg, ordered, timeout, skipOnTimeout); - } else + } + else res = new GridIoMessage(plc, topic, msg, ordered, timeout, skipOnTimeout); res.opCtxMsg = OperationContexMessage.instance(DistributedOperationContextAttributeRegistry.instance() diff --git a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java index 6e91ce9394da7..477af4b633abd 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java @@ -927,7 +927,7 @@ public void testSendAttributesByCommunication() throws Exception { grid(i).context().io().addMessageListener(GridTopic.TOPIC_IO_TEST, new GridMessageListener() { @Override public void onMessage(UUID nodeId, Object msg, byte plc) { - if(msg instanceof IgniteIoTestMessage) { + if (msg instanceof IgniteIoTestMessage) { InetSocketAddressMessage receivedVal = OperationContext.get(attr); assertNotNull(receivedVal); From 39942afe5dfa38e46f7b26c67e890e9b395f1003 Mon Sep 17 00:00:00 2001 From: Vladimir Steshin Date: Wed, 17 Jun 2026 20:21:59 +0300 Subject: [PATCH 15/18] minority --- .../java/org/apache/ignite/internal/OperationContexMessage.java | 2 +- .../ignite/internal/managers/communication/GridIoManager.java | 2 +- .../java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java | 2 +- .../java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/OperationContexMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/OperationContexMessage.java index 5c0e1d9fe1692..fd047389b54e6 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/OperationContexMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/OperationContexMessage.java @@ -39,7 +39,7 @@ public OperationContexMessage() { } /** */ - public static @Nullable OperationContexMessage instance(Map attrs) { + public static @Nullable OperationContexMessage create(Map attrs) { if (F.isEmpty(attrs)) return null; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java index 043bb4df1b5e2..c99b3ce8e8e57 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java @@ -2061,7 +2061,7 @@ private long getInverseConnectionWaitTimeout() { else res = new GridIoMessage(plc, topic, msg, ordered, timeout, skipOnTimeout); - res.opCtxMsg = OperationContexMessage.instance(DistributedOperationContextAttributeRegistry.instance() + res.opCtxMsg = OperationContexMessage.create(DistributedOperationContextAttributeRegistry.instance() .collectContext(Message.class)); return res; diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java index 3cdb322951d3e..cfc1784304d28 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java @@ -1314,7 +1314,7 @@ private class SocketWriter extends IgniteSpiThread { * @param msg Message. */ private void sendMessage(TcpDiscoveryAbstractMessage msg) { - msg.opCtxMsg = OperationContexMessage.instance(DistributedOperationContextAttributeRegistry.instance() + msg.opCtxMsg = OperationContexMessage.create(DistributedOperationContextAttributeRegistry.instance() .collectContext(Message.class)); synchronized (mux) { diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java index 3d87de1a320f7..c7f1875b74ce9 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java @@ -3051,7 +3051,7 @@ void addMessage(TcpDiscoveryAbstractMessage msg, boolean ignoreHighPriority, boo } if (!fromSocket) { - msg.opCtxMsg = OperationContexMessage.instance(DistributedOperationContextAttributeRegistry.instance() + msg.opCtxMsg = OperationContexMessage.create(DistributedOperationContextAttributeRegistry.instance() .collectContext(Message.class)); } From 08f3b7a0e672e8deb61b4e9aaba4f5e053c687bf Mon Sep 17 00:00:00 2001 From: Vladimir Steshin Date: Thu, 18 Jun 2026 20:47:07 +0300 Subject: [PATCH 16/18] fix --- ...utedOperationContextAttributeRegistry.java | 104 ---------------- .../ignite/internal/CoreMessagesProvider.java | 2 +- ...istributedOperationAttributesMessage.java} | 40 +----- .../managers/communication/GridIoManager.java | 15 +-- .../managers/communication/GridIoMessage.java | 4 +- .../DistributedOperationAttributeManager.java | 117 ++++++++++++++++++ .../ignite/spi/discovery/tcp/ClientImpl.java | 14 +-- .../ignite/spi/discovery/tcp/ServerImpl.java | 21 +--- .../messages/TcpDiscoveryAbstractMessage.java | 4 +- .../OperationContextAttributesTest.java | 27 ++-- 10 files changed, 147 insertions(+), 201 deletions(-) delete mode 100644 modules/commons/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextAttributeRegistry.java rename modules/core/src/main/java/org/apache/ignite/internal/{OperationContexMessage.java => DistributedOperationAttributesMessage.java} (55%) create mode 100644 modules/core/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationAttributeManager.java diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextAttributeRegistry.java b/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextAttributeRegistry.java deleted file mode 100644 index c347d486f6603..0000000000000 --- a/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextAttributeRegistry.java +++ /dev/null @@ -1,104 +0,0 @@ -/* - * Licensed to the Apache Software Foundation (ASF) under one or more - * contributor license agreements. See the NOTICE file distributed with - * this work for additional information regarding copyright ownership. - * The ASF licenses this file to You under the Apache License, Version 2.0 - * (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.apache.ignite.internal.thread.context; - -import java.util.Collections; -import java.util.HashMap; -import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; -import org.apache.ignite.IgniteException; -import org.apache.ignite.internal.util.typedef.F; -import org.jetbrains.annotations.Nullable; - -/** */ -public class DistributedOperationContextAttributeRegistry { - /** */ - public static final byte MAX_DISTRIBUTED_ATTR_ID = 7; - - /** */ - private static final DistributedOperationContextAttributeRegistry INSTANCE = new DistributedOperationContextAttributeRegistry(); - - /** Attributes by their id. */ - private final Map> attributes = new ConcurrentHashMap<>(); - - /** */ - public static DistributedOperationContextAttributeRegistry instance() { - return INSTANCE; - } - - /** */ - public void register(byte id, OperationContextAttribute attr) { - assert id >= 0; - - if (attributes.size() == OperationContextAttribute.MAX_ATTR_CNT) - throw new IgniteException("Maximum number of attributes is exceeded [" + OperationContextAttribute.MAX_ATTR_CNT + "]."); - - if (attributes.putIfAbsent(id, attr) != null) - throw new IgniteException("Duplicated attribute id: " + id); - } - - /** - * TODO : Declare distributed attributes as 'extends Message' after https://issues.apache.org/jira/browse/IGNITE-28766 - * - * @return Values for all registered operation context attributes. - */ - public Map collectContext(@Nullable Class checkValuesType) { - Map res = Collections.emptyMap(); - - for (Map.Entry> e : attributes.entrySet()) { - OperationContextAttribute attr = e.getValue(); - - Object curVal = OperationContext.get(attr); - - if (curVal != null && checkValuesType != null && !checkValuesType.isAssignableFrom(curVal.getClass())) { - throw new IgniteException("To distribute operation context attributes they have to be a " - + checkValuesType.getSimpleName()); - } - - if (!Objects.equals(attr.initialValue(), curVal)) { - if (res == Collections.EMPTY_MAP) - res = new HashMap<>(attributes.size(), 1.0f); - - res.put(e.getKey(), (T)curVal); - } - } - - return res; - } - - /** */ - public Scope restoreContext(byte idBitmask, Object[] values) { - if (F.isEmpty(values) || idBitmask == 0) - return Scope.NOOP_SCOPE; - - assert values.length <= MAX_DISTRIBUTED_ATTR_ID; - - OperationContext.ContextUpdater updater = OperationContext.ContextUpdater.create(); - - for (byte attrId = 0, idx = 0; attrId < Byte.SIZE; ++attrId) { - byte mask = (byte)(1 << attrId); - - if ((mask & idBitmask) == 0) - continue; - - updater.set((OperationContextAttribute)attributes.get(attrId), values[idx++]); - } - - return updater.apply(); - } -} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java b/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java index f2a37b3e336f0..19fb738b9dd2f 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java @@ -668,7 +668,7 @@ public CoreMessagesProvider(Marshaller dfltMarsh, Marshaller schemaAwareMarsh, C // [13400 - 13500]: Operation context messages. msgIdx = 13400; - withNoSchema(OperationContexMessage.class); + withNoSchema(DistributedOperationAttributesMessage.class); assert msgIdx <= MAX_MESSAGE_ID; } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/OperationContexMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/DistributedOperationAttributesMessage.java similarity index 55% rename from modules/core/src/main/java/org/apache/ignite/internal/OperationContexMessage.java rename to modules/core/src/main/java/org/apache/ignite/internal/DistributedOperationAttributesMessage.java index fd047389b54e6..32b106f649903 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/OperationContexMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/DistributedOperationAttributesMessage.java @@ -17,52 +17,22 @@ package org.apache.ignite.internal; -import java.util.Map; +import java.util.List; import org.apache.ignite.internal.thread.context.OperationContext; -import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.plugin.extensions.communication.Message; -import org.jetbrains.annotations.Nullable; -/** ransport for {@link OperationContext} attributes. */ -public class OperationContexMessage implements Message { +/** Transport for {@link OperationContext} distibuted attributes. */ +public class DistributedOperationAttributesMessage implements Message { /** Values of operation context attributes. */ @Order(0) - public Message[] vals; + public List vals; /** Bitmask of effective attributes ids. */ @Order(1) public byte idBitmask; /** Empty constructor for serialization purposes. */ - public OperationContexMessage() { + public DistributedOperationAttributesMessage() { // No-op. } - - /** */ - public static @Nullable OperationContexMessage create(Map attrs) { - if (F.isEmpty(attrs)) - return null; - - OperationContexMessage res = new OperationContexMessage(); - - res.vals = new Message[attrs.size()]; - - int idx = 0; - - for (Map.Entry e : attrs.entrySet()) { - byte attrId = e.getKey(); - Message msgVal = e.getValue(); - - assert attrId >= 0 && attrId < Byte.SIZE; - - byte mask = (byte)(1 << attrId); - - assert (res.idBitmask & mask) == 0; - - res.idBitmask |= mask; - res.vals[idx++] = msgVal; - } - - return res; - } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java index c99b3ce8e8e57..2d74d2260de80 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java @@ -83,7 +83,6 @@ import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.IgniteKernal; import org.apache.ignite.internal.NodeStoppingException; -import org.apache.ignite.internal.OperationContexMessage; import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException; import org.apache.ignite.internal.direct.DirectMessageReader; import org.apache.ignite.internal.direct.DirectMessageWriter; @@ -103,7 +102,7 @@ import org.apache.ignite.internal.processors.tracing.MTC.TraceSurroundings; import org.apache.ignite.internal.processors.tracing.Span; import org.apache.ignite.internal.processors.tracing.SpanTags; -import org.apache.ignite.internal.thread.context.DistributedOperationContextAttributeRegistry; +import org.apache.ignite.internal.thread.context.DistributedOperationAttributeManager; import org.apache.ignite.internal.thread.context.Scope; import org.apache.ignite.internal.util.GridBoundedConcurrentLinkedHashSet; import org.apache.ignite.internal.util.IgniteUtils; @@ -462,14 +461,9 @@ public void resetMetrics() { try { GridIoMessage msg0 = (GridIoMessage)msg; - if (!locNodeId.equals(nodeId) && msg0.opCtxMsg != null) { - try (Scope ignored = DistributedOperationContextAttributeRegistry.instance() - .restoreContext(msg0.opCtxMsg.idBitmask, msg0.opCtxMsg.vals)) { - onMessage0(nodeId, msg0, msgC); - } - } - else + try (Scope ignored = DistributedOperationAttributeManager.instance().restoreDistributedAttributes(msg0.opCtxMsg)) { onMessage0(nodeId, msg0, msgC); + } } catch (ClassCastException ignored) { U.error(log, "Communication manager received message of unknown type (will ignore): " + @@ -2061,8 +2055,7 @@ private long getInverseConnectionWaitTimeout() { else res = new GridIoMessage(plc, topic, msg, ordered, timeout, skipOnTimeout); - res.opCtxMsg = OperationContexMessage.create(DistributedOperationContextAttributeRegistry.instance() - .collectContext(Message.class)); + res.opCtxMsg = DistributedOperationAttributeManager.instance().collectDistributedAttributes(); return res; } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessage.java index f6a099481ac2b..8aedd85956fea 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessage.java @@ -17,9 +17,9 @@ package org.apache.ignite.internal.managers.communication; +import org.apache.ignite.internal.DistributedOperationAttributesMessage; import org.apache.ignite.internal.ExecutorAwareMessage; import org.apache.ignite.internal.GridTopicMessage; -import org.apache.ignite.internal.OperationContexMessage; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.cache.GridCacheMessage; import org.apache.ignite.internal.processors.datastreamer.DataStreamerRequest; @@ -68,7 +68,7 @@ public class GridIoMessage implements Message, SpanTransport { /** Effective operation context attributes. */ @Order(7) @GridToStringInclude - public @Nullable OperationContexMessage opCtxMsg; + public @Nullable DistributedOperationAttributesMessage opCtxMsg; /** * Default constructor. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationAttributeManager.java b/modules/core/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationAttributeManager.java new file mode 100644 index 0000000000000..9c1dec7ea4cdc --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationAttributeManager.java @@ -0,0 +1,117 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.ignite.internal.thread.context; + +import java.util.ArrayList; +import java.util.Map; +import java.util.Objects; +import java.util.concurrent.ConcurrentHashMap; +import org.apache.ignite.IgniteException; +import org.apache.ignite.internal.DistributedOperationAttributesMessage; +import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.plugin.extensions.communication.Message; +import org.jetbrains.annotations.Nullable; + +/** */ +public class DistributedOperationAttributeManager { + /** */ + public static final byte MAX_DISTRIBUTED_ATTR_ID = 7; + + /** */ + private static final DistributedOperationAttributeManager INSTANCE = new DistributedOperationAttributeManager(); + + /** Attributes by their id. */ + private final Map> attrs = new ConcurrentHashMap<>(); + + /** */ + public static DistributedOperationAttributeManager instance() { + return INSTANCE; + } + + /** */ + public OperationContextAttribute createDistributedAttriubte(byte id, @Nullable T initVal) { + assert id >= 0; + + if (attrs.size() == OperationContextAttribute.MAX_ATTR_CNT) + throw new IgniteException("Maximum number of ributed attributes is exceeded [" + OperationContextAttribute.MAX_ATTR_CNT + "]."); + + attrs.compute(id, (id0, attr0) -> { + if (attr0 != null) + throw new IgniteException("Duplicated distributed attribute id: " + id); + + return OperationContextAttribute.newInstance(initVal); + }); + + return (OperationContextAttribute)attrs.get(id); + } + + /** */ + public @Nullable DistributedOperationAttributesMessage collectDistributedAttributes() { + DistributedOperationAttributesMessage res = null; + + for (Map.Entry> e : attrs.entrySet()) { + OperationContextAttribute attr = e.getValue(); + + Message curVal = OperationContext.get(attr); + + assert attr.initialValue() == null || curVal == null || curVal.getClass().isAssignableFrom(attr.initialValue().getClass()); + + if (!Objects.equals(curVal, attr.initialValue())) { + if (res == null) { + res = new DistributedOperationAttributesMessage(); + + res.vals = new ArrayList<>(MAX_DISTRIBUTED_ATTR_ID / 2); + } + + byte mask = (byte)(1 << e.getKey()); + + assert (res.idBitmask & mask) == 0; + + res.vals.add(curVal); + res.idBitmask |= mask; + } + } + + return res; + } + + /** */ + public Scope restoreDistributedAttributes(@Nullable DistributedOperationAttributesMessage msg) { + if (msg == null) + return Scope.NOOP_SCOPE; + + assert msg.idBitmask != 0; + assert !F.isEmpty(msg.vals); + assert msg.vals.size() <= MAX_DISTRIBUTED_ATTR_ID; + + OperationContext.ContextUpdater updater = OperationContext.ContextUpdater.create(); + + for (byte valIdx = 0, maskIdx = -1; valIdx < msg.vals.size(); ++valIdx) { + Message curVal = msg.vals.get(valIdx); + + while (maskIdx < 0 || (msg.idBitmask & (1 << maskIdx)) == 0) { + assert maskIdx <= MAX_DISTRIBUTED_ATTR_ID; + + ++maskIdx; + } + + updater.set((OperationContextAttribute)attrs.get(maskIdx++), curVal); + } + + return updater.apply(); + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java index cfc1784304d28..da38209518d63 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java @@ -64,14 +64,13 @@ import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.IgniteInterruptedCheckedException; import org.apache.ignite.internal.IgniteNodeAttributes; -import org.apache.ignite.internal.OperationContexMessage; import org.apache.ignite.internal.managers.discovery.DiscoveryServerOnlyCustomMessage; import org.apache.ignite.internal.processors.tracing.Span; import org.apache.ignite.internal.processors.tracing.SpanTags; import org.apache.ignite.internal.processors.tracing.messages.SpanContainer; import org.apache.ignite.internal.processors.tracing.messages.TraceableMessage; import org.apache.ignite.internal.processors.tracing.messages.TraceableMessagesTable; -import org.apache.ignite.internal.thread.context.DistributedOperationContextAttributeRegistry; +import org.apache.ignite.internal.thread.context.DistributedOperationAttributeManager; import org.apache.ignite.internal.thread.context.Scope; import org.apache.ignite.internal.util.future.GridFutureAdapter; import org.apache.ignite.internal.util.tostring.GridToStringExclude; @@ -84,7 +83,6 @@ import org.apache.ignite.internal.worker.WorkersRegistry; import org.apache.ignite.lang.IgniteInClosure; import org.apache.ignite.lang.IgniteUuid; -import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.spi.IgniteSpiAdapter; import org.apache.ignite.spi.IgniteSpiContext; import org.apache.ignite.spi.IgniteSpiException; @@ -1314,8 +1312,7 @@ private class SocketWriter extends IgniteSpiThread { * @param msg Message. */ private void sendMessage(TcpDiscoveryAbstractMessage msg) { - msg.opCtxMsg = OperationContexMessage.create(DistributedOperationContextAttributeRegistry.instance() - .collectContext(Message.class)); + msg.opCtxMsg = DistributedOperationAttributeManager.instance().collectDistributedAttributes(); synchronized (mux) { queue.add(msg); @@ -2010,13 +2007,8 @@ else if (discoMsg instanceof TcpDiscoveryCheckFailedMessage) TcpDiscoveryAbstractMessage msg0 = (TcpDiscoveryAbstractMessage)msg; - if (msg0.opCtxMsg == null) + try (Scope ignored = DistributedOperationAttributeManager.instance().restoreDistributedAttributes(msg0.opCtxMsg)) { processDiscoveryMessage(msg0); - else { - try (Scope ignored = DistributedOperationContextAttributeRegistry.instance() - .restoreContext(msg0.opCtxMsg.idBitmask, msg0.opCtxMsg.vals)) { - processDiscoveryMessage(msg0); - } } } } diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java index c7f1875b74ce9..c8f45ecc8ccbf 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java @@ -81,7 +81,6 @@ import org.apache.ignite.internal.IgniteInterruptedCheckedException; import org.apache.ignite.internal.IgniteNodeAttributes; import org.apache.ignite.internal.IgnitionEx; -import org.apache.ignite.internal.OperationContexMessage; import org.apache.ignite.internal.events.DiscoveryCustomEvent; import org.apache.ignite.internal.managers.communication.UnknownMessageException; import org.apache.ignite.internal.managers.discovery.DiscoveryServerOnlyCustomMessage; @@ -96,7 +95,7 @@ import org.apache.ignite.internal.processors.tracing.messages.SpanContainer; import org.apache.ignite.internal.processors.tracing.messages.TraceableMessage; import org.apache.ignite.internal.processors.tracing.messages.TraceableMessagesTable; -import org.apache.ignite.internal.thread.context.DistributedOperationContextAttributeRegistry; +import org.apache.ignite.internal.thread.context.DistributedOperationAttributeManager; import org.apache.ignite.internal.thread.context.Scope; import org.apache.ignite.internal.thread.pool.IgniteThreadPoolExecutor; import org.apache.ignite.internal.util.GridBoundedLinkedHashSet; @@ -121,7 +120,6 @@ import org.apache.ignite.lang.IgniteInClosure; import org.apache.ignite.lang.IgniteProductVersion; import org.apache.ignite.lang.IgniteUuid; -import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.plugin.security.SecurityCredentials; import org.apache.ignite.spi.IgniteNodeValidationResult; import org.apache.ignite.spi.IgniteSpiContext; @@ -3050,13 +3048,10 @@ void addMessage(TcpDiscoveryAbstractMessage msg, boolean ignoreHighPriority, boo return; } - if (!fromSocket) { - msg.opCtxMsg = OperationContexMessage.create(DistributedOperationContextAttributeRegistry.instance() - .collectContext(Message.class)); - } + if (!fromSocket) + msg.opCtxMsg = DistributedOperationAttributeManager.instance().collectDistributedAttributes(); - if (msg instanceof TraceableMessage) { - TraceableMessage tMsg = (TraceableMessage)msg; + if (msg instanceof TraceableMessage tMsg) { // If we read this message from socket. if (fromSocket) @@ -3326,14 +3321,8 @@ else if (msg instanceof TcpDiscoveryAuthFailedMessage) if (msg == WAKEUP) return; - if (msg.opCtxMsg == null) + try (Scope ignored = DistributedOperationAttributeManager.instance().restoreDistributedAttributes(msg.opCtxMsg)) { processMessage0(msg); - else { - OperationContexMessage cm = msg.opCtxMsg; - - try (Scope ignored = DistributedOperationContextAttributeRegistry.instance().restoreContext(cm.idBitmask, cm.vals)) { - processMessage0(msg); - } } } diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryAbstractMessage.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryAbstractMessage.java index 1f624f7775af8..f92f0e0524576 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryAbstractMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryAbstractMessage.java @@ -21,7 +21,7 @@ import java.util.HashSet; import java.util.Set; import java.util.UUID; -import org.apache.ignite.internal.OperationContexMessage; +import org.apache.ignite.internal.DistributedOperationAttributesMessage; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.util.tostring.GridToStringExclude; import org.apache.ignite.internal.util.tostring.GridToStringInclude; @@ -80,7 +80,7 @@ public abstract class TcpDiscoveryAbstractMessage implements Message { /** Operation context attributes message. */ @GridToStringInclude @Order(5) - public @Nullable OperationContexMessage opCtxMsg; + public @Nullable DistributedOperationAttributesMessage opCtxMsg; /** * Default no-arg constructor for {@link Externalizable} interface. diff --git a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java index 477af4b633abd..0d4eae5565bd9 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java @@ -826,13 +826,12 @@ public void testContextAwareDelayQueue() throws Exception { /** */ @Test public void testSendAttributesByDiscovery() throws Exception { - byte attrId = DistributedOperationContextAttributeRegistry.MAX_DISTRIBUTED_ATTR_ID; + byte attrId = DistributedOperationAttributeManager.MAX_DISTRIBUTED_ATTR_ID; InetSocketAddressMessage dfltAttrVal = new InetSocketAddressMessage(InetAddress.getLoopbackAddress(), 80); - OperationContextAttribute attr = OperationContextAttribute.newInstance(); - - DistributedOperationContextAttributeRegistry.instance().register(attrId, attr); + OperationContextAttribute attr = DistributedOperationAttributeManager.instance() + .createDistributedAttriubte(attrId, dfltAttrVal); startGrids(2); startClientGrid(2); @@ -854,7 +853,9 @@ public void testSendAttributesByDiscovery() throws Exception { InetSocketAddressMessage receivedVal = OperationContext.get(attr); assertNotNull(receivedVal); + assertFalse(dfltAttrVal.port() == receivedVal.port()); + assertEquals(receivedVal.port(), valToSend.port()); assertEquals(receivedVal.address(), valToSend.address()); @@ -868,9 +869,6 @@ else if (grid(i0).localNode().order() == 1) }); } - assertFalse(valToSend.equals(dfltAttrVal)); - assertNull(OperationContext.get(attr)); - // Send from the coordinator. try (Scope ignored = OperationContext.set(attr, valToSend)) { grid(0).createCache(defaultCacheConfiguration()); @@ -879,7 +877,6 @@ else if (grid(i0).localNode().order() == 1) assertTrue(waitForCondition(() -> coordLatch.getCount() == 2, getTestTimeout())); assertTrue(waitForCondition(() -> srvrLatch.getCount() == 2, getTestTimeout())); assertTrue(waitForCondition(() -> clientLatch.getCount() == 2, getTestTimeout())); - assertNull(OperationContext.get(attr)); // Send from a server. try (Scope ignored = OperationContext.set(attr, valToSend)) { @@ -889,14 +886,12 @@ else if (grid(i0).localNode().order() == 1) assertTrue(waitForCondition(() -> coordLatch.getCount() == 1, getTestTimeout())); assertTrue(waitForCondition(() -> srvrLatch.getCount() == 1, getTestTimeout())); assertTrue(waitForCondition(() -> clientLatch.getCount() == 1, getTestTimeout())); - assertNull(OperationContext.get(attr)); // Send from a client. try (Scope ignored = OperationContext.set(attr, valToSend)) { grid(2).createCache(defaultCacheConfiguration()); } - assertNull(OperationContext.get(attr)); assertTrue(coordLatch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); assertTrue(srvrLatch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); assertTrue(clientLatch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); @@ -905,13 +900,12 @@ else if (grid(i0).localNode().order() == 1) /** */ @Test public void testSendAttributesByCommunication() throws Exception { - byte attrId = DistributedOperationContextAttributeRegistry.MAX_DISTRIBUTED_ATTR_ID; + byte attrId = DistributedOperationAttributeManager.MAX_DISTRIBUTED_ATTR_ID; InetSocketAddressMessage dfltAttrVal = new InetSocketAddressMessage(InetAddress.getLoopbackAddress(), 80); - OperationContextAttribute attr = OperationContextAttribute.newInstance(); - - DistributedOperationContextAttributeRegistry.instance().register(attrId, attr); + OperationContextAttribute attr = DistributedOperationAttributeManager.instance() + .createDistributedAttriubte(attrId, dfltAttrVal); startGrids(2); startClientGrid(2); @@ -947,7 +941,6 @@ else if (grid(i0).localNode().order() == 1) } assertFalse(attrValToSend.equals(dfltAttrVal)); - assertNull(OperationContext.get(attr)); // From the coordinator to a server. try (Scope ignored = OperationContext.set(attr, attrValToSend)) { @@ -956,7 +949,6 @@ else if (grid(i0).localNode().order() == 1) } assertTrue(waitForCondition(() -> coordLatch.getCount() == 2, getTestTimeout())); - assertNull(OperationContext.get(attr)); // From a server to the coordinator. try (Scope ignored = OperationContext.set(attr, attrValToSend)) { @@ -965,7 +957,6 @@ else if (grid(i0).localNode().order() == 1) } assertTrue(coordLatch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); - assertNull(OperationContext.get(attr)); // From a client to a server. try (Scope ignored = OperationContext.set(attr, attrValToSend)) { @@ -974,7 +965,6 @@ else if (grid(i0).localNode().order() == 1) } assertTrue(srvrLatch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); - assertNull(OperationContext.get(attr)); // From a server to a client. try (Scope ignored = OperationContext.set(attr, attrValToSend)) { @@ -983,7 +973,6 @@ else if (grid(i0).localNode().order() == 1) } assertTrue(clientLatch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); - assertNull(OperationContext.get(attr)); } /** @return a {@link ClusterNode} with {@link ClusterNode#isLocal()} == {@code false} to avoid some asserts/checks. */ From f219fb555abd95120d1a74bf92fc6c9469977258 Mon Sep 17 00:00:00 2001 From: Vladimir Steshin Date: Fri, 19 Jun 2026 16:37:48 +0300 Subject: [PATCH 17/18] raw --- .../context/OperationContextAttribute.java | 2 +- .../ignite/internal/CoreMessagesProvider.java | 2 +- ...> DistributedOperationContextMessage.java} | 4 +- .../managers/communication/GridIoManager.java | 6 +-- .../managers/communication/GridIoMessage.java | 4 +- ...> DistributedOperationContextManager.java} | 53 +++++++++---------- .../ignite/spi/discovery/tcp/ClientImpl.java | 6 +-- .../ignite/spi/discovery/tcp/ServerImpl.java | 6 +-- .../messages/TcpDiscoveryAbstractMessage.java | 4 +- .../OperationContextAttributesTest.java | 8 +-- 10 files changed, 47 insertions(+), 48 deletions(-) rename modules/core/src/main/java/org/apache/ignite/internal/{DistributedOperationAttributesMessage.java => DistributedOperationContextMessage.java} (91%) rename modules/core/src/main/java/org/apache/ignite/internal/thread/context/{DistributedOperationAttributeManager.java => DistributedOperationContextManager.java} (66%) diff --git a/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/OperationContextAttribute.java b/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/OperationContextAttribute.java index 373a72ee3b278..499d241d9ccba 100644 --- a/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/OperationContextAttribute.java +++ b/modules/commons/src/main/java/org/apache/ignite/internal/thread/context/OperationContextAttribute.java @@ -32,7 +32,7 @@ public class OperationContextAttribute { static final AtomicInteger ID_GEN = new AtomicInteger(); /** */ - public static final int MAX_ATTR_CNT = Integer.SIZE; + static final int MAX_ATTR_CNT = Integer.SIZE; /** */ private final int bitmask; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java b/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java index 19fb738b9dd2f..f6b51fabbcde3 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/CoreMessagesProvider.java @@ -668,7 +668,7 @@ public CoreMessagesProvider(Marshaller dfltMarsh, Marshaller schemaAwareMarsh, C // [13400 - 13500]: Operation context messages. msgIdx = 13400; - withNoSchema(DistributedOperationAttributesMessage.class); + withNoSchema(DistributedOperationContextMessage.class); assert msgIdx <= MAX_MESSAGE_ID; } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/DistributedOperationAttributesMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/DistributedOperationContextMessage.java similarity index 91% rename from modules/core/src/main/java/org/apache/ignite/internal/DistributedOperationAttributesMessage.java rename to modules/core/src/main/java/org/apache/ignite/internal/DistributedOperationContextMessage.java index 32b106f649903..3c623e9695386 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/DistributedOperationAttributesMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/DistributedOperationContextMessage.java @@ -22,7 +22,7 @@ import org.apache.ignite.plugin.extensions.communication.Message; /** Transport for {@link OperationContext} distibuted attributes. */ -public class DistributedOperationAttributesMessage implements Message { +public class DistributedOperationContextMessage implements Message { /** Values of operation context attributes. */ @Order(0) public List vals; @@ -32,7 +32,7 @@ public class DistributedOperationAttributesMessage implements Message { public byte idBitmask; /** Empty constructor for serialization purposes. */ - public DistributedOperationAttributesMessage() { + public DistributedOperationContextMessage() { // No-op. } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java index 2d74d2260de80..bdbc375fc9ff3 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoManager.java @@ -102,7 +102,7 @@ import org.apache.ignite.internal.processors.tracing.MTC.TraceSurroundings; import org.apache.ignite.internal.processors.tracing.Span; import org.apache.ignite.internal.processors.tracing.SpanTags; -import org.apache.ignite.internal.thread.context.DistributedOperationAttributeManager; +import org.apache.ignite.internal.thread.context.DistributedOperationContextManager; import org.apache.ignite.internal.thread.context.Scope; import org.apache.ignite.internal.util.GridBoundedConcurrentLinkedHashSet; import org.apache.ignite.internal.util.IgniteUtils; @@ -461,7 +461,7 @@ public void resetMetrics() { try { GridIoMessage msg0 = (GridIoMessage)msg; - try (Scope ignored = DistributedOperationAttributeManager.instance().restoreDistributedAttributes(msg0.opCtxMsg)) { + try (Scope ignored = DistributedOperationContextManager.instance().restoreDistributedAttributes(msg0.opCtxMsg)) { onMessage0(nodeId, msg0, msgC); } } @@ -2055,7 +2055,7 @@ private long getInverseConnectionWaitTimeout() { else res = new GridIoMessage(plc, topic, msg, ordered, timeout, skipOnTimeout); - res.opCtxMsg = DistributedOperationAttributeManager.instance().collectDistributedAttributes(); + res.opCtxMsg = DistributedOperationContextManager.instance().collectDistributedAttributes(); return res; } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessage.java index 8aedd85956fea..cb09122415def 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessage.java @@ -17,7 +17,7 @@ package org.apache.ignite.internal.managers.communication; -import org.apache.ignite.internal.DistributedOperationAttributesMessage; +import org.apache.ignite.internal.DistributedOperationContextMessage; import org.apache.ignite.internal.ExecutorAwareMessage; import org.apache.ignite.internal.GridTopicMessage; import org.apache.ignite.internal.Order; @@ -68,7 +68,7 @@ public class GridIoMessage implements Message, SpanTransport { /** Effective operation context attributes. */ @Order(7) @GridToStringInclude - public @Nullable DistributedOperationAttributesMessage opCtxMsg; + public @Nullable DistributedOperationContextMessage opCtxMsg; /** * Default constructor. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationAttributeManager.java b/modules/core/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextManager.java similarity index 66% rename from modules/core/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationAttributeManager.java rename to modules/core/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextManager.java index 9c1dec7ea4cdc..0738398560df2 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationAttributeManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextManager.java @@ -18,27 +18,26 @@ import java.util.ArrayList; import java.util.Map; -import java.util.Objects; -import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentSkipListMap; import org.apache.ignite.IgniteException; -import org.apache.ignite.internal.DistributedOperationAttributesMessage; +import org.apache.ignite.internal.DistributedOperationContextAttributesMessage; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.plugin.extensions.communication.Message; import org.jetbrains.annotations.Nullable; /** */ -public class DistributedOperationAttributeManager { +public class DistributedOperationContextManager { /** */ - public static final byte MAX_DISTRIBUTED_ATTR_ID = 7; + static final byte MAX_DISTRIBUTED_ATTR_CNT = 7; /** */ - private static final DistributedOperationAttributeManager INSTANCE = new DistributedOperationAttributeManager(); + private static final DistributedOperationContextManager INSTANCE = new DistributedOperationContextManager(); /** Attributes by their id. */ - private final Map> attrs = new ConcurrentHashMap<>(); + private final Map> attrs = new ConcurrentSkipListMap<>(); /** */ - public static DistributedOperationAttributeManager instance() { + public static DistributedOperationContextManager instance() { return INSTANCE; } @@ -46,22 +45,22 @@ public static DistributedOperationAttributeManager instance() { public OperationContextAttribute createDistributedAttriubte(byte id, @Nullable T initVal) { assert id >= 0; - if (attrs.size() == OperationContextAttribute.MAX_ATTR_CNT) - throw new IgniteException("Maximum number of ributed attributes is exceeded [" + OperationContextAttribute.MAX_ATTR_CNT + "]."); + if (attrs.size() == OperationContextAttribute.MAX_ATTR_CNT) { + throw new IgniteException("Maximum number of distributed attributes is exceeded [max=" + + OperationContextAttribute.MAX_ATTR_CNT + "]."); + } - attrs.compute(id, (id0, attr0) -> { + return (OperationContextAttribute)attrs.compute(id, (id0, attr0) -> { if (attr0 != null) - throw new IgniteException("Duplicated distributed attribute id: " + id); + throw new IgniteException("Duplicated distributed attribute id [id=" + id + "]."); return OperationContextAttribute.newInstance(initVal); }); - - return (OperationContextAttribute)attrs.get(id); } /** */ - public @Nullable DistributedOperationAttributesMessage collectDistributedAttributes() { - DistributedOperationAttributesMessage res = null; + public @Nullable DistributedOperationContextAttributesMessage collectDistributedAttributes() { + DistributedOperationContextAttributesMessage res = null; for (Map.Entry> e : attrs.entrySet()) { OperationContextAttribute attr = e.getValue(); @@ -70,19 +69,19 @@ public OperationContextAttribute createDistributedAttriub assert attr.initialValue() == null || curVal == null || curVal.getClass().isAssignableFrom(attr.initialValue().getClass()); - if (!Objects.equals(curVal, attr.initialValue())) { + if (curVal != attr.initialValue()) { if (res == null) { - res = new DistributedOperationAttributesMessage(); + res = new DistributedOperationContextAttributesMessage(); - res.vals = new ArrayList<>(MAX_DISTRIBUTED_ATTR_ID / 2); + res.vals = new ArrayList<>(MAX_DISTRIBUTED_ATTR_CNT / 2); } byte mask = (byte)(1 << e.getKey()); - assert (res.idBitmask & mask) == 0; + assert (res.idBitmap & mask) == 0; res.vals.add(curVal); - res.idBitmask |= mask; + res.idBitmap |= mask; } } @@ -90,21 +89,21 @@ public OperationContextAttribute createDistributedAttriub } /** */ - public Scope restoreDistributedAttributes(@Nullable DistributedOperationAttributesMessage msg) { + public Scope restoreDistributedAttributes(@Nullable DistributedOperationContextAttributesMessage msg) { if (msg == null) return Scope.NOOP_SCOPE; - assert msg.idBitmask != 0; + assert msg.idBitmap != 0; assert !F.isEmpty(msg.vals); - assert msg.vals.size() <= MAX_DISTRIBUTED_ATTR_ID; + assert msg.vals.size() <= MAX_DISTRIBUTED_ATTR_CNT; OperationContext.ContextUpdater updater = OperationContext.ContextUpdater.create(); - for (byte valIdx = 0, maskIdx = -1; valIdx < msg.vals.size(); ++valIdx) { + for (byte valIdx = 0, maskIdx = 0; valIdx < msg.vals.size(); ++valIdx) { Message curVal = msg.vals.get(valIdx); - while (maskIdx < 0 || (msg.idBitmask & (1 << maskIdx)) == 0) { - assert maskIdx <= MAX_DISTRIBUTED_ATTR_ID; + while ((msg.idBitmap & (1 << maskIdx)) == 0) { + assert maskIdx <= MAX_DISTRIBUTED_ATTR_CNT; ++maskIdx; } diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java index da38209518d63..ec153176d64b6 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ClientImpl.java @@ -70,7 +70,7 @@ import org.apache.ignite.internal.processors.tracing.messages.SpanContainer; import org.apache.ignite.internal.processors.tracing.messages.TraceableMessage; import org.apache.ignite.internal.processors.tracing.messages.TraceableMessagesTable; -import org.apache.ignite.internal.thread.context.DistributedOperationAttributeManager; +import org.apache.ignite.internal.thread.context.DistributedOperationContextManager; import org.apache.ignite.internal.thread.context.Scope; import org.apache.ignite.internal.util.future.GridFutureAdapter; import org.apache.ignite.internal.util.tostring.GridToStringExclude; @@ -1312,7 +1312,7 @@ private class SocketWriter extends IgniteSpiThread { * @param msg Message. */ private void sendMessage(TcpDiscoveryAbstractMessage msg) { - msg.opCtxMsg = DistributedOperationAttributeManager.instance().collectDistributedAttributes(); + msg.opCtxMsg = DistributedOperationContextManager.instance().collectDistributedAttributes(); synchronized (mux) { queue.add(msg); @@ -2007,7 +2007,7 @@ else if (discoMsg instanceof TcpDiscoveryCheckFailedMessage) TcpDiscoveryAbstractMessage msg0 = (TcpDiscoveryAbstractMessage)msg; - try (Scope ignored = DistributedOperationAttributeManager.instance().restoreDistributedAttributes(msg0.opCtxMsg)) { + try (Scope ignored = DistributedOperationContextManager.instance().restoreDistributedAttributes(msg0.opCtxMsg)) { processDiscoveryMessage(msg0); } } diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java index c8f45ecc8ccbf..a8a4f2f0a473e 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/ServerImpl.java @@ -95,7 +95,7 @@ import org.apache.ignite.internal.processors.tracing.messages.SpanContainer; import org.apache.ignite.internal.processors.tracing.messages.TraceableMessage; import org.apache.ignite.internal.processors.tracing.messages.TraceableMessagesTable; -import org.apache.ignite.internal.thread.context.DistributedOperationAttributeManager; +import org.apache.ignite.internal.thread.context.DistributedOperationContextManager; import org.apache.ignite.internal.thread.context.Scope; import org.apache.ignite.internal.thread.pool.IgniteThreadPoolExecutor; import org.apache.ignite.internal.util.GridBoundedLinkedHashSet; @@ -3049,7 +3049,7 @@ void addMessage(TcpDiscoveryAbstractMessage msg, boolean ignoreHighPriority, boo } if (!fromSocket) - msg.opCtxMsg = DistributedOperationAttributeManager.instance().collectDistributedAttributes(); + msg.opCtxMsg = DistributedOperationContextManager.instance().collectDistributedAttributes(); if (msg instanceof TraceableMessage tMsg) { @@ -3321,7 +3321,7 @@ else if (msg instanceof TcpDiscoveryAuthFailedMessage) if (msg == WAKEUP) return; - try (Scope ignored = DistributedOperationAttributeManager.instance().restoreDistributedAttributes(msg.opCtxMsg)) { + try (Scope ignored = DistributedOperationContextManager.instance().restoreDistributedAttributes(msg.opCtxMsg)) { processMessage0(msg); } } diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryAbstractMessage.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryAbstractMessage.java index f92f0e0524576..9dda990c7d020 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryAbstractMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryAbstractMessage.java @@ -21,7 +21,7 @@ import java.util.HashSet; import java.util.Set; import java.util.UUID; -import org.apache.ignite.internal.DistributedOperationAttributesMessage; +import org.apache.ignite.internal.DistributedOperationContextMessage; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.util.tostring.GridToStringExclude; import org.apache.ignite.internal.util.tostring.GridToStringInclude; @@ -80,7 +80,7 @@ public abstract class TcpDiscoveryAbstractMessage implements Message { /** Operation context attributes message. */ @GridToStringInclude @Order(5) - public @Nullable DistributedOperationAttributesMessage opCtxMsg; + public @Nullable DistributedOperationContextMessage opCtxMsg; /** * Default no-arg constructor for {@link Externalizable} interface. diff --git a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java index 0d4eae5565bd9..eb688d0194955 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java @@ -826,11 +826,11 @@ public void testContextAwareDelayQueue() throws Exception { /** */ @Test public void testSendAttributesByDiscovery() throws Exception { - byte attrId = DistributedOperationAttributeManager.MAX_DISTRIBUTED_ATTR_ID; + byte attrId = DistributedOperationContextManager.MAX_DISTRIBUTED_ATTR_ID; InetSocketAddressMessage dfltAttrVal = new InetSocketAddressMessage(InetAddress.getLoopbackAddress(), 80); - OperationContextAttribute attr = DistributedOperationAttributeManager.instance() + OperationContextAttribute attr = DistributedOperationContextManager.instance() .createDistributedAttriubte(attrId, dfltAttrVal); startGrids(2); @@ -900,11 +900,11 @@ else if (grid(i0).localNode().order() == 1) /** */ @Test public void testSendAttributesByCommunication() throws Exception { - byte attrId = DistributedOperationAttributeManager.MAX_DISTRIBUTED_ATTR_ID; + byte attrId = DistributedOperationContextManager.MAX_DISTRIBUTED_ATTR_ID; InetSocketAddressMessage dfltAttrVal = new InetSocketAddressMessage(InetAddress.getLoopbackAddress(), 80); - OperationContextAttribute attr = DistributedOperationAttributeManager.instance() + OperationContextAttribute attr = DistributedOperationContextManager.instance() .createDistributedAttriubte(attrId, dfltAttrVal); startGrids(2); From 84fdd2ae9f558ad5024d87dd8931070996f52a30 Mon Sep 17 00:00:00 2001 From: Vladimir Steshin Date: Fri, 19 Jun 2026 17:53:58 +0300 Subject: [PATCH 18/18] test fix --- .../DistributedOperationContextMessage.java | 4 +- .../DistributedOperationContextManager.java | 10 +- .../OperationContextAttributesTest.java | 95 +++++++++++++------ 3 files changed, 74 insertions(+), 35 deletions(-) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/DistributedOperationContextMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/DistributedOperationContextMessage.java index 3c623e9695386..0277784044272 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/DistributedOperationContextMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/DistributedOperationContextMessage.java @@ -21,7 +21,7 @@ import org.apache.ignite.internal.thread.context.OperationContext; import org.apache.ignite.plugin.extensions.communication.Message; -/** Transport for {@link OperationContext} distibuted attributes. */ +/** Transport for {@link OperationContext} distributed attributes. */ public class DistributedOperationContextMessage implements Message { /** Values of operation context attributes. */ @Order(0) @@ -29,7 +29,7 @@ public class DistributedOperationContextMessage implements Message { /** Bitmask of effective attributes ids. */ @Order(1) - public byte idBitmask; + public byte idBitmap; /** Empty constructor for serialization purposes. */ public DistributedOperationContextMessage() { diff --git a/modules/core/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextManager.java b/modules/core/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextManager.java index 0738398560df2..a95e48880353f 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/thread/context/DistributedOperationContextManager.java @@ -20,7 +20,7 @@ import java.util.Map; import java.util.concurrent.ConcurrentSkipListMap; import org.apache.ignite.IgniteException; -import org.apache.ignite.internal.DistributedOperationContextAttributesMessage; +import org.apache.ignite.internal.DistributedOperationContextMessage; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.plugin.extensions.communication.Message; import org.jetbrains.annotations.Nullable; @@ -59,8 +59,8 @@ public OperationContextAttribute createDistributedAttriub } /** */ - public @Nullable DistributedOperationContextAttributesMessage collectDistributedAttributes() { - DistributedOperationContextAttributesMessage res = null; + public @Nullable DistributedOperationContextMessage collectDistributedAttributes() { + DistributedOperationContextMessage res = null; for (Map.Entry> e : attrs.entrySet()) { OperationContextAttribute attr = e.getValue(); @@ -71,7 +71,7 @@ public OperationContextAttribute createDistributedAttriub if (curVal != attr.initialValue()) { if (res == null) { - res = new DistributedOperationContextAttributesMessage(); + res = new DistributedOperationContextMessage(); res.vals = new ArrayList<>(MAX_DISTRIBUTED_ATTR_CNT / 2); } @@ -89,7 +89,7 @@ public OperationContextAttribute createDistributedAttriub } /** */ - public Scope restoreDistributedAttributes(@Nullable DistributedOperationContextAttributesMessage msg) { + public Scope restoreDistributedAttributes(@Nullable DistributedOperationContextMessage msg) { if (msg == null) return Scope.NOOP_SCOPE; diff --git a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java index eb688d0194955..7bef37a872d43 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/thread/context/OperationContextAttributesTest.java @@ -48,6 +48,7 @@ import org.apache.ignite.internal.managers.discovery.CustomEventListener; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.DynamicCacheChangeBatch; +import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.processors.timeout.GridTimeoutObject; import org.apache.ignite.internal.processors.timeout.GridTimeoutProcessor; import org.apache.ignite.internal.thread.context.concurrent.IgniteCompletableFuture; @@ -826,12 +827,25 @@ public void testContextAwareDelayQueue() throws Exception { /** */ @Test public void testSendAttributesByDiscovery() throws Exception { - byte attrId = DistributedOperationContextManager.MAX_DISTRIBUTED_ATTR_ID; + byte attrId1 = 0; + byte attrId2 = DistributedOperationContextManager.MAX_DISTRIBUTED_ATTR_CNT; - InetSocketAddressMessage dfltAttrVal = new InetSocketAddressMessage(InetAddress.getLoopbackAddress(), 80); + InetSocketAddressMessage dfltDistAttr1Val = new InetSocketAddressMessage(InetAddress.getLoopbackAddress(), 80); + GridCacheVersion dfltDistrAttr2Val = new GridCacheVersion(1, 1, 1); - OperationContextAttribute attr = DistributedOperationContextManager.instance() - .createDistributedAttriubte(attrId, dfltAttrVal); + // Local attribute 1. + OperationContextAttribute.newInstance(1000); + + // Distributed attribute 1. + OperationContextAttribute dAttr1 = DistributedOperationContextManager.instance() + .createDistributedAttriubte(attrId1, dfltDistAttr1Val); + + // Local attribute 2. + OperationContextAttribute.newInstance("locaAttr2"); + + // Distributed attribute 2. + OperationContextAttribute dAttr2 = DistributedOperationContextManager.instance() + .createDistributedAttriubte(attrId2, dfltDistrAttr2Val); startGrids(2); startClientGrid(2); @@ -840,7 +854,8 @@ public void testSendAttributesByDiscovery() throws Exception { CountDownLatch srvrLatch = new CountDownLatch(3); CountDownLatch clientLatch = new CountDownLatch(3); - InetSocketAddressMessage valToSend = new InetSocketAddressMessage(dfltAttrVal.address(), 443); + InetSocketAddressMessage valToSend1 = new InetSocketAddressMessage(dfltDistAttr1Val.address(), 443); + GridCacheVersion valToSend2 = new GridCacheVersion(2, 2, 2); for (int i = 0; i < G.allGrids().size(); ++i) { int i0 = i; @@ -850,14 +865,18 @@ public void testSendAttributesByDiscovery() throws Exception { @Override public void onCustomEvent(AffinityTopologyVersion topVer, ClusterNode snd, DynamicCacheChangeBatch msg) { - InetSocketAddressMessage receivedVal = OperationContext.get(attr); + InetSocketAddressMessage receivedVal1 = OperationContext.get(dAttr1); + GridCacheVersion receivedVal2 = OperationContext.get(dAttr2); - assertNotNull(receivedVal); + assertNotNull(receivedVal1); + assertNotNull(receivedVal2); - assertFalse(dfltAttrVal.port() == receivedVal.port()); + assertFalse(dfltDistAttr1Val.port() == receivedVal1.port()); + assertEquals(receivedVal1.port(), valToSend1.port()); + assertEquals(receivedVal1.address(), valToSend1.address()); - assertEquals(receivedVal.port(), valToSend.port()); - assertEquals(receivedVal.address(), valToSend.address()); + assertFalse(dfltDistrAttr2Val.equals(receivedVal2)); + assertTrue(valToSend2.equals(receivedVal2)); if (grid(i0).localNode().isClient()) clientLatch.countDown(); @@ -870,7 +889,7 @@ else if (grid(i0).localNode().order() == 1) } // Send from the coordinator. - try (Scope ignored = OperationContext.set(attr, valToSend)) { + try (Scope ignored = OperationContext.set(dAttr1, valToSend1, dAttr2, valToSend2)) { grid(0).createCache(defaultCacheConfiguration()); } @@ -879,7 +898,7 @@ else if (grid(i0).localNode().order() == 1) assertTrue(waitForCondition(() -> clientLatch.getCount() == 2, getTestTimeout())); // Send from a server. - try (Scope ignored = OperationContext.set(attr, valToSend)) { + try (Scope ignored = OperationContext.set(dAttr1, valToSend1, dAttr2, valToSend2)) { grid(1).destroyCache(DEFAULT_CACHE_NAME); } @@ -888,7 +907,7 @@ else if (grid(i0).localNode().order() == 1) assertTrue(waitForCondition(() -> clientLatch.getCount() == 1, getTestTimeout())); // Send from a client. - try (Scope ignored = OperationContext.set(attr, valToSend)) { + try (Scope ignored = OperationContext.set(dAttr1, valToSend1, dAttr2, valToSend2)) { grid(2).createCache(defaultCacheConfiguration()); } @@ -900,12 +919,25 @@ else if (grid(i0).localNode().order() == 1) /** */ @Test public void testSendAttributesByCommunication() throws Exception { - byte attrId = DistributedOperationContextManager.MAX_DISTRIBUTED_ATTR_ID; + byte attrId1 = 0; + byte attrId2 = DistributedOperationContextManager.MAX_DISTRIBUTED_ATTR_CNT; + + InetSocketAddressMessage dfltDistrAttr1Val = new InetSocketAddressMessage(InetAddress.getLoopbackAddress(), 80); + GridCacheVersion dfltDistrAttr2Val = new GridCacheVersion(1, 1, 1); - InetSocketAddressMessage dfltAttrVal = new InetSocketAddressMessage(InetAddress.getLoopbackAddress(), 80); + // Local attribute 1. + OperationContextAttribute.newInstance(1000); - OperationContextAttribute attr = DistributedOperationContextManager.instance() - .createDistributedAttriubte(attrId, dfltAttrVal); + // Distributed attribute 1. + OperationContextAttribute dAttr1 = DistributedOperationContextManager.instance() + .createDistributedAttriubte(attrId1, dfltDistrAttr1Val); + + // Local attribute 2. + OperationContextAttribute.newInstance("locaAttr2"); + + // Distributed attribute 2. + OperationContextAttribute dAttr2 = DistributedOperationContextManager.instance() + .createDistributedAttriubte(attrId2, dfltDistrAttr2Val); startGrids(2); startClientGrid(2); @@ -914,7 +946,8 @@ public void testSendAttributesByCommunication() throws Exception { CountDownLatch srvrLatch = new CountDownLatch(4); CountDownLatch clientLatch = new CountDownLatch(2); - InetSocketAddressMessage attrValToSend = new InetSocketAddressMessage(dfltAttrVal.address(), 443); + InetSocketAddressMessage valToSend1 = new InetSocketAddressMessage(dfltDistrAttr1Val.address(), 443); + GridCacheVersion valToSend2 = new GridCacheVersion(2, 2, 2); for (int i = 0; i < G.allGrids().size(); ++i) { int i0 = i; @@ -922,12 +955,17 @@ public void testSendAttributesByCommunication() throws Exception { grid(i).context().io().addMessageListener(GridTopic.TOPIC_IO_TEST, new GridMessageListener() { @Override public void onMessage(UUID nodeId, Object msg, byte plc) { if (msg instanceof IgniteIoTestMessage) { - InetSocketAddressMessage receivedVal = OperationContext.get(attr); + InetSocketAddressMessage receivedVal1 = OperationContext.get(dAttr1); + GridCacheVersion receivedVal2 = OperationContext.get(dAttr2); + + assertNotNull(receivedVal1); + assertNotNull(receivedVal2); + + assertFalse(dfltDistrAttr1Val.port() == receivedVal1.port()); + assertEquals(receivedVal1.port(), valToSend1.port()); + assertEquals(receivedVal1.address(), valToSend1.address()); - assertNotNull(receivedVal); - assertFalse(dfltAttrVal.port() == receivedVal.port()); - assertEquals(receivedVal.port(), attrValToSend.port()); - assertEquals(receivedVal.address(), attrValToSend.address()); + assertEquals(receivedVal2, valToSend2); if (grid(i0).localNode().isClient()) clientLatch.countDown(); @@ -940,10 +978,11 @@ else if (grid(i0).localNode().order() == 1) }); } - assertFalse(attrValToSend.equals(dfltAttrVal)); + assertFalse(valToSend1.equals(dfltDistrAttr1Val)); + assertFalse(valToSend2.equals(dfltDistrAttr2Val)); // From the coordinator to a server. - try (Scope ignored = OperationContext.set(attr, attrValToSend)) { + try (Scope ignored = OperationContext.set(dAttr1, valToSend1, dAttr2, valToSend2)) { io(0).sendIoTest(node(1), null, false); io(0).sendIoTest(node(1), null, true); } @@ -951,7 +990,7 @@ else if (grid(i0).localNode().order() == 1) assertTrue(waitForCondition(() -> coordLatch.getCount() == 2, getTestTimeout())); // From a server to the coordinator. - try (Scope ignored = OperationContext.set(attr, attrValToSend)) { + try (Scope ignored = OperationContext.set(dAttr1, valToSend1, dAttr2, valToSend2)) { io(1).sendIoTest(node(0), null, false); io(1).sendIoTest(node(0), null, true); } @@ -959,7 +998,7 @@ else if (grid(i0).localNode().order() == 1) assertTrue(coordLatch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); // From a client to a server. - try (Scope ignored = OperationContext.set(attr, attrValToSend)) { + try (Scope ignored = OperationContext.set(dAttr1, valToSend1, dAttr2, valToSend2)) { io(2).sendIoTest(node(1), null, false); io(2).sendIoTest(node(1), null, true); } @@ -967,7 +1006,7 @@ else if (grid(i0).localNode().order() == 1) assertTrue(srvrLatch.await(getTestTimeout(), TimeUnit.MILLISECONDS)); // From a server to a client. - try (Scope ignored = OperationContext.set(attr, attrValToSend)) { + try (Scope ignored = OperationContext.set(dAttr1, valToSend1, dAttr2, valToSend2)) { io(1).sendIoTest(node(2), null, false); io(1).sendIoTest(node(2), null, true); }