Skip to content

IGNITE-28520 Auto-generate message serialization / marshalling / deployment#13095

Open
anton-vinogradov wants to merge 320 commits into
apache:masterfrom
anton-vinogradov:ignite-28520
Open

IGNITE-28520 Auto-generate message serialization / marshalling / deployment#13095
anton-vinogradov wants to merge 320 commits into
apache:masterfrom
anton-vinogradov:ignite-28520

Conversation

@anton-vinogradov

@anton-vinogradov anton-vinogradov commented Apr 30, 2026

Copy link
Copy Markdown
Contributor

What

Extends the annotation-driven message codegen (previously serialization-only) to
marshalling and deployment: a message's wire read/write, marshalling and
deployment are now generated from declarative field annotations, replacing
hand-written writeTo/readFrom, prepareMarshal/finishUnmarshal and prepareDeployment.

Main directions

  1. Generated marshaller & deployer companions. MessageProcessor now emits
    <Msg>Marshaller and <Msg>Deployer next to <Msg>Serializer, driven by
    @Marshalled / @MarshalledCollection / @MarshalledMap (with @Order /
    @NioField). Hand-written marshalling/deployment hooks are removed from messages.

  2. Uniform factory dispatch. MessageFactory resolves all three by direct type —
    serializer() / marshaller() / deployer() — via one
    register(directType, supplier, serializer, marshaller, deployer). Callers use the
    static facades MessageSerializer.writeTo/readFrom, MessageMarshaller.marshal/unmarshal,
    GridCacheMessageDeployer.deploy; an ArchUnit rule (MessageSerializationArchitectureTest)
    enforces it.

  3. Comm & discovery wired to it. GridIoManager / GridCacheIoManager /
    IgniteTxManager and the TCP/ZK discovery I/O call MessageMarshaller.marshal/unmarshal;
    discovery custom messages (MetadataUpdateProposedMessage, BinaryMetadataVersionInfo, …)
    move from MarshallableMessage hooks to @Marshalled.

  4. Deployment collapsed. GridCacheMessageDeployer is now only the codegen interface
    plus the factory-resolving facade; per-field static bridges dropped, GridCacheMessage#deploy*
    accessed directly.

  5. Marshalling stays off the NIO threads. The NIO codec does only serialization
    (writeTo/readFrom); the actual marshal/unmarshal runs on the sender and worker
    threads. @NioField + unmarshalNio are the explicit, minimal exception — only the
    handful of fields needed for early dispatch are unmarshalled on the NIO thread.

Side effects (mechanical — skim)

  • Rename to a consistent vocabulary (bulk of the diff, purely mechanical):
    • prepareMarshalmarshal, finishUnmarshalunmarshal,
      finishUnmarshalNiounmarshalNio (on MarshallableMessage / MessageMarshaller);
    • CacheObject#prepareMarshal(ctx) / finishUnmarshal(ctx)marshal / unmarshal;
    • deployment prepareDeployment + prepare*Deployment helpers → deploy / deploy*;
    • test renames: MarshallerCacheFreeFinishTest…UnmarshalTest,
      MessageFinishUnmarshalOnceTestMessageUnmarshalOnceTest.
  • Build/CI: .mvn/jvm.config opens jdk.compiler for the codegen tests
    (Google compile-testing); commit-check.yml now surfaces the real compile error
    behind the generated-class "cannot find symbol" cascade.

Performance

JMH-verified: serialization hot path unchanged (Δ ≈ 0 vs master); marshalling adds
~1.8 ns/message of factory dispatch (<0.5% of the actual U.marshal, ~µs); zero extra
allocations.

@sonarqubecloud

Copy link
Copy Markdown

Quality Gate Failed Quality Gate failed

Failed conditions
43 New Code Smells (required ≤ 1)

See analysis details on SonarQube Cloud

Catch issues before they fail your Quality Gate with our IDE extension SonarQube for IDE

Map<Class<?>, Short> REGISTRATIONS = new ConcurrentHashMap<>();

/** Per-class cache over {@link #REGISTRATIONS}; keeps {@link #directType()} off the map lookup done for every sent message. */
ClassValue<Short> DIRECT_TYPES = new ClassValue<>() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why changed? let's use just REGISTRATIONS.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The ClassValue isn't a rename, it's a cache with a contract: a plain REGISTRATIONS.get(getClass()) returns null for an unregistered class → NPE on unboxing, while DIRECT_TYPES throws UnknownMessageException, which production discovery (TcpDiscoverySpi, ServerImpl, TcpDiscoveryIoSession) catches for unknown-type tolerance and DiscoverySerializationExceptionTest covers.

import org.apache.ignite.plugin.extensions.communication.MessageWriter;

/** Serializer for {@link TestDelayMessage} that injects an optional write delay for testing. */
public class TestDelayMessageSerializer implements MessageSerializer<TestDelayMessage> {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

How it is used now?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's resolved by naming convention: MessagesPluginProvider registers TestDelayMessage with GridTestUtils.loadSerializer(msg), which loads this class. Codegen intentionally skips the message (SKIP_MESSAGES in MessageProcessor) because the hand-written serializer injects a write delay a generated one can't.

# Conflicts:
#	modules/codegen/src/main/java/org/apache/ignite/internal/MessageSerializerGenerator.java
#	modules/codegen/src/main/java/org/apache/ignite/internal/idto/IDTOSerializerGenerator.java
#	modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZkMessageFactory.java
#	modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoveryImpl.java
@anton-vinogradov

Copy link
Copy Markdown
Contributor Author

/runall

@github-actions

Copy link
Copy Markdown

Possible compatibility issues. Please, check rolling upgrade cases

This PR modifies protected classes (with Order annotation).
Changes to these classes can break rolling upgrade compatibility.

Affected files:

  • modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/GenericValueMessage.java
  • modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryStartRequest.java
  • modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryTxEntry.java
  • modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/ColocationGroup.java
  • modules/codegen/src/main/java/org/apache/ignite/internal/MessageProcessor.java
  • modules/codegen/src/main/java/org/apache/ignite/internal/idto/IDTOSerializerGenerator.java
  • modules/core/src/main/java/org/apache/ignite/internal/managers/communication/ErrorMessage.java
  • modules/core/src/main/java/org/apache/ignite/internal/managers/communication/GridIoMessage.java
  • modules/core/src/main/java/org/apache/ignite/internal/managers/communication/IgniteIoTestMessage.java
  • modules/core/src/main/java/org/apache/ignite/internal/managers/eventstorage/GridEventStorageMessage.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheEntryPredicateAdapter.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheInvokeDirectResult.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeRequest.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryInfo.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheIdMessage.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMessage.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheReturn.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/StoredCacheData.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/BinaryMetadataVersionInfo.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/MetadataUpdateProposedMessage.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheTtlUpdateRequest.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedLockRequest.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedLockResponse.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedTxPrepareRequest.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridNearUnlockRequest.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtLockRequest.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtLockResponse.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxFinishResponse.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareRequest.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareResponse.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtUnlockRequest.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/TransactionAttributesAwareRequest.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/AtomicApplicationAttributesAwareRequest.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicNearResponse.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicSingleUpdateRequest.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicUpdateRequest.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicUpdateResponse.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicFullUpdateRequest.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicSingleUpdateFilterRequest.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicSingleUpdateInvokeRequest.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicSingleUpdateRequest.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicUpdateResponse.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/UpdateErrors.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtForceKeysRequest.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtForceKeysResponse.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionSupplyMessage.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsFullMessage.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsSingleMessage.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/CacheVersionedValue.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetRequest.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetResponse.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearSingleGetRequest.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearSingleGetResponse.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxPrepareRequest.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxPrepareResponse.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/IncrementalSnapshotAwareMessage.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/IncrementalSnapshotVerifyResult.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryRequest.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryResponse.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryEntry.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxEntry.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxKey.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TxEntryValueHolder.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TxLocksRequest.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TxLocksResponse.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/PartitionHashRecord.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/TransactionsHashRecord.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/ChangeGlobalStateMessage.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/StartRequestData.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/datastreamer/DataStreamerRequest.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/metastorage/persistence/DistributedMetaStorageCasMessage.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/metastorage/persistence/DistributedMetaStorageUpdateMessage.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/plugin/PluginsDataBagItem.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/message/QueryEntityMessage.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/task/GridTaskResultResponse.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceDeploymentRequest.java
  • modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceSingleNodeDeploymentResult.java
  • modules/core/src/main/java/org/apache/ignite/spi/discovery/SerializableDataBagItemWrapper.java
  • modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/TcpDiscoveryNode.java
  • modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryAbstractTraceableMessage.java
  • modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryNodeAddFinishedMessage.java
  • modules/core/src/test/java/org/apache/ignite/internal/codegen/MessageProcessorTest.java
  • modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/TestDelayMessage.java
  • modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/ExploitMessage.java
  • modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/msg/GridH2CacheObject.java

@anton-vinogradov

anton-vinogradov commented Jul 17, 2026

Copy link
Copy Markdown
Contributor Author

Ignite PR Checker verdict · RunAll build 9216359 · 147 suites ran, 0 reused

⚠️ 1 broken suite(s) (no reliable run):

  • Platform C++ CMake (Win x64 | Release): IgniteCoreTest terminated abnormally - the test binary died, its remaining tests never ran · Number of tests 458 is 23% less than 595 in build #18333

🔍 2 suite(s) ran fewer tests than on master (tests that never ran can't fail):

  • Cache (Failover) 5: 33 tests vs 67 on master (−51%)
  • Platform C++ CMake (Win x64 | Release): 458 tests vs 595 on master (−23%)

✅ No test blockers otherwise; 26 pre-existing/flaky filtered out.

♻️ Settled after 2 auto re-run wave(s): #1 — 2 broken suite(s); #2 — 1 broken suite(s).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants