diff --git a/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/direct/JmhDirectMessageReaderBenchmark.java b/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/direct/JmhDirectMessageReaderBenchmark.java index e9b2a81f65815..e35091ec3cae7 100644 --- a/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/direct/JmhDirectMessageReaderBenchmark.java +++ b/modules/benchmarks/src/main/java/org/apache/ignite/internal/benchmarks/jmh/direct/JmhDirectMessageReaderBenchmark.java @@ -30,7 +30,6 @@ import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionsFullMessage; import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GroupPartitionIdPair; -import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.plugin.extensions.communication.MessageFactory; import org.apache.ignite.plugin.extensions.communication.MessageFactoryProvider; @@ -123,6 +122,6 @@ public Message compressedMessage() { /** */ private static MessageFactory msgFactory() { return new IgniteMessageFactoryImpl(new MessageFactoryProvider[]{ - new CoreMessagesProvider(jdk(), jdk(), U.gridClassLoader())}); + new CoreMessagesProvider(jdk(), jdk())}); } } diff --git a/modules/binary/api/src/main/java/org/apache/ignite/internal/processors/cache/CacheObject.java b/modules/binary/api/src/main/java/org/apache/ignite/internal/processors/cache/CacheObject.java index 09e7a8d5a0e91..845eb86e17402 100644 --- a/modules/binary/api/src/main/java/org/apache/ignite/internal/processors/cache/CacheObject.java +++ b/modules/binary/api/src/main/java/org/apache/ignite/internal/processors/cache/CacheObject.java @@ -120,13 +120,13 @@ public interface CacheObject { * @param ldr Class loader. * @throws IgniteCheckedException If failed. */ - public void finishUnmarshal(CacheObjectValueContext ctx, ClassLoader ldr) throws IgniteCheckedException; + public void unmarshal(CacheObjectValueContext ctx, ClassLoader ldr) throws IgniteCheckedException; /** * @param ctx Context. * @throws IgniteCheckedException If failed. */ - public void prepareMarshal(CacheObjectValueContext ctx) throws IgniteCheckedException; + public void marshal(CacheObjectValueContext ctx) throws IgniteCheckedException; /** * @return {@code True} if postWriteHashCode call required, {@code false} otherwise. diff --git a/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryEnumObjectImpl.java b/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryEnumObjectImpl.java index d61cab738b414..2024eef66e521 100644 --- a/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryEnumObjectImpl.java +++ b/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryEnumObjectImpl.java @@ -367,12 +367,12 @@ private T uncachedValue(Class cls) throws BinaryObjectException { } /** {@inheritDoc} */ - @Override public void finishUnmarshal(CacheObjectValueContext ctx, ClassLoader ldr) throws IgniteCheckedException { + @Override public void unmarshal(CacheObjectValueContext ctx, ClassLoader ldr) throws IgniteCheckedException { this.ctx = ctx.binaryContext(); } /** {@inheritDoc} */ - @Override public void prepareMarshal(CacheObjectValueContext ctx) throws IgniteCheckedException { + @Override public void marshal(CacheObjectValueContext ctx) throws IgniteCheckedException { // No-op. } diff --git a/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryObjectImpl.java b/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryObjectImpl.java index 50e85ff230899..7dd2bebdf86af 100644 --- a/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryObjectImpl.java +++ b/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryObjectImpl.java @@ -220,13 +220,13 @@ public BinaryObjectImpl(BinaryContext ctx, byte[] arr, int start) { @Override public CacheObject prepareForCache(CacheObjectValueContext ctx) { BinaryObjectImpl res = detached() ? this : detach(false); - res.prepareMarshal(ctx); + res.marshal(ctx); return res; } /** {@inheritDoc} */ - @Override public void finishUnmarshal(CacheObjectValueContext ctx, ClassLoader ldr) throws IgniteCheckedException { + @Override public void unmarshal(CacheObjectValueContext ctx, ClassLoader ldr) throws IgniteCheckedException { assert arr != null || valBytes != null; if (arr == null) @@ -238,7 +238,7 @@ public BinaryObjectImpl(BinaryContext ctx, byte[] arr, int start) { } /** {@inheritDoc} */ - @Override public void prepareMarshal(CacheObjectValueContext ctx) { + @Override public void marshal(CacheObjectValueContext ctx) { assert arr != null || valBytes != null; if (valBytes == null) diff --git a/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryObjectOffheapImpl.java b/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryObjectOffheapImpl.java index cce4f59dab7fe..e2ac1b89b4e42 100644 --- a/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryObjectOffheapImpl.java +++ b/modules/binary/impl/src/main/java/org/apache/ignite/internal/binary/BinaryObjectOffheapImpl.java @@ -453,12 +453,12 @@ else if (fieldOffLen == BinaryUtils.OFFSET_2) } /** {@inheritDoc} */ - @Override public void finishUnmarshal(CacheObjectValueContext ctx, ClassLoader ldr) throws IgniteCheckedException { + @Override public void unmarshal(CacheObjectValueContext ctx, ClassLoader ldr) throws IgniteCheckedException { throw new UnsupportedOperationException(); } /** {@inheritDoc} */ - @Override public void prepareMarshal(CacheObjectValueContext ctx) throws IgniteCheckedException { + @Override public void marshal(CacheObjectValueContext ctx) throws IgniteCheckedException { throw new UnsupportedOperationException(); } diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/CalciteErrorMessage.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/CalciteErrorMessage.java index 9d62635cc2285..d6f32fd195b69 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/CalciteErrorMessage.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/CalciteErrorMessage.java @@ -18,11 +18,12 @@ package org.apache.ignite.internal.processors.query.calcite.message; import java.util.UUID; +import org.apache.ignite.internal.DeferredUnmarshalMessage; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.managers.communication.ErrorMessage; /** */ -public class CalciteErrorMessage extends ErrorMessage { +public class CalciteErrorMessage extends ErrorMessage implements DeferredUnmarshalMessage { /** */ @Order(0) UUID qryId; diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/CalciteMessageFactory.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/CalciteMessageFactory.java index d15b5821e0597..c525c32b1f8e6 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/CalciteMessageFactory.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/CalciteMessageFactory.java @@ -17,41 +17,29 @@ package org.apache.ignite.internal.processors.query.calcite.message; +import org.apache.ignite.internal.managers.communication.IgniteMessageFactory; import org.apache.ignite.internal.plugin.AbstractMarshallableMessageFactoryProvider; import org.apache.ignite.internal.processors.query.calcite.metadata.ColocationGroup; import org.apache.ignite.internal.processors.query.calcite.metadata.FragmentDescription; import org.apache.ignite.internal.processors.query.calcite.metadata.FragmentMapping; -import org.apache.ignite.plugin.extensions.communication.Message; -import org.apache.ignite.plugin.extensions.communication.MessageFactory; /** * Message factory. */ public class CalciteMessageFactory extends AbstractMarshallableMessageFactoryProvider { - /** */ - public static final short MIN_MESSAGE_TYPE = 300; - - /** */ - public static final short MAX_MESSAGE_TYPE = 311; - /** {@inheritDoc} */ - @Override public void registerAll(MessageFactory factory) { - register(factory, QueryStartRequest.class, (short)300, schemaAwareMarsh, resolvedClsLdr); - register(factory, QueryStartResponse.class, (short)301, dfltMarsh, dftlClsLdr); - register(factory, CalciteErrorMessage.class, (short)302, dfltMarsh, resolvedClsLdr); - register(factory, QueryBatchMessage.class, (short)303, dfltMarsh, dftlClsLdr); - register(factory, QueryBatchAcknowledgeMessage.class, (short)304, dfltMarsh, dftlClsLdr); - register(factory, QueryInboxCloseMessage.class, (short)305, dfltMarsh, dftlClsLdr); - register(factory, QueryCloseMessage.class, (short)306, dfltMarsh, dftlClsLdr); - register(factory, GenericValueMessage.class, (short)307, schemaAwareMarsh, resolvedClsLdr); - register(factory, FragmentMapping.class, (short)308, dfltMarsh, dftlClsLdr); - register(factory, ColocationGroup.class, (short)309, dfltMarsh, dftlClsLdr); - register(factory, FragmentDescription.class, (short)310, dfltMarsh, dftlClsLdr); - register(factory, QueryTxEntry.class, (short)311, dfltMarsh, dftlClsLdr); - } - - /** */ - public static boolean isCalciteMessage(Message msg) { - return msg.directType() >= MIN_MESSAGE_TYPE && msg.directType() <= MAX_MESSAGE_TYPE; + @Override public void registerAll(IgniteMessageFactory factory) { + register(factory, QueryStartRequest.class, (short)300, QueryStartRequest::new, schemaAwareMarsh); + register(factory, QueryStartResponse.class, (short)301, QueryStartResponse::new, dfltMarsh); + register(factory, CalciteErrorMessage.class, (short)302, CalciteErrorMessage::new, dfltMarsh); + register(factory, QueryBatchMessage.class, (short)303, QueryBatchMessage::new, dfltMarsh); + register(factory, QueryBatchAcknowledgeMessage.class, (short)304, QueryBatchAcknowledgeMessage::new, dfltMarsh); + register(factory, QueryInboxCloseMessage.class, (short)305, QueryInboxCloseMessage::new, dfltMarsh); + register(factory, QueryCloseMessage.class, (short)306, QueryCloseMessage::new, dfltMarsh); + register(factory, GenericValueMessage.class, (short)307, GenericValueMessage::new, schemaAwareMarsh); + register(factory, FragmentMapping.class, (short)308, FragmentMapping::new, dfltMarsh); + register(factory, ColocationGroup.class, (short)309, ColocationGroup::new, dfltMarsh); + register(factory, FragmentDescription.class, (short)310, FragmentDescription::new, dfltMarsh); + register(factory, QueryTxEntry.class, (short)311, QueryTxEntry::new, dfltMarsh); } } diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/GenericValueMessage.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/GenericValueMessage.java index 40849bab6a73a..1f1c6b356e8ae 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/GenericValueMessage.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/GenericValueMessage.java @@ -48,13 +48,13 @@ public Object value() { } /** {@inheritDoc} */ - @Override public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { + @Override public void marshal(Marshaller marsh) throws IgniteCheckedException { if (val != null && serialized == null) serialized = U.marshal(marsh, val); } /** {@inheritDoc} */ - @Override public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { + @Override public void unmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { if (serialized != null && val == null) val = U.unmarshal(marsh, serialized, clsLdr); diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/MessageServiceImpl.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/MessageServiceImpl.java index 4c8a699ca9c68..477f91450ea9f 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/MessageServiceImpl.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/MessageServiceImpl.java @@ -23,16 +23,14 @@ import java.util.UUID; import java.util.concurrent.ThreadLocalRandom; import org.apache.ignite.IgniteCheckedException; -import org.apache.ignite.failure.FailureContext; -import org.apache.ignite.failure.FailureType; +import org.apache.ignite.internal.DeferredUnmarshalMessage; import org.apache.ignite.internal.GridKernalContext; import org.apache.ignite.internal.GridTopic; import org.apache.ignite.internal.IgniteClientDisconnectedCheckedException; 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.processors.cache.GridCacheSharedContext; -import org.apache.ignite.internal.processors.failure.FailureProcessor; +import org.apache.ignite.internal.managers.communication.MessageMarshalling; import org.apache.ignite.internal.processors.query.calcite.CalciteQueryProcessor; import org.apache.ignite.internal.processors.query.calcite.exec.QueryTaskExecutor; import org.apache.ignite.internal.processors.query.calcite.util.AbstractService; @@ -45,13 +43,10 @@ */ public class MessageServiceImpl extends AbstractService implements MessageService { /** */ - private final GridMessageListener msgLsnr; - - /** */ - private final GridCacheSharedContext ctx; + private final GridKernalContext kctx; /** */ - private final ClassLoader clsLdr; + private final GridMessageListener msgLsnr; /** */ private UUID locNodeId; @@ -62,9 +57,6 @@ public class MessageServiceImpl extends AbstractService implements MessageServic /** */ private QueryTaskExecutor taskExecutor; - /** */ - private FailureProcessor failureProc; - /** */ private Map, MessageListener> lsnrs; @@ -72,8 +64,7 @@ public class MessageServiceImpl extends AbstractService implements MessageServic public MessageServiceImpl(GridKernalContext ctx) { super(ctx); - this.ctx = ctx.cache().context(); - clsLdr = U.resolveClassLoader(ctx.config()); + kctx = ctx; ioMgr = ctx.io(); msgLsnr = this::onMessage; } @@ -113,20 +104,6 @@ public QueryTaskExecutor taskExecutor() { return taskExecutor; } - /** - * @param failureProc Failure processor. - */ - public void failureProcessor(FailureProcessor failureProc) { - this.failureProc = failureProc; - } - - /** - * @return Failure processor. - */ - public FailureProcessor failureProcessor() { - return failureProc; - } - /** {@inheritDoc} */ @Override public void onStart(GridKernalContext ctx) { localNodeId(ctx.localNodeId()); @@ -134,7 +111,6 @@ public FailureProcessor failureProcessor() { CalciteQueryProcessor proc = queryProcessor(ctx); taskExecutor(proc.taskExecutor()); - failureProcessor(proc.failureProcessor()); init(); } @@ -154,11 +130,8 @@ public FailureProcessor failureProcessor() { @Override public void send(UUID nodeId, Message msg) throws IgniteCheckedException { if (localNodeId().equals(nodeId)) onMessage(nodeId, msg); - else { - prepareMarshal(msg); - + else ioManager().sendToGridTopic(nodeId, GridTopic.TOPIC_QUERY, msg, GridIoPolicy.CALLER_THREAD); - } } /** {@inheritDoc} */ @@ -182,61 +155,50 @@ public FailureProcessor failureProcessor() { } /** */ - protected void prepareMarshal(Message msg) throws IgniteCheckedException { - try { - if (msg instanceof CalciteContextMarshallableMessage) - ((CalciteContextMarshallableMessage)msg).prepareMarshal(ctx); - } - catch (Exception e) { - failureProcessor().process(new FailureContext(FailureType.CRITICAL_ERROR, e)); - - throw e; - } + protected void onMessage(UUID nodeId, Message msg) { + onMessage(nodeId, msg, false); } - /** */ - protected void prepareUnmarshal(Message msg) throws IgniteCheckedException { - try { - if (msg instanceof CalciteContextMarshallableMessage) - ((CalciteContextMarshallableMessage)msg).finishUnmarshal(ctx, clsLdr); - } - catch (Exception e) { - failureProcessor().process(new FailureContext(FailureType.CRITICAL_ERROR, e)); - - throw e; - } + /** + * Listener for messages arriving from remote nodes. All Calcite messages are {@link DeferredUnmarshalMessage}s + * and the only ones on this topic: the generic {@code GridIoManager} payload pass skips them, so their payload + * is unmarshalled here, on the query task executor. + */ + private void onMessage(UUID nodeId, Object msg, byte plc) { + if (msg instanceof DeferredUnmarshalMessage) + onMessage(nodeId, (Message)msg, true); } /** */ - protected void onMessage(UUID nodeId, Message msg) { + private void onMessage(UUID nodeId, Message msg, boolean unmarshal) { if (msg instanceof ExecutionContextAware) { ExecutionContextAware msg0 = (ExecutionContextAware)msg; - taskExecutor().execute(msg0.queryId(), msg0.fragmentId(), () -> onMessageInternal(nodeId, msg)); + taskExecutor().execute(msg0.queryId(), msg0.fragmentId(), () -> onMessageInternal(nodeId, msg, unmarshal)); } else taskExecutor().execute( IgniteUuid.VM_ID, ThreadLocalRandom.current().nextLong(1024), - () -> onMessageInternal(nodeId, msg) + () -> onMessageInternal(nodeId, msg, unmarshal) ); } - /** */ - private void onMessage(UUID nodeId, Object msg, byte plc) { - if (msg instanceof Message && CalciteMessageFactory.isCalciteMessage((Message)msg)) - onMessage(nodeId, (Message)msg); - } + /** + * @param unmarshal Whether to unmarshal the payload: {@code true} only for remotely received messages; locally + * delivered ones were never marshalled. + */ + private void onMessageInternal(UUID nodeId, Message msg, boolean unmarshal) { + if (unmarshal) { + try { + MessageMarshalling.unmarshal(msg, kctx); + } + catch (IgniteCheckedException e) { + throw U.convertException(e); + } + } - /** */ - private void onMessageInternal(UUID nodeId, Message msg) { - try { - prepareUnmarshal(msg); + MessageListener lsnr = Objects.requireNonNull(lsnrs.get(msg.getClass())); - MessageListener lsnr = Objects.requireNonNull(lsnrs.get(msg.getClass())); - lsnr.onMessage(nodeId, msg); - } - catch (IgniteCheckedException e) { - throw U.convertException(e); - } + lsnr.onMessage(nodeId, msg); } } diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryBatchAcknowledgeMessage.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryBatchAcknowledgeMessage.java index acf2b31bedcb6..d482b0fc06549 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryBatchAcknowledgeMessage.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryBatchAcknowledgeMessage.java @@ -18,12 +18,13 @@ package org.apache.ignite.internal.processors.query.calcite.message; import java.util.UUID; +import org.apache.ignite.internal.DeferredUnmarshalMessage; import org.apache.ignite.internal.Order; /** * */ -public class QueryBatchAcknowledgeMessage implements ExecutionContextAware { +public class QueryBatchAcknowledgeMessage implements DeferredUnmarshalMessage, ExecutionContextAware { /** */ @Order(0) UUID qryId; diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryBatchMessage.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryBatchMessage.java index 487baff9fdca1..13f5faf5ced59 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryBatchMessage.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryBatchMessage.java @@ -17,13 +17,16 @@ package org.apache.ignite.internal.processors.query.calcite.message; +import java.util.ArrayList; import java.util.List; import java.util.UUID; -import java.util.stream.Collectors; +import org.apache.ignite.internal.DeferredUnmarshalMessage; +import org.apache.ignite.internal.MarshallableMessage; import org.apache.ignite.internal.Order; +import org.apache.ignite.marshaller.Marshaller; /** */ -public class QueryBatchMessage implements ExecutionContextAware { +public class QueryBatchMessage implements MarshallableMessage, DeferredUnmarshalMessage, ExecutionContextAware { /** */ @Order(0) UUID qryId; @@ -44,6 +47,9 @@ public class QueryBatchMessage implements ExecutionContextAware { @Order(4) boolean last; + /** */ + private List rows; + /** */ @Order(5) List mRows; @@ -60,8 +66,7 @@ public QueryBatchMessage(UUID qryId, long fragmentId, long exchangeId, int batch this.exchangeId = exchangeId; this.batchId = batchId; this.last = last; - - mRows = rows.stream().map(o -> o == null ? null : new GenericValueMessage(o)).collect(Collectors.toList()); + this.rows = rows; } /** {@inheritDoc} */ @@ -99,6 +104,29 @@ public boolean last() { * @return Rows. */ public List rows() { - return mRows.stream().map(GenericValueMessage::value).collect(Collectors.toList()); + return rows; + } + + /** {@inheritDoc} */ + @Override public void marshal(Marshaller marsh) { + if (mRows != null || rows == null) + return; + + mRows = new ArrayList<>(rows.size()); + + for (Object row : rows) + mRows.add(row == null ? null : new GenericValueMessage(row)); + } + + /** {@inheritDoc} */ + @Override public void unmarshal(Marshaller marsh, ClassLoader clsLdr) { + if (rows == null && mRows != null) { + rows = new ArrayList<>(mRows.size()); + + for (GenericValueMessage mRow : mRows) + rows.add(mRow == null ? null : mRow.value()); + } + + mRows = null; } } diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryCloseMessage.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryCloseMessage.java index 4972314aa0a41..90b0077877176 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryCloseMessage.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryCloseMessage.java @@ -18,13 +18,13 @@ package org.apache.ignite.internal.processors.query.calcite.message; import java.util.UUID; +import org.apache.ignite.internal.DeferredUnmarshalMessage; import org.apache.ignite.internal.Order; -import org.apache.ignite.plugin.extensions.communication.Message; /** * */ -public class QueryCloseMessage implements Message { +public class QueryCloseMessage implements DeferredUnmarshalMessage { /** */ @Order(0) UUID qryId; diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryInboxCloseMessage.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryInboxCloseMessage.java index 532c024d6573d..53c8ff6a516ac 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryInboxCloseMessage.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryInboxCloseMessage.java @@ -18,13 +18,13 @@ package org.apache.ignite.internal.processors.query.calcite.message; import java.util.UUID; +import org.apache.ignite.internal.DeferredUnmarshalMessage; import org.apache.ignite.internal.Order; -import org.apache.ignite.plugin.extensions.communication.Message; /** * */ -public class QueryInboxCloseMessage implements Message { +public class QueryInboxCloseMessage implements DeferredUnmarshalMessage { /** */ @Order(0) UUID qryId; diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryStartRequest.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryStartRequest.java index 15d34e00fbbfe..f3c6e5b9109cc 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryStartRequest.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryStartRequest.java @@ -21,19 +21,17 @@ import java.util.Map; import java.util.UUID; import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.DeferredUnmarshalMessage; import org.apache.ignite.internal.MarshallableMessage; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; -import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.processors.query.calcite.metadata.FragmentDescription; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.marshaller.Marshaller; import org.jetbrains.annotations.Nullable; -/** - * - */ -public class QueryStartRequest implements MarshallableMessage, CalciteContextMarshallableMessage, ExecutionContextAware { +/** Message sent to remote nodes to start a query fragment execution. */ +public class QueryStartRequest implements MarshallableMessage, DeferredUnmarshalMessage, ExecutionContextAware { /** */ @Order(0) String schema; @@ -215,32 +213,16 @@ public boolean keepBinaryMode() { } /** {@inheritDoc} */ - @Override public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { + @Override public void marshal(Marshaller marsh) throws IgniteCheckedException { if (paramsBytes == null && params != null) paramsBytes = U.marshal(marsh, params); } /** {@inheritDoc} */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - if (qryTxEntries != null) { - for (QueryTxEntry e : qryTxEntries) - e.prepareMarshal(ctx); - } - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { + @Override public void unmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { if (params == null && paramsBytes != null) params = U.unmarshal(marsh, paramsBytes, clsLdr); paramsBytes = null; } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader clsLdr) throws IgniteCheckedException { - if (qryTxEntries != null) { - for (QueryTxEntry e : qryTxEntries) - e.finishUnmarshal(ctx, clsLdr); - } - } } diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryStartResponse.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryStartResponse.java index afc9d7c78126e..0099086d1a96f 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryStartResponse.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryStartResponse.java @@ -18,15 +18,15 @@ package org.apache.ignite.internal.processors.query.calcite.message; import java.util.UUID; +import org.apache.ignite.internal.DeferredUnmarshalMessage; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.managers.communication.ErrorMessage; -import org.apache.ignite.plugin.extensions.communication.Message; import org.jetbrains.annotations.Nullable; /** * */ -public class QueryStartResponse implements Message { +public class QueryStartResponse implements DeferredUnmarshalMessage { /** */ @Order(0) UUID qryId; diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryTxEntry.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryTxEntry.java index 36f2d9dceee84..6f3e6e4b5afb9 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryTxEntry.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/message/QueryTxEntry.java @@ -20,15 +20,14 @@ import java.util.Collection; import java.util.Comparator; import java.util.function.Function; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.configuration.TransactionConfiguration; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.cache.CacheObject; -import org.apache.ignite.internal.processors.cache.CacheObjectContext; -import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.processors.query.calcite.exec.ExecutionContext; +import org.apache.ignite.plugin.extensions.communication.CacheIdAware; +import org.apache.ignite.plugin.extensions.communication.Message; /** * Class to pass to remote nodes transaction changes. @@ -38,7 +37,7 @@ * @see ExecutionContext#transactionChanges(int, int[], Function, Comparator) * @see QueryStartRequest#queryTransactionEntries() */ -public class QueryTxEntry implements CalciteContextMarshallableMessage { +public class QueryTxEntry implements Message, CacheIdAware { /** Cache id. */ @Order(0) int cacheId; @@ -75,8 +74,8 @@ public QueryTxEntry(int cacheId, KeyCacheObject key, CacheObject val, GridCacheV this.ver = ver; } - /** @return Cache id. */ - public int cacheId() { + /** {@inheritDoc} */ + @Override public int cacheId() { return cacheId; } @@ -94,24 +93,4 @@ public CacheObject value() { public GridCacheVersion version() { return ver; } - - /** {@inheritDoc} */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - CacheObjectContext coctx = ctx.cacheContext(cacheId).cacheObjectContext(); - - key.prepareMarshal(coctx); - - if (val != null) - val.prepareMarshal(coctx); - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - CacheObjectContext coctx = ctx.cacheContext(cacheId).cacheObjectContext(); - - key.finishUnmarshal(coctx, ldr); - - if (val != null) - val.finishUnmarshal(coctx, ldr); - } } diff --git a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/ColocationGroup.java b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/ColocationGroup.java index 7981d736953e2..e0b4738bceda0 100644 --- a/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/ColocationGroup.java +++ b/modules/calcite/src/main/java/org/apache/ignite/internal/processors/query/calcite/metadata/ColocationGroup.java @@ -314,8 +314,8 @@ public int[] partitions(UUID nodeId) { } /** {@inheritDoc} */ - @Override public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { - if (assignments == null || primaryAssignment) + @Override public void marshal(Marshaller marsh) throws IgniteCheckedException { + if (!F.isEmpty(marshalledAssignments) || assignments == null || primaryAssignment) return; Map nodeIdxs = new HashMap<>(); @@ -343,7 +343,7 @@ public int[] partitions(UUID nodeId) { } /** {@inheritDoc} */ - @Override public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { + @Override public void unmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { if (F.isEmpty(marshalledAssignments)) return; diff --git a/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/message/CalciteMessageUnmarshalThreadIntegrationTest.java b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/message/CalciteMessageUnmarshalThreadIntegrationTest.java new file mode 100644 index 0000000000000..9b7fd8e9c9cdb --- /dev/null +++ b/modules/calcite/src/test/java/org/apache/ignite/internal/processors/query/calcite/message/CalciteMessageUnmarshalThreadIntegrationTest.java @@ -0,0 +1,94 @@ +/* + * 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.processors.query.calcite.message; + +import java.io.IOException; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.io.Serializable; +import java.util.List; +import java.util.Queue; +import java.util.concurrent.ConcurrentLinkedQueue; +import org.apache.ignite.internal.processors.query.calcite.exec.task.AbstractQueryTaskExecutor; +import org.apache.ignite.internal.processors.query.calcite.integration.AbstractBasicIntegrationTest; +import org.junit.Test; + +import static java.util.stream.Collectors.toList; + +/** + * Verifies that payload of calcite messages is unmarshalled on the query task executor, not on a NIO thread: probe + * objects travel as {@code QueryStartRequest} parameters and as {@code QueryBatchMessage} rows, and record the thread + * that deserializes them. + */ +public class CalciteMessageUnmarshalThreadIntegrationTest extends AbstractBasicIntegrationTest { + /** */ + private static final int ROWS = 200; + + /** Names of the threads that deserialized a {@link Probe}. */ + private static final Queue unmarshalThreads = new ConcurrentLinkedQueue<>(); + + /** {@inheritDoc} */ + @Override protected int nodeCount() { + return 2; + } + + /** */ + @Test + public void testPayloadUnmarshalledOnQueryExecutor() { + sql("CREATE TABLE t(id INT PRIMARY KEY, oth OTHER)"); + + for (int i = 0; i < ROWS; i++) + sql("INSERT INTO t VALUES (?, ?)", i, new Probe()); + + unmarshalThreads.clear(); + + List> res = sql("SELECT id, oth FROM t WHERE oth != ?", new Probe()); + + assertEquals(ROWS, res.size()); + + assertFalse("No probe deserialization recorded", unmarshalThreads.isEmpty()); + + List nioThreads = unmarshalThreads.stream().filter(t -> t.contains("nio")).collect(toList()); + + assertTrue("Message payload unmarshalled on NIO threads: " + nioThreads, nioThreads.isEmpty()); + + assertTrue("No probe deserialization on the query task executor: " + unmarshalThreads, + unmarshalThreads.stream().anyMatch(t -> t.startsWith(AbstractQueryTaskExecutor.THREAD_PREFIX))); + } + + /** + * Records the name of the thread deserializing it. The custom {@code writeObject}/{@code readObject} pair also + * routes the class through {@code OptimizedMarshaller}, so the hook is invoked on every unmarshal. + */ + private static class Probe implements Serializable { + /** */ + private static final long serialVersionUID = 0L; + + /** */ + private void writeObject(ObjectOutputStream out) throws IOException { + out.defaultWriteObject(); + } + + /** */ + private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { + in.defaultReadObject(); + + unmarshalThreads.add(Thread.currentThread().getName()); + } + } +} diff --git a/modules/calcite/src/test/java/org/apache/ignite/testsuites/IntegrationTestSuite.java b/modules/calcite/src/test/java/org/apache/ignite/testsuites/IntegrationTestSuite.java index b965adf193dc1..e392d7c78bb38 100644 --- a/modules/calcite/src/test/java/org/apache/ignite/testsuites/IntegrationTestSuite.java +++ b/modules/calcite/src/test/java/org/apache/ignite/testsuites/IntegrationTestSuite.java @@ -90,6 +90,7 @@ import org.apache.ignite.internal.processors.query.calcite.integration.tpch.TpchScale001Test; import org.apache.ignite.internal.processors.query.calcite.integration.tpch.TpchScale010Test; import org.apache.ignite.internal.processors.query.calcite.integration.tpch.TpchScale100Test; +import org.apache.ignite.internal.processors.query.calcite.message.CalciteMessageUnmarshalThreadIntegrationTest; import org.apache.ignite.internal.processors.query.calcite.rules.JoinCommuteRulesTest; import org.apache.ignite.internal.processors.query.calcite.rules.JoinOrderOptimizationTest; import org.apache.ignite.internal.processors.query.calcite.rules.OrToUnionRuleTest; @@ -185,6 +186,7 @@ TxThreadLockingTest.class, SelectByKeyFieldTest.class, WindowIntegrationTest.class, + CalciteMessageUnmarshalThreadIntegrationTest.class, }) public class IntegrationTestSuite { } diff --git a/modules/codegen/src/main/java/org/apache/ignite/internal/Marshalled.java b/modules/codegen/src/main/java/org/apache/ignite/internal/Marshalled.java new file mode 100644 index 0000000000000..62526f4e03906 --- /dev/null +++ b/modules/codegen/src/main/java/org/apache/ignite/internal/Marshalled.java @@ -0,0 +1,49 @@ +/* + * 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 java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Links a message field to its wire form, held in the companion field(s) this annotation names. The marshalling + * flavour is derived from the companion's shape: + *
    + *
  • {@code byte[]} — the whole object is a single marshaller blob;
  • + *
  • {@code Message[]} — per-element {@code Message} serialization, the collection is rebuilt on unmarshal;
  • + *
  • {@code Collection} — per-element marshaller blobs, each element keeping its own class loader;
  • + *
  • {@link #keys()}/{@link #values()} instead of {@link #value()} — a {@code Map} serialized as two parallel + * wire fields.
  • + *
+ * + * @see Order + */ +@Retention(RetentionPolicy.CLASS) +@Target(ElementType.FIELD) +public @interface Marshalled { + /** Name of the companion wire field. Mutually exclusive with {@link #keys()}/{@link #values()}. */ + String value() default ""; + + /** Name of the map-keys companion wire field; requires {@link #values()}. */ + String keys() default ""; + + /** Name of the map-values companion wire field; requires {@link #keys()}. */ + String values() default ""; +} diff --git a/modules/codegen/src/main/java/org/apache/ignite/internal/MessageDeploymentGenerator.java b/modules/codegen/src/main/java/org/apache/ignite/internal/MessageDeploymentGenerator.java new file mode 100644 index 0000000000000..7069410af42aa --- /dev/null +++ b/modules/codegen/src/main/java/org/apache/ignite/internal/MessageDeploymentGenerator.java @@ -0,0 +1,247 @@ +/* + * 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 java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.List; +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.WildcardType; +import org.jetbrains.annotations.Nullable; + +import static org.apache.ignite.internal.MessageProcessor.CACHE_OBJECT_CLS; + +/** + * Generates a {@code *Deployer} class for messages whose {@code @Order} fields have a type that indicates deployment + * need: {@code CacheObject} subtypes, {@code Collection}, {@code Iterable}, or a + * nested {@code GridCacheMessage} (whose deployment is delegated). The strategy is inferred entirely from the field type. + * + *

A message with deployment logic that cannot be inferred from field types implements {@code DeployableMessage}; + * the generated deployer then also delegates to its {@code deploy}, mirroring {@code marshal}. + */ +public class MessageDeploymentGenerator extends MessageGenerator { + /** */ + private final TypeMirror gridCacheMsgType; + + /** */ + private final TypeMirror deployableMsgType; + + /** */ + private final TypeMirror cacheObjType; + + /** */ + private final TypeMirror txEntryType; + + /** */ + private final TypeMirror colType; + + /** */ + private final TypeMirror iterableType; + + /** Accumulated source lines for the generated {@code GridCacheMessageDeployer#deploy} implementation. */ + private final List deploy = new ArrayList<>(); + + /** */ + private boolean needsCctx; + + /** */ + MessageDeploymentGenerator(ProcessingEnvironment env) { + super(env); + + gridCacheMsgType = type("org.apache.ignite.internal.processors.cache.GridCacheMessage"); + deployableMsgType = type("org.apache.ignite.internal.processors.cache.DeployableMessage"); + cacheObjType = type(CACHE_OBJECT_CLS); + txEntryType = type("org.apache.ignite.internal.processors.cache.transactions.IgniteTxEntry"); + colType = erasedType(type("java.util.Collection")); + iterableType = erasedType(type("java.lang.Iterable")); + } + + /** {@inheritDoc} */ + @Override String typeSuffix() { + return "Deployer"; + } + + /** {@inheritDoc} */ + @Override boolean shouldSkip(TypeElement type, List fields) { + if (gridCacheMsgType == null || !assignableFrom(type.asType(), gridCacheMsgType)) + return true; + + // Generate when the message carries custom deployment logic... + if (hasCustomDeployment(type)) + return false; + + // ...or has any field whose deployment can be inferred from its type. + for (VariableElement f : fields) { + if (deployKind(f) != null) + return false; + } + + return true; + } + + /** @return {@code true} if {@code type} implements {@code DeployableMessage} (has hand-written {@code deploy}). */ + private boolean hasCustomDeployment(TypeElement type) { + return deployableMsgType != null && assignableFrom(type.asType(), deployableMsgType); + } + + /** {@inheritDoc} */ + @Override void generateBody(List fields) { + emitMethod(deploy, "deploy(" + simpleNameWithGeneric(type) + " msg, GridCacheSharedContext ctx)", body -> { + List fieldStmts = new ArrayList<>(); + + for (VariableElement field : fields) { + DeployKind kind = deployKind(field); + + if (kind == null) + continue; + + needsCctx |= kind.needsCctx; + + appendBlock(fieldStmts, List.of(indentedLine(kind.stmt, fieldAccessor(field)))); + } + + if (needsCctx) { + body.add(indentedLine(cctxResolutionLine())); + body.add(EMPTY); + } + + body.addAll(fieldStmts); + + // Delegate the non-inferable part to the message's own deploy, mirroring msg.marshal(). + if (hasCustomDeployment(type)) { + if (!fieldStmts.isEmpty()) + body.add(EMPTY); + + body.add(indentedLine("msg.deploy(ctx);")); + } + }); + } + + /** {@inheritDoc} */ + @Override String buildClassCode(String deployerClsName) throws IOException { + try (Writer writer = new StringWriter()) { + imports.add(type.toString()); + imports.add("org.apache.ignite.IgniteCheckedException"); + imports.add("org.apache.ignite.internal.processors.cache.GridCacheMessageDeployer"); + imports.add("org.apache.ignite.internal.processors.cache.GridCacheSharedContext"); + + if (needsCctx) + imports.add("org.apache.ignite.internal.processors.cache.GridCacheContext"); + + writeClassHeader(writer, "GridCacheMessageDeployer", deployerClsName); + + writer.write(" {" + NL); + + for (String line : deploy) + writer.write(line + NL); + + writer.write("}"); + + return writer.toString(); + } + } + + /** Returns the line that resolves {@code cctx} from {@code ctx} based on the message type hierarchy. */ + private String cctxResolutionLine() { + if (isCacheIdAwareMessage(type)) + return "GridCacheContext cctx = ctx.cacheContext(msg.cacheId());"; + + throw new IllegalStateException("Cannot resolve cache context for " + type.getQualifiedName() + + ": CacheObject deployment fields are supported for CacheIdAware messages only."); + } + + /** Returns the deployment strategy for {@code field} based on its Java type, or {@code null} if not deployable. */ + private @Nullable DeployKind deployKind(VariableElement field) { + TypeMirror fieldType = field.asType(); + + if (fieldType.getKind() == TypeKind.ARRAY || fieldType.getKind().isPrimitive()) + return null; + + if (assignableFrom(fieldType, cacheObjType)) + return DeployKind.CACHE_OBJECT; + + if (!(fieldType instanceof DeclaredType)) + return null; + + List args = ((DeclaredType)fieldType).getTypeArguments(); + TypeMirror erased = erasedType(fieldType); + + if (!args.isEmpty()) { + TypeMirror elemType = erasedType(elementBound(args.get(0))); + + if (assignableFrom(erased, colType) + && assignableFrom(elemType, cacheObjType)) + return DeployKind.CACHE_OBJECTS; + + if (txEntryType != null && iterableType != null + && assignableFrom(erased, iterableType) + && env.getTypeUtils().isSameType(elemType, txEntryType)) + return DeployKind.TX_ENTRIES; + } + + // A nested message field delegates its own deployment (a no-op when that message has no deployer). + if (gridCacheMsgType != null && assignableFrom(fieldType, gridCacheMsgType)) + return DeployKind.NESTED; + + return null; + } + + /** Unwraps the upper bound of a wildcard type; returns the type as-is for non-wildcards. */ + private TypeMirror elementBound(TypeMirror arg) { + if (arg instanceof WildcardType) { + TypeMirror bound = ((WildcardType)arg).getExtendsBound(); + return bound != null ? bound : arg; + } + + return arg; + } + + /** Deployment strategy inferred from a field's type. */ + private enum DeployKind { + /** Single {@code CacheObject} field. */ + CACHE_OBJECT("msg.deployCacheObject(%s, cctx);", true), + + /** {@code Collection} of {@code CacheObject}s. */ + CACHE_OBJECTS("msg.deployCacheObjects(%s, cctx);", true), + + /** {@code Iterable}. */ + TX_ENTRIES("msg.deployTx(%s, ctx);", false), + + /** Nested {@code GridCacheMessage} delegating its own deployment. */ + NESTED("GridCacheMessageDeployer.deploy(ctx.kernalContext().messageFactory(), %s, ctx);", false); + + /** Statement template with {@code %s} placeholder for the field accessor. */ + private final String stmt; + + /** Whether the statement requires the resolved {@code cctx}. */ + private final boolean needsCctx; + + /** */ + DeployKind(String stmt, boolean needsCctx) { + this.stmt = stmt; + this.needsCctx = needsCctx; + } + } +} diff --git a/modules/codegen/src/main/java/org/apache/ignite/internal/MessageGenerator.java b/modules/codegen/src/main/java/org/apache/ignite/internal/MessageGenerator.java new file mode 100644 index 0000000000000..411dccef9fe05 --- /dev/null +++ b/modules/codegen/src/main/java/org/apache/ignite/internal/MessageGenerator.java @@ -0,0 +1,289 @@ +/* + * 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 java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStream; +import java.io.InputStreamReader; +import java.io.PrintWriter; +import java.io.Reader; +import java.io.Writer; +import java.util.ArrayList; +import java.util.Collections; +import java.util.LinkedHashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.TreeSet; +import java.util.function.Consumer; +import java.util.stream.Collectors; +import javax.annotation.processing.FilerException; +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.ElementFilter; +import javax.lang.model.util.Elements; +import javax.tools.Diagnostic; +import javax.tools.FileObject; +import javax.tools.JavaFileObject; +import javax.tools.StandardLocation; +import org.apache.ignite.internal.systemview.SystemViewRowAttributeWalkerProcessor; + +/** + * Base class for message code generators ({@link MessageSerializerGenerator}, {@link MessageMarshallerGenerator}, + * {@link MessageDeploymentGenerator}). + */ +public abstract class MessageGenerator { + /** Blank separator line in generated code. */ + public static final String EMPTY = ""; + + /** Platform line separator used in generated code. */ + public static final String NL = System.lineSeparator(); + + /** Single indentation unit. */ + public static final String TAB = " "; + + /** Javadoc stub emitted on every generated {@code @Override} method. */ + public static final String METHOD_JAVADOC = "/** */"; + + /** Javadoc block emitted on every generated class. */ + public static final String CLS_JAVADOC = "/**" + NL + + " * This class is generated automatically." + NL + + " *" + NL + + " * @see " + MessageProcessor.class.getName() + NL + + " */"; + + /** */ + protected final ProcessingEnvironment env; + + /** */ + protected final Set imports = new TreeSet<>(); + + /** */ + protected TypeElement type; + + /** Current indentation level. Set to the class-member level once in {@link #generate}; adjusted only by balanced shifts. */ + protected int indent; + + /** Dispatches cache-object-context resolution in both the marshaller and the deployment generators. */ + protected final TypeMirror cacheIdAwareType; + + /** */ + MessageGenerator(ProcessingEnvironment env) { + this.env = env; + + cacheIdAwareType = type("org.apache.ignite.plugin.extensions.communication.CacheIdAware"); + } + + /** */ + boolean isCacheIdAwareMessage(TypeElement te) { + return assignableFrom(te.asType(), cacheIdAwareType); + } + + /** Generates and writes the source file for {@code type}; skipped when {@link #shouldSkip} returns {@code true}. */ + final void generate(TypeElement type, List fields) throws Exception { + assert this.type == null : "Message" + typeSuffix() + " generator isn't stateless and is supposed to be single-use."; + + if (shouldSkip(type, fields)) + return; + + this.type = type; + + indent = 1; + + generateBody(fields); + + String clsName = type.getSimpleName() + typeSuffix(); + String fqnClsName = env.getElementUtils().getPackageOf(type) + "." + clsName; + String code = buildClassCode(clsName); + + if (code == null) + return; + + try { + JavaFileObject file = env.getFiler().createSourceFile(fqnClsName); + + try (Writer writer = file.openWriter()) { + writer.append(code); + writer.flush(); + } + } + catch (FilerException e) { + if (!identicalFileIsAlreadyGenerated(env, code, fqnClsName)) { + env.getMessager().printMessage(Diagnostic.Kind.ERROR, + "Message" + typeSuffix() + " " + clsName + " is already generated. Try 'mvn clean install' to fix the issue."); + + throw e; + } + } + } + + /** @return Class name suffix: {@code "Serializer"} or {@code "Marshaller"}. */ + abstract String typeSuffix(); + + /** @return {@code true} if no file should be generated for this type; default is {@code false}. */ + boolean shouldSkip(TypeElement type, List fields) { + return false; + } + + /** Populates internal state (method body lines etc.) from {@code fields}; called before {@link #buildClassCode}. */ + abstract void generateBody(List fields) throws Exception; + + /** Generates and returns the complete source code for the generated class, or {@code null} to skip the class. */ + abstract String buildClassCode(String clsName) throws IOException; + + /** */ + public static void writeLicense(Writer writer) throws IOException { + try (InputStream in = MessageGenerator.class.getClassLoader().getResourceAsStream("license.txt"); + BufferedReader reader = new BufferedReader(new InputStreamReader(in))) { + + PrintWriter out = new PrintWriter(writer); + String line; + + while ((line = reader.readLine()) != null) + out.println(line); + } + } + + /** Writes license, package, imports, javadoc, and class declaration; {@link #imports} must be populated before calling. */ + void writeClassHeader(Writer writer, String interfaceName, String clsName) throws IOException { + writeLicense(writer); + + writer.write(NL); + writer.write("package " + env.getElementUtils().getPackageOf(type) + ";" + NL + NL); + + for (String imp : imports) + writer.write("import " + imp + ";" + NL); + + writer.write(NL); + writer.write(CLS_JAVADOC); + writer.write(NL); + writer.write("public class " + clsName + " implements " + interfaceName + "<" + simpleNameWithGeneric(type) + ">"); + } + + /** @return {@code format} formatted with {@code args}, prefixed with {@link #indent} tabs. */ + String indentedLine(String format, Object... args) { + return TAB.repeat(indent) + String.format(format, args); + } + + /** @return simple name of {@code te} with {@code } wildcard type arguments appended when parameterised. */ + String simpleNameWithGeneric(TypeElement te) { + int paramsCnt = te.getTypeParameters().size(); + + return paramsCnt == 0 + ? te.getSimpleName().toString() + : te.getSimpleName() + "<" + String.join(", ", Collections.nCopies(paramsCnt, "?")) + ">"; + } + + /** */ + boolean assignableFrom(TypeMirror type, TypeMirror superType) { + return superType != null && env.getTypeUtils().isAssignable(type, superType); + } + + /** @return the {@link TypeMirror} for the fully-qualified {@code clazz}, or {@code null} if not on classpath. */ + TypeMirror type(String clazz) { + Elements elementUtils = env.getElementUtils(); + TypeElement typeElement = elementUtils.getTypeElement(clazz); + return typeElement != null ? typeElement.asType() : null; + } + + /** */ + TypeMirror erasedType(TypeMirror type) { + return env.getTypeUtils().erasure(type); + } + + /** @return {@code "msg."} accessor expression for {@code field}. */ + String fieldAccessor(VariableElement field) { + return "msg." + field.getSimpleName().toString(); + } + + /** Returns fields of {@link #type} and all its superclasses, subclass-first; a subclass field shadows an inherited one. */ + protected Map enclosedFields() { + Map result = new LinkedHashMap<>(); + + SystemViewRowAttributeWalkerProcessor.superclasses(env, type).forEach(c -> { + for (VariableElement f : ElementFilter.fieldsIn(c.getEnclosedElements())) + result.putIfAbsent(f.getSimpleName().toString(), f); + }); + + return result; + } + + /** Appends {@code block} to {@code body}, inserting a blank-line separator when {@code body} is non-empty. */ + protected static void appendBlock(List body, List block) { + if (!body.isEmpty()) + body.add(EMPTY); + + body.addAll(block); + } + + /** + * Emits an {@code @Override public void throws IgniteCheckedException} method into {@code target}: a + * leading blank separator, the {@link #METHOD_JAVADOC} stub, the signature line, and the indented body produced by + * {@code bodyBuilder}. + * + * @return {@code true} if {@code bodyBuilder} produced any body lines, {@code false} for an empty method. + */ + protected boolean emitMethod(List target, String signature, Consumer> bodyBuilder) { + if (!target.isEmpty()) + target.add(EMPTY); + + target.add(indentedLine(METHOD_JAVADOC)); + target.add(indentedLine("@Override public void " + signature + " throws IgniteCheckedException {")); + + indent++; + + List body = new ArrayList<>(); + bodyBuilder.accept(body); + target.addAll(body); + + indent--; + + target.add(indentedLine("}")); + + return !body.isEmpty(); + } + + /** @return {@code true} if a file with identical content is already generated (e.g. during incremental build). */ + public static boolean identicalFileIsAlreadyGenerated(ProcessingEnvironment env, String srcCode, String fqnClsName) { + try { + String fileName = fqnClsName.replace('.', '/') + ".java"; + FileObject prevFile = env.getFiler().getResource(StandardLocation.SOURCE_OUTPUT, "", fileName); + + String prevFileContent; + try (Reader r = prevFile.openReader(true)) { + prevFileContent = content(r); + } + + if (prevFileContent.contentEquals(srcCode)) + return true; + } + catch (Exception ignoredAttemptToGetExistingFile) { + // We have some other problem, not an existing file. + } + + return false; + } + + /** */ + static String content(Reader reader) { + return new BufferedReader(reader).lines().collect(Collectors.joining(NL)); + } +} diff --git a/modules/codegen/src/main/java/org/apache/ignite/internal/MessageMarshallerGenerator.java b/modules/codegen/src/main/java/org/apache/ignite/internal/MessageMarshallerGenerator.java new file mode 100644 index 0000000000000..cadf735530615 --- /dev/null +++ b/modules/codegen/src/main/java/org/apache/ignite/internal/MessageMarshallerGenerator.java @@ -0,0 +1,1180 @@ +/* + * 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 java.io.IOException; +import java.io.StringWriter; +import java.io.Writer; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.BiFunction; +import javax.annotation.processing.ProcessingEnvironment; +import javax.lang.model.element.Element; +import javax.lang.model.element.Modifier; +import javax.lang.model.element.QualifiedNameable; +import javax.lang.model.element.TypeElement; +import javax.lang.model.element.VariableElement; +import javax.lang.model.type.ArrayType; +import javax.lang.model.type.DeclaredType; +import javax.lang.model.type.TypeKind; +import javax.lang.model.type.TypeMirror; +import javax.lang.model.type.TypeVariable; +import javax.lang.model.util.ElementFilter; +import javax.tools.Diagnostic; +import org.apache.ignite.internal.systemview.SystemViewRowAttributeWalkerProcessor; +import org.jetbrains.annotations.Nullable; + +import static org.apache.ignite.internal.MessageProcessor.CACHE_OBJECT_CLS; +import static org.apache.ignite.internal.MessageProcessor.KEY_CACHE_OBJECT_CLS; +import static org.apache.ignite.internal.MessageProcessor.MARSHALLABLE_MESSAGE_INTERFACE; +import static org.apache.ignite.internal.MessageProcessor.MESSAGE_INTERFACE; +import static org.apache.ignite.internal.MessageProcessor.NON_MARSHALLABLE_MESSAGE_INTERFACE; + +/** + * Generates {@code *Marshaller} classes for {@code Message} types that are not {@code NonMarshallableMessage}. + */ +public class MessageMarshallerGenerator extends MessageGenerator { + /** Accumulated source lines for all generated marshal/unmarshal methods. */ + private final List marshall = new ArrayList<>(); + + /** */ + private final TypeMirror marshallableMsgType; + + /** */ + private final TypeMirror msgType; + + /** */ + private final TypeMirror cacheObjType; + + /** */ + private final TypeMirror nonMarshallableType; + + /** */ + private final TypeMirror cacheGrpIdMsgType; + + /** */ + private final TypeMirror mapType; + + /** */ + private final TypeMirror colType; + + /** */ + private boolean marshallable; + + /** */ + private boolean hasMarshalled; + + /** Whether any generated method got a non-empty body; a marshaller without one is skipped entirely. */ + private boolean hasStatements; + + /** Enclosed fields of the currently processed type. Computed once per {@link #generateBody} call. */ + private Map enclosed; + + /** {@link MarshalledKind} of each {@code @Marshalled} enclosed field. Computed once per {@link #generateBody} call. */ + private final Map kinds = new HashMap<>(); + + /** Nesting depth of the current marshal for-loop; names loop variables {@code e}, {@code e1}, {@code e2}… */ + private int loopDepth; + + /** Whether the currently generated method emitted a loop-nested facade call and so needs the {@code msgFactory} local. */ + private boolean usesMsgFactory; + + /** */ + MessageMarshallerGenerator(ProcessingEnvironment env) { + super(env); + + marshallableMsgType = type(MARSHALLABLE_MESSAGE_INTERFACE); + msgType = type(MESSAGE_INTERFACE); + cacheObjType = type(CACHE_OBJECT_CLS); + nonMarshallableType = type(NON_MARSHALLABLE_MESSAGE_INTERFACE); + cacheGrpIdMsgType = type("org.apache.ignite.internal.processors.cache.GridCacheGroupIdMessage"); + mapType = type("java.util.Map"); + colType = type("java.util.Collection"); + } + + /** {@inheritDoc} */ + @Override String typeSuffix() { + return "Marshaller"; + } + + /** {@inheritDoc} */ + @Override boolean shouldSkip(TypeElement type, List fields) { + return isNonMarshallableMessage(type); + } + + /** {@inheritDoc} */ + @Override void generateBody(List fields) throws Exception { + enclosed = enclosedFields(); + + for (VariableElement f : enclosed.values()) { + MarshalledKind kind = marshalledKind(f); + + if (kind != null) + kinds.put(f, kind); + } + + marshallable = marshallableMsgType != null && assignableFrom(type.asType(), marshallableMsgType); + hasMarshalled = kinds.values().stream().anyMatch(k -> k == MarshalledKind.BLOB || k == MarshalledKind.ELEMENT_BLOBS); + + generateMarshalMethod(fields); + generateUnmarshalMethods(fields); + } + + /** {@inheritDoc} */ + @Override String buildClassCode(String marshallerClsName) throws IOException { + if (!hasStatements) + return null; + + try (Writer writer = new StringWriter()) { + imports.add(type.toString()); + imports.add("org.apache.ignite.plugin.extensions.communication.MessageMarshaller"); + + if (marshallable || hasMarshalled) + imports.add("org.apache.ignite.marshaller.Marshaller"); + + writeClassHeader(writer, "MessageMarshaller", marshallerClsName); + + writer.write(" {" + NL); + + writeConstructor(writer, marshallerClsName); + + for (String line : marshall) + writer.write(line + NL); + + writer.write("}"); + + return writer.toString(); + } + } + + /** Writes the {@code marshaller} field and the constructor initializing it, when the marshaller is needed. */ + private void writeConstructor(Writer writer, String marshallerClsName) throws IOException { + if (!marshallable && !hasMarshalled) + return; + + writer.write(indentedLine(METHOD_JAVADOC)); + writer.write(NL); + writer.write(indentedLine("private final Marshaller marshaller;")); + writer.write(NL + NL); + + writer.write(indentedLine(METHOD_JAVADOC)); + writer.write(NL); + writer.write(indentedLine("public " + marshallerClsName + "(Marshaller marshaller) {")); + writer.write(NL); + + indent++; + + writer.write(indentedLine("this.marshaller = marshaller;")); + writer.write(NL); + + indent--; + + writer.write(indentedLine("}")); + writer.write(NL + NL); + } + + /** Generates the {@code marshal} method body and appends it to {@link #marshall}. */ + private void generateMarshalMethod(List orderedFields) { + imports.add("org.apache.ignite.IgniteCheckedException"); + imports.add("org.apache.ignite.internal.GridKernalContext"); + imports.add("org.apache.ignite.internal.processors.cache.CacheObjectContext"); + + String signature = "marshal(" + simpleNameWithGeneric(type) + " msg, GridKernalContext kctx, CacheObjectContext cacheObjCtx)"; + + hasStatements |= emitMethod(marshall, signature, body -> { + usesMsgFactory = false; + + if (needsCtx(orderedFields)) + appendBlock(body, List.of(ctxResolutionLine())); + + appendMarshalledFieldsPrepare(body); + appendMarshalledPrepare(body); + + if (marshallable) + appendBlock(body, List.of(indentedLine("msg.marshal(marshaller);"))); + + appendFields(body, orderedFields, MarshalMode.MARSHAL); + + prependMsgFactoryResolution(body); + }); + } + + /** Generates all {@code unmarshal} overloads and appends them to {@link #marshall}. */ + private void generateUnmarshalMethods(List orderedFields) { + List nioFields = new ArrayList<>(); + List workerFields = new ArrayList<>(); + + for (VariableElement f : orderedFields) { + boolean nioField = isNioField(f); + + if (nioField && isMessage(f.asType()) && !nestedNeedsCtx(f.asType())) + nioFields.add(f); + else { + if (nioField && !isMessage(f.asType())) + env.getMessager().printMessage(Diagnostic.Kind.ERROR, + "@NioField has no effect on non-Message field '" + f.getSimpleName() + "' of type " + f.asType(), f); + else if (nioField) + env.getMessager().printMessage(Diagnostic.Kind.ERROR, + "@NioField field '" + f.getSimpleName() + "' of type " + f.asType() + " needs a cache object " + + "context to unmarshal, but the NIO thread has none; only context-free messages may be @NioField", f); + + workerFields.add(f); + } + } + + // U is referenced only by @Marshalled handling. + boolean usesU = enclosed.values().stream().anyMatch(f -> f.getAnnotation(Marshalled.class) != null); + + if (usesU) + imports.add("org.apache.ignite.internal.util.typedef.internal.U"); + + String msgParam = simpleNameWithGeneric(type) + " msg, GridKernalContext kctx"; + + generateUnmarshalMethod(msgParam + ", CacheObjectContext cacheObjCtx, ClassLoader clsLdr", workerFields); + + if (!nioFields.isEmpty()) + generateUnmarshalNioMethod(msgParam, nioFields); + } + + /** Generates the cache-aware {@code unmarshal} overload: the full field set, with cache context and deployment class loader. */ + private void generateUnmarshalMethod(String params, List fields) { + hasStatements |= emitMethod(marshall, "unmarshal(" + params + ")", body -> { + usesMsgFactory = false; + + Set wireFieldSkip = marshalledWireFieldsToSkip(); + + if (needsCtx(fields) || !wireFieldSkip.isEmpty()) + appendBlock(body, List.of(ctxResolutionLine())); + + appendFields(body, fields, MarshalMode.UNMARSHAL, wireFieldSkip); + + if (marshallable) + appendBlock(body, List.of(indentedLine("msg.unmarshal(marshaller, clsLdr);"))); + + appendMarshalledFinish(body); + + appendMarshalledElementsFinish(body); + appendMarshalledMapFinish(body); + appendMarshalledElementBlobsFinish(body); + + prependMsgFactoryResolution(body); + }); + } + + /** Generates the {@code unmarshalNio} method for NIO-eligible {@code @Message} fields. */ + private void generateUnmarshalNioMethod(String params, List nioFields) { + hasStatements |= emitMethod(marshall, "unmarshalNio(" + params + ")", body -> { + for (VariableElement f : nioFields) + appendBlock(body, unmarshalNioField(fieldAccessor(f))); + }); + } + + /** Cache-free unmarshal of a {@code @NioField} message field on the NIO thread (no cache context available). */ + private List unmarshalNioField(String accessor) { + imports.add("org.apache.ignite.internal.managers.communication.MessageMarshalling"); + + List code = new ArrayList<>(); + + code.add(indentedLine("if (%s != null)", accessor)); + + indent++; + + code.add(indentedLine("MessageMarshalling.unmarshal(%s, kctx);", accessor)); + + indent--; + + return code; + } + + /** Generates logical→wire conversions for the element-, blob-list- and map-flavoured {@code @Marshalled} fields. */ + private void appendMarshalledFieldsPrepare(List body) { + for (VariableElement field : enclosed.values()) { + appendCollectionPrepare(body, field); + appendMapPrepare(body, field); + appendObjectsPrepare(body, field); + } + } + + /** Generates the {@code Collection} build-up for a per-element-blobs {@code @Marshalled} field in marshal. */ + private void appendObjectsPrepare(List body, VariableElement field) { + if (kinds.get(field) != MarshalledKind.ELEMENT_BLOBS) + return; + + Marshalled ann = field.getAnnotation(Marshalled.class); + + String objField = "msg." + field.getSimpleName(); + String bytesField = "msg." + ann.value(); + + imports.add("java.util.ArrayList"); + + List code = new ArrayList<>(); + + code.add(indentedLine("if (%s != null && %s == null) {", objField, bytesField)); + + indent++; + + code.add(indentedLine("%s = new ArrayList<>(%s.size());", bytesField, objField)); + code.add(EMPTY); + code.add(indentedLine("for (Object e : %s)", objField)); + + indent++; + + code.add(indentedLine("%s.add(U.marshal(marshaller, e));", bytesField)); + + indent--; + indent--; + + code.add(indentedLine("}")); + + appendBlock(body, code); + } + + /** Appends a {@code toArray} assignment for a per-element {@code @Marshalled} field, if present. */ + private void appendCollectionPrepare(List body, VariableElement field) { + if (kinds.get(field) != MarshalledKind.ELEMENTS) + return; + + Marshalled ann = field.getAnnotation(Marshalled.class); + + String colField = "msg." + field.getSimpleName(); + String arrField = "msg." + ann.value(); + String compName = arrayComponentName(requireEnclosed(enclosed, ann.value(), "@Marshalled")); + + List code = new ArrayList<>(); + + code.add(indentedLine("if (%s != null && %s == null)", colField, arrField)); + + indent++; + + code.add(indentedLine("%s = %s.toArray(new %s[0]);", arrField, colField, compName)); + + indent--; + + appendBlock(body, code); + } + + /** Appends key/value array assignments for a map-flavoured {@code @Marshalled} field, if present. */ + private void appendMapPrepare(List body, VariableElement field) { + if (kinds.get(field) != MarshalledKind.MAP) + return; + + Marshalled ann = field.getAnnotation(Marshalled.class); + + String mapField = "msg." + field.getSimpleName(); + String keysField = "msg." + ann.keys(); + String valuesField = "msg." + ann.values(); + VariableElement keysEl = requireEnclosed(enclosed, ann.keys(), "@Marshalled"); + + List code = new ArrayList<>(); + + code.add(indentedLine("if (%s != null && %s == null) {", mapField, keysField)); + + indent++; + + code.addAll(keysEl.asType().getKind() == TypeKind.ARRAY + ? arrayMapBody(ann, mapField, keysField, keysEl, valuesField) + : viewBasedMapBody(keysField, mapField, valuesField)); + + indent--; + + code.add(indentedLine("}")); + + appendBlock(body, code); + } + + /** Generates {@code U.marshal} calls for all {@code @Marshalled} fields in marshal. */ + private void appendMarshalledPrepare(List body) { + forEachMarshalled((bytesAcc, objAcc) -> { + List code = new ArrayList<>(); + + code.add(indentedLine("if (%s != null && %s == null)", objAcc, bytesAcc)); + + indent++; + + code.add(indentedLine("%s = U.marshal(marshaller, %s);", bytesAcc, objAcc)); + + indent--; + + return code; + }, body); + } + + /** Generates {@code U.unmarshal} calls for all {@code @Marshalled} fields in the cache-aware unmarshal. */ + private void appendMarshalledFinish(List body) { + forEachMarshalled((bytesAcc, objAcc) -> { + List code = new ArrayList<>(); + + code.add(indentedLine("if (%s != null) {", bytesAcc)); + + indent++; + + code.add(indentedLine("%s = U.unmarshal(marshaller, %s, clsLdr);", objAcc, bytesAcc)); + code.add(EMPTY); + + // Drop the serialized cache once the object is restored: keeping both the deserialized value and its bytes + // on every received message doubles retained memory (e.g. topology history nodes) and can exhaust the heap. + code.add(indentedLine("%s = null;", bytesAcc)); + + indent--; + + code.add(indentedLine("}")); + + return code; + }, body); + } + + /** Generates Set reconstruction for all {@link MarshalledKind#ELEMENTS} {@code @Marshalled} fields. */ + private void appendMarshalledElementsFinish(List body) { + for (VariableElement field : enclosed.values()) { + if (kinds.get(field) != MarshalledKind.ELEMENTS) + continue; + + Marshalled colAnn = field.getAnnotation(Marshalled.class); + + String colField = "msg." + field.getSimpleName(); + String arrField = "msg." + colAnn.value(); + VariableElement wireField = requireEnclosed(enclosed, colAnn.value(), "@Marshalled"); + + List code = new ArrayList<>(); + + code.add(indentedLine("if (%s != null) {", arrField)); + + indent++; + + code.add(indentedLine("%s = U.newHashSet(%s.length);", colField, arrField)); + code.add(EMPTY); + code.addAll(collectionFinishForBlock(wireField, colField, arrField, field.getSimpleName().toString())); + code.add(EMPTY); + code.add(indentedLine("%s = null;", arrField)); + + indent--; + + code.add(indentedLine("}")); + + appendBlock(body, code); + } + } + + /** Generates Collection reconstruction for {@link MarshalledKind#ELEMENT_BLOBS} {@code @Marshalled} fields (cache-aware pass only). */ + private void appendMarshalledElementBlobsFinish(List body) { + for (VariableElement field : enclosed.values()) { + if (kinds.get(field) != MarshalledKind.ELEMENT_BLOBS) + continue; + + Marshalled ann = field.getAnnotation(Marshalled.class); + + String objField = "msg." + field.getSimpleName(); + String bytesField = "msg." + ann.value(); + + imports.add("java.util.ArrayList"); + imports.add("java.util.Map"); + imports.add(KEY_CACHE_OBJECT_CLS); + + List code = new ArrayList<>(); + + code.add(indentedLine("if (%s != null) {", bytesField)); + + indent++; + + code.add(indentedLine("%s = new ArrayList<>(%s.size());", objField, bytesField)); + code.add(EMPTY); + code.add(indentedLine("for (byte[] e : %s) {", bytesField)); + + indent++; + + code.add(indentedLine("Object o = U.unmarshal(marshaller, e, clsLdr);")); + code.add(EMPTY); + code.add(indentedLine("if (o instanceof Map.Entry) {")); + + indent++; + + code.add(indentedLine("Object key = ((Map.Entry)o).getKey();")); + code.add(EMPTY); + code.add(indentedLine("if (key instanceof KeyCacheObject)")); + + indent++; + + code.add(indentedLine("((KeyCacheObject)key).unmarshal(ctx, clsLdr);")); + + indent--; + indent--; + + code.add(indentedLine("}")); + code.add(EMPTY); + code.add(indentedLine("%s.add(o);", objField)); + + indent--; + + code.add(indentedLine("}")); + code.add(EMPTY); + code.add(indentedLine("%s = null;", bytesField)); + + indent--; + + code.add(indentedLine("}")); + + appendBlock(body, code); + } + } + + /** Generates the {@code for} loop body: per-element unmarshal + try/catch add into the collection. */ + private List collectionFinishForBlock(VariableElement wireField, String colField, String arrField, String fieldName) { + String compName = arrayComponentName(wireField); + TypeMirror compType = ((ArrayType)wireField.asType()).getComponentType(); + + List code = new ArrayList<>(); + + code.add(indentedLine("for (%s e : %s) {", compName, arrField)); + + indent++; + + code.addAll(codeFor(compType, "e", MarshalMode.UNMARSHAL)); + code.add(EMPTY); + code.add(indentedLine("%s.add(e);", colField)); + + indent--; + + code.add(indentedLine("}")); + + return code; + } + + /** Returns names of wire fields skipped by {@link #appendFields} in UNMARSHAL mode. */ + private Set marshalledWireFieldsToSkip() { + Set names = new HashSet<>(); + + for (VariableElement f : enclosed.values()) { + MarshalledKind kind = kinds.get(f); + + if (kind == null || kind == MarshalledKind.BLOB) + continue; + + Marshalled ann = f.getAnnotation(Marshalled.class); + + if (kind == MarshalledKind.MAP) { + names.add(ann.keys()); + names.add(ann.values()); + } + else + names.add(ann.value()); + } + + return names; + } + + /** Generates Map reconstruction for all map-flavoured {@code @Marshalled} fields. */ + private void appendMarshalledMapFinish(List body) { + for (VariableElement field : enclosed.values()) { + if (kinds.get(field) != MarshalledKind.MAP) + continue; + + Marshalled ann = field.getAnnotation(Marshalled.class); + + VariableElement keysEl = requireEnclosed(enclosed, ann.keys(), "@Marshalled"); + VariableElement valsEl = requireEnclosed(enclosed, ann.values(), "@Marshalled"); + + String mapField = "msg." + field.getSimpleName(); + String keysField = "msg." + ann.keys(); + String valsField = "msg." + ann.values(); + + List code = keysEl.asType().getKind() == TypeKind.ARRAY + ? mapFinishArrayBlock(field, keysEl, valsEl, mapField, keysField, valsField) + : mapFinishCollectionBlock(keysEl, valsEl, mapField, keysField, valsField); + + appendBlock(body, code); + } + } + + /** Generates indexed-loop Map reconstruction for array-backed map-flavoured {@code @Marshalled} fields. */ + private List mapFinishArrayBlock(VariableElement field, VariableElement keysEl, VariableElement valsEl, String mapField, + String keysField, String valsField) { + List code = new ArrayList<>(); + + code.add(indentedLine("if (%s != null) {", keysField)); + + indent++; + + if (!field.getModifiers().contains(Modifier.FINAL)) { + code.add(indentedLine("%s = U.newHashMap(%s.length);", mapField, keysField)); + code.add(EMPTY); + } + + code.add(indentedLine("for (int i = 0; i < %s.length; i++) {", keysField)); + + indent++; + + code.addAll(mapPutBlock( + ((ArrayType)keysEl.asType()).getComponentType(), + ((ArrayType)valsEl.asType()).getComponentType(), + arrayComponentName(keysEl) + " k = " + keysField + "[i];", + arrayComponentName(valsEl) + " v = " + valsField + "[i];", + mapField)); + + indent--; + + code.add(indentedLine("}")); + code.add(EMPTY); + code.add(indentedLine("%s = null;", keysField)); + code.add(indentedLine("%s = null;", valsField)); + + indent--; + + code.add(indentedLine("}")); + + return code; + } + + /** Generates iterator-based Map reconstruction for collection-backed map-flavoured {@code @Marshalled} fields. */ + private List mapFinishCollectionBlock(VariableElement keysEl, VariableElement valsEl, String mapField, + String keysField, String valsField) { + TypeMirror keyCompType = ((DeclaredType)keysEl.asType()).getTypeArguments().get(0); + TypeMirror valCompType = ((DeclaredType)valsEl.asType()).getTypeArguments().get(0); + + Element keyElem = element(keyCompType); + Element valElem = element(valCompType); + + String keyCompName = keyElem.getSimpleName().toString(); + String valCompName = valElem.getSimpleName().toString(); + + imports.add(((QualifiedNameable)keyElem).getQualifiedName().toString()); + imports.add(((QualifiedNameable)valElem).getQualifiedName().toString()); + imports.add("java.util.Iterator"); + + List code = new ArrayList<>(); + + code.add(indentedLine("if (%s != null) {", keysField)); + + indent++; + + code.add(indentedLine("%s = U.newHashMap(%s.size());", mapField, keysField)); + code.add(EMPTY); + code.add(indentedLine("Iterator<%s> keyIter = %s.iterator();", keyCompName, keysField)); + code.add(indentedLine("Iterator<%s> valIter = %s.iterator();", valCompName, valsField)); + code.add(EMPTY); + code.add(indentedLine("while (keyIter.hasNext()) {")); + + indent++; + + code.addAll(mapPutBlock(keyCompType, valCompType, + keyCompName + " k = keyIter.next();", + valCompName + " v = valIter.next();", + mapField)); + + indent--; + + code.add(indentedLine("}")); + code.add(EMPTY); + code.add(indentedLine("%s = null;", keysField)); + code.add(indentedLine("%s = null;", valsField)); + + indent--; + + code.add(indentedLine("}")); + + return code; + } + + /** + * Generates the reconstruction-loop body shared by both map layouts: k/v declarations, + * element unmarshal and {@code map.put}. + */ + private List mapPutBlock(TypeMirror keyCompType, TypeMirror valCompType, String kDecl, String vDecl, String mapField) { + List code = new ArrayList<>(); + + code.add(indentedLine("%s", kDecl)); + code.add(indentedLine("%s", vDecl)); + + List keyUnmarshal = codeFor(keyCompType, "k", MarshalMode.UNMARSHAL); + List valUnmarshal = codeFor(valCompType, "v", MarshalMode.UNMARSHAL); + + if (!keyUnmarshal.isEmpty()) { + code.add(EMPTY); + code.addAll(keyUnmarshal); + } + + if (!valUnmarshal.isEmpty()) { + code.add(EMPTY); + code.addAll(valUnmarshal); + } + + code.add(EMPTY); + code.add(indentedLine("%s.put(k, v);", mapField)); + + return code; + } + + /** Generates key/value array population from the map's entry set. */ + private List arrayMapBody(Marshalled ann, String mapField, String keysField, VariableElement keysEl, String valuesField) { + String compName = arrayComponentName(keysEl); + String valCompName = arrayComponentName(requireEnclosed(enclosed, ann.values(), "@Marshalled")); + + List inner = new ArrayList<>(); + + imports.add("java.util.Map"); + + inner.add(indentedLine("%s = new %s[%s.size()];", keysField, compName, mapField)); + inner.add(indentedLine("%s = new %s[%s.length];", valuesField, valCompName, keysField)); + inner.add(indentedLine("int i = 0;")); + inner.add(indentedLine("for (Map.Entry e : %s.entrySet()) {", mapField)); + + indent++; + + inner.add(indentedLine("%s[i] = (%s)e.getKey();", keysField, compName)); + inner.add(indentedLine("%s[i] = (%s)e.getValue();", valuesField, valCompName)); + inner.add(indentedLine("i++;")); + + indent--; + + inner.add(indentedLine("}")); + + return inner; + } + + /** Generates key/value assignments backed by the map's own {@code keySet()} and {@code values()} views. */ + private List viewBasedMapBody(String keysField, String mapField, String valuesField) { + List inner = new ArrayList<>(); + + inner.add(indentedLine("%s = %s.keySet();", keysField, mapField)); + inner.add(indentedLine("%s = %s.values();", valuesField, mapField)); + + return inner; + } + + /** Marshals each field and appends non-empty results to {@code body}. */ + private void appendFields(List body, List fields, MarshalMode mode) { + appendFields(body, fields, mode, Set.of()); + } + + /** Marshals each field, skipping names in {@code skip}, and appends non-empty results to {@code body}. */ + private void appendFields(List body, List fields, MarshalMode mode, Set skip) { + for (VariableElement field : fields) { + if (skip.contains(field.getSimpleName().toString())) + continue; + + List result = codeFor(field.asType(), fieldAccessor(field), mode); + + if (!result.isEmpty()) + appendBlock(body, result); + } + } + + /** Returns generated marshal/unmarshal code lines for field of type {@code t}, or empty if none needed. */ + private List codeFor(TypeMirror t, String accessor, MarshalMode mode) { + if (t.getKind() == TypeKind.ARRAY) { + TypeMirror comp = ((ArrayType)t).getComponentType(); + + return comp.getKind() == TypeKind.DECLARED ? marshallArray(comp, accessor, mode) : List.of(); + } + + if (t.getKind() == TypeKind.DECLARED || t.getKind() == TypeKind.TYPEVAR) { + if (isMessage(t)) + return isNonMarshallable(t) ? List.of() : marshallMessage(accessor, mode); + if (isCacheObject(t)) + return marshallCacheObject(accessor, mode); + if (isMap(t)) + return marshallMap((DeclaredType)t, accessor, mode); + if (isCollection(t)) + return marshallCollection((DeclaredType)t, accessor, mode); + } + + return List.of(); + } + + /** + * Generates a null-guarded {@code MessageMarshalling.marshal/unmarshal} call. Loop-nested calls go through the + * overloads taking the pre-resolved {@code msgFactory} local (see {@link #prependMsgFactoryResolution}), so the + * factory is not re-resolved from the context on every element. + */ + private List marshallMessage(String accessor, MarshalMode mode) { + imports.add("org.apache.ignite.internal.managers.communication.MessageMarshalling"); + + List code = new ArrayList<>(); + + code.add(indentedLine("if (%s != null)", accessor)); + + indent++; + + if (loopDepth > 0) { + usesMsgFactory = true; + + code.add(mode == MarshalMode.MARSHAL + ? indentedLine("MessageMarshalling.marshal(msgFactory, %s, kctx, ctx);", accessor) + : indentedLine("MessageMarshalling.unmarshal(msgFactory, %s, kctx, ctx, clsLdr);", accessor)); + } + else { + code.add(mode == MarshalMode.MARSHAL + ? indentedLine("MessageMarshalling.marshal(%s, kctx, ctx);", accessor) + : indentedLine("MessageMarshalling.unmarshal(%s, kctx, ctx, clsLdr);", accessor)); + } + + indent--; + + return code; + } + + /** Generates a null-and-ctx-guarded {@code marshal/unmarshal} call on a {@code CacheObject} (marshal or cache-aware unmarshal only). */ + private List marshallCacheObject(String accessor, MarshalMode mode) { + List code = new ArrayList<>(); + + code.add(indentedLine("if (%s != null && ctx != null)", accessor)); + + indent++; + + code.add(mode == MarshalMode.MARSHAL + ? indentedLine("%s.marshal(ctx);", accessor) + : indentedLine("%s.unmarshal(ctx, clsLdr);", accessor)); + + indent--; + + return code; + } + + /** Generates a null-guarded for-each loop over the array's elements. */ + private List marshallArray(TypeMirror comp, String accessor, MarshalMode mode) { + Element elem = ((DeclaredType)comp).asElement(); + + indent++; + + List loopCode = forLoop(elem.getSimpleName().toString(), comp, accessor, mode); + + indent--; + + if (!loopCode.isEmpty()) + imports.add(((QualifiedNameable)elem).getQualifiedName().toString()); + + return wrapNullGuarded(accessor, loopCode); + } + + /** Generates a null-guarded for-each loop over the collection's elements. */ + private List marshallCollection(DeclaredType t, String accessor, MarshalMode mode) { + TypeMirror arg = t.getTypeArguments().get(0); + + if (arg.getKind() != TypeKind.DECLARED && arg.getKind() != TypeKind.TYPEVAR) + return List.of(); + + Element elem = element(arg); + + String typeName = elem.getSimpleName().toString(); + + indent++; + + List loopCode = forLoop(typeName, arg, "(Collection)" + accessor, mode); + + indent--; + + if (!loopCode.isEmpty()) { + imports.add(((QualifiedNameable)elem).getQualifiedName().toString()); + imports.add("java.util.Collection"); + } + + return wrapNullGuarded(accessor, loopCode); + } + + /** Iterates {@code keySet()} then {@code values()}, wrapping both loops in a null-guard. */ + private List marshallMap(DeclaredType t, String accessor, MarshalMode mode) { + List args = t.getTypeArguments(); + + indent++; + + List combined = new ArrayList<>(); + + for (int i = 0; i < 2; i++) { + TypeMirror elemType = args.get(i); + + if (elemType.getKind() != TypeKind.DECLARED && elemType.getKind() != TypeKind.TYPEVAR) + continue; + + Element elem = element(elemType); + + String typeName = elem.getSimpleName().toString(); + String collection = i == 0 ? "keySet" : "values"; + String iterable = "((Collection)" + accessor + "." + collection + "())"; + + List loopCode = forLoop(typeName, elemType, iterable, mode); + + if (loopCode.isEmpty()) + continue; + + imports.add(((QualifiedNameable)elem).getQualifiedName().toString()); + imports.add("java.util.Collection"); + + combined.addAll(loopCode); + } + + indent--; + + return wrapNullGuarded(accessor, combined); + } + + /** Returns empty if {@code elemType} requires no marshalling; otherwise returns a for-each loop over {@code iterable}. */ + private List forLoop(String typeName, TypeMirror elemType, String iterable, MarshalMode mode) { + String el = loopDepth == 0 ? "e" : "e" + loopDepth; + + loopDepth++; + indent++; + + List inner = codeFor(elemType, el, mode); + + indent--; + loopDepth--; + + if (inner.isEmpty()) + return List.of(); + + List code = new ArrayList<>(); + + code.add(indentedLine("for (%s %s : %s) {", typeName, el, iterable)); + + code.addAll(inner); + + code.add(indentedLine("}")); + + return code; + } + + /** Prefixes {@code body} with the {@code msgFactory} resolution line when a loop-nested facade call was emitted. */ + private void prependMsgFactoryResolution(List body) { + if (!usesMsgFactory) + return; + + imports.add("org.apache.ignite.internal.managers.communication.IgniteMessageFactory"); + + body.add(0, EMPTY); + body.add(0, indentedLine("IgniteMessageFactory msgFactory = (IgniteMessageFactory)kctx.messageFactory();")); + } + + /** Returns empty if {@code inner} is empty; otherwise wraps {@code inner} in a null-guard on {@code nullGuard}. */ + private List wrapNullGuarded(String nullGuard, List inner) { + if (inner.isEmpty()) + return List.of(); + + List code = new ArrayList<>(); + + code.add(indentedLine("if (%s != null) {", nullGuard)); + + code.addAll(inner); + + code.add(indentedLine("}")); + + return code; + } + + /** + * Returns the {@code CacheObjectContext ctx} resolution line for the current message type. Cache messages resolve + * via the cache, group messages via the cache group — the group's context outlives the stop of individual caches, + * so cache objects still unmarshal while a cache (group) is being destroyed. + */ + private String ctxResolutionLine() { + if (isCacheIdAwareMessage(type)) + return indentedLine("CacheObjectContext ctx = cacheObjCtx != null ? cacheObjCtx : " + + "kctx.cache().context().cacheObjectContext(msg.cacheId());"); + else if (isCacheGroupIdMessage(type)) + return indentedLine("CacheObjectContext ctx = cacheObjCtx != null ? cacheObjCtx : " + + "kctx.cache().cacheGroup(msg.groupId()) == null ? null : " + + "kctx.cache().cacheGroup(msg.groupId()).cacheObjectContext();"); + else + return indentedLine("CacheObjectContext ctx = cacheObjCtx;"); + } + + /** Returns {@code true} if any field requires {@code ctx} in generated marshal/unmarshal code. */ + private boolean needsCtx(List fields) { + return fields.stream().anyMatch(f -> needsCtxType(f.asType())); + } + + /** + * Returns whether the {@code @Order} fields of {@code msgType} need a cache object context to unmarshal. Such a + * message must not be a {@code @NioField}: its {@code unmarshalNio} runs on the NIO thread, which has no context. + * A type with no fields to inspect (e.g. a type variable) is conservatively assumed to need the context. + */ + private boolean nestedNeedsCtx(TypeMirror type) { + Element el = env.getTypeUtils().asElement(type); + + if (!(el instanceof TypeElement)) + return true; + + return SystemViewRowAttributeWalkerProcessor.superclasses(env, (TypeElement)el) + .flatMap(c -> ElementFilter.fieldsIn(c.getEnclosedElements()).stream()) + .filter(f -> f.getAnnotation(Order.class) != null) + .anyMatch(f -> needsCtxType(f.asType())); + } + + /** Returns {@code true} if type {@code t} (or its element/key/value types) requires {@code ctx}. */ + private boolean needsCtxType(TypeMirror t) { + if (t.getKind() == TypeKind.ARRAY) + return needsCtxType(((ArrayType)t).getComponentType()); + + if (t.getKind() == TypeKind.DECLARED || t.getKind() == TypeKind.TYPEVAR) { + if (isMessage(t)) + return !isNonMarshallable(t); + + if (isCacheObject(t)) + return true; + + if (isMap(t)) { + List args = ((DeclaredType)t).getTypeArguments(); + return needsCtxType(args.get(0)) || needsCtxType(args.get(1)); + } + + if (isCollection(t)) { + List args = ((DeclaredType)t).getTypeArguments(); + return needsCtxType(args.get(0)); + } + } + + return false; + } + + /** */ + private boolean isMessage(TypeMirror type) { + return assignableFrom(type, msgType); + } + + /** */ + private boolean isCacheObject(TypeMirror type) { + return assignableFrom(type, cacheObjType); + } + + /** Returns {@code true} if {@code type} (erased) is assignable to {@code java.util.Map}. */ + private boolean isMap(TypeMirror type) { + return assignableFrom(erasedType(type), mapType); + } + + /** Returns {@code true} if {@code type} (erased) is assignable to {@code java.util.Collection}. */ + private boolean isCollection(TypeMirror type) { + return assignableFrom(erasedType(type), colType); + } + + /** */ + private boolean isNonMarshallableMessage(TypeElement te) { + return isNonMarshallable(te.asType()); + } + + /** Recursion skip for such fields is subtype-safe: subclasses inherit the {@code NonMarshallableMessage} marker. */ + private boolean isNonMarshallable(TypeMirror t) { + return assignableFrom(t, nonMarshallableType); + } + + /** */ + private boolean isCacheGroupIdMessage(TypeElement te) { + return assignableFrom(te.asType(), cacheGrpIdMsgType); + } + + /** */ + private static boolean isNioField(VariableElement field) { + return field.getAnnotation(NioField.class) != null; + } + + /** Marshalling flavour of a {@code @Marshalled} field, told apart by the shape of its companion wire field(s). */ + private enum MarshalledKind { + /** {@code byte[]} companion: the whole object is a single marshaller blob. */ + BLOB, + + /** {@code Message[]} companion: per-element {@code Message} serialization, the collection is rebuilt on unmarshal. */ + ELEMENTS, + + /** {@code Collection} companion: per-element marshaller blobs, each element keeping its own class loader. */ + ELEMENT_BLOBS, + + /** Two companions ({@code keys()}/{@code values()}): a {@code Map} serialized as parallel wire fields. */ + MAP + } + + /** + * @return the flavour of {@code field}'s {@code @Marshalled}, or {@code null} when the field is not annotated. + * Called once per field when building {@link #kinds}; look the kind up there instead. + */ + private @Nullable MarshalledKind marshalledKind(VariableElement field) { + Marshalled ann = field.getAnnotation(Marshalled.class); + + if (ann == null) + return null; + + boolean map = !ann.keys().isEmpty() || !ann.values().isEmpty(); + + if (map == !ann.value().isEmpty() || (map && (ann.keys().isEmpty() || ann.values().isEmpty()))) { + env.getMessager().printMessage(Diagnostic.Kind.ERROR, + "@Marshalled must set either value() or both keys() and values()", field); + + return null; + } + + if (map) + return MarshalledKind.MAP; + + TypeMirror wire = requireEnclosed(enclosed, ann.value(), "@Marshalled").asType(); + + if (wire.getKind() == TypeKind.ARRAY) { + return ((ArrayType)wire).getComponentType().getKind() == TypeKind.BYTE + ? MarshalledKind.BLOB + : MarshalledKind.ELEMENTS; + } + + return MarshalledKind.ELEMENT_BLOBS; + } + + /** Returns the enclosed field named {@code name}, or throws if absent. */ + private VariableElement requireEnclosed(Map enclosed, String name, String annotationName) { + VariableElement el = enclosed.get(name); + + if (el == null) + throw new IllegalStateException(annotationName + " companion field '" + name + "' not found in " + type); + + return el; + } + + /** Iterates all {@code @Marshalled} fields and applies {@code codeGen(bytesAccessor, objAccessor)} to each. */ + private void forEachMarshalled(BiFunction> codeGen, List body) { + for (VariableElement field : enclosed.values()) { + if (kinds.get(field) != MarshalledKind.BLOB) + continue; + + Marshalled ann = field.getAnnotation(Marshalled.class); + + appendBlock(body, codeGen.apply("msg." + ann.value(), "msg." + field.getSimpleName())); + } + } + + /** Returns the element for {@code t}; for a type variable, uses its upper bound. */ + private Element element(TypeMirror t) { + return t.getKind() == TypeKind.DECLARED ? + ((DeclaredType)t).asElement() : + ((DeclaredType)((TypeVariable)t).getUpperBound()).asElement(); + } + + /** Returns the simple name of the array component type of {@code field}, registering its import. */ + private String arrayComponentName(VariableElement field) { + Element comp = ((DeclaredType)((ArrayType)field.asType()).getComponentType()).asElement(); + + imports.add(((QualifiedNameable)comp).getQualifiedName().toString()); + + return comp.getSimpleName().toString(); + } + + /** Direction of the field code a generator pass emits: object→wire ({@link #MARSHAL}) or wire→object ({@link #UNMARSHAL}). */ + private enum MarshalMode { + /** Marshal: object → wire bytes, on the sending side. */ + MARSHAL, + + /** Unmarshal: wire bytes → object, with full cache context and class loader. */ + UNMARSHAL + } +} diff --git a/modules/codegen/src/main/java/org/apache/ignite/internal/MessageProcessor.java b/modules/codegen/src/main/java/org/apache/ignite/internal/MessageProcessor.java index d6d331175e8c4..250a2ed6cff64 100644 --- a/modules/codegen/src/main/java/org/apache/ignite/internal/MessageProcessor.java +++ b/modules/codegen/src/main/java/org/apache/ignite/internal/MessageProcessor.java @@ -25,8 +25,10 @@ import java.util.Map; import java.util.Objects; import java.util.Set; +import java.util.function.Function; import java.util.stream.Collectors; import javax.annotation.processing.AbstractProcessor; +import javax.annotation.processing.ProcessingEnvironment; import javax.annotation.processing.RoundEnvironment; import javax.annotation.processing.SupportedAnnotationTypes; import javax.annotation.processing.SupportedSourceVersion; @@ -37,13 +39,15 @@ import javax.lang.model.element.Modifier; import javax.lang.model.element.TypeElement; import javax.lang.model.element.VariableElement; -import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; +import javax.lang.model.util.ElementFilter; import javax.tools.Diagnostic; +import org.apache.ignite.internal.systemview.SystemViewRowAttributeWalkerProcessor; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.lang.IgniteBiTuple; import static org.apache.ignite.internal.MessageSerializerGenerator.DLFT_ENUM_MAPPER_CLS; +import static org.apache.ignite.internal.MessageSerializerGenerator.enumType; /** * Annotation processor that generates serialization and deserialization code for classes implementing the {@code Message} interface. @@ -77,6 +81,15 @@ public class MessageProcessor extends AbstractProcessor { /** Externalizable message. */ static final String MARSHALLABLE_MESSAGE_INTERFACE = "org.apache.ignite.internal.MarshallableMessage"; + /** Marker of messages with no marshaller. */ + static final String NON_MARSHALLABLE_MESSAGE_INTERFACE = "org.apache.ignite.plugin.extensions.communication.NonMarshallableMessage"; + + /** */ + static final String CACHE_OBJECT_CLS = "org.apache.ignite.internal.processors.cache.CacheObject"; + + /** */ + static final String KEY_CACHE_OBJECT_CLS = "org.apache.ignite.internal.processors.cache.KeyCacheObject"; + /** */ public static final String GRID_H2_NULL = "org.apache.ignite.internal.processors.query.h2.twostep.msg.GridH2Null"; @@ -97,21 +110,32 @@ public class MessageProcessor extends AbstractProcessor { static final String[] SKIP_MESSAGES = { "org.apache.ignite.internal.processors.odbc.ClientMessage", COMPRESSED_MESSAGE_CLASS, - "org.apache.ignite.loadtests.communication.GridTestMessage" + "org.apache.ignite.loadtests.communication.GridTestMessage", + "org.apache.ignite.spi.communication.tcp.TestDelayMessage" }; /** */ private final Map> enumMappersInUse = new HashMap<>(); - /** - * Processes all classes implementing the {@code Message} interface and generates corresponding serializer code. - */ + /** Processes all classes implementing the {@code Message} interface and generates corresponding serializer code. */ @Override public boolean process(Set annotations, RoundEnvironment roundEnv) { - TypeMirror msgType = processingEnv.getElementUtils().getTypeElement(MESSAGE_INTERFACE).asType(); + TypeElement msgEl = processingEnv.getElementUtils().getTypeElement(MESSAGE_INTERFACE); + + if (msgEl == null) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, + "Cannot resolve " + MESSAGE_INTERFACE + " on the annotation-processing classpath."); + + return false; + } + + TypeMirror msgType = msgEl.asType(); List emptyMsgs = typesToTypeMirrors(EMPTY_MESSAGES); List skipMsgs = typesToTypeMirrors(SKIP_MESSAGES); + TypeElement marshallableEl = processingEnv.getElementUtils().getTypeElement(MARSHALLABLE_MESSAGE_INTERFACE); + TypeElement nonMarshallableEl = processingEnv.getElementUtils().getTypeElement(NON_MARSHALLABLE_MESSAGE_INTERFACE); + Map> msgFields = new HashMap<>(); for (Element el: roundEnv.getRootElements()) { @@ -123,6 +147,13 @@ public class MessageProcessor extends AbstractProcessor { if (!isAssignable(msgType, clazz)) continue; + // No marshaller is generated for a NonMarshallableMessage, so declared marshalling logic would silently never run. + if (nonMarshallableEl != null && isAssignable(nonMarshallableEl.asType(), clazz) + && ((marshallableEl != null && isAssignable(marshallableEl.asType(), clazz)) || hasMarshalledFields(clazz))) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, + "NonMarshallableMessage must not implement MarshallableMessage or declare @Marshalled fields", clazz); + } + if (clazz.getModifiers().contains(Modifier.ABSTRACT)) continue; @@ -145,15 +176,20 @@ public class MessageProcessor extends AbstractProcessor { msgFields.put(clazz, fields); } + List> generators = List.of( + MessageSerializerGenerator::new, MessageMarshallerGenerator::new, MessageDeploymentGenerator::new); + for (Map.Entry> type: msgFields.entrySet()) { - try { - new MessageSerializerGenerator(processingEnv).generate(type.getKey(), type.getValue()); - } - catch (Exception e) { - processingEnv.getMessager().printMessage( - Diagnostic.Kind.ERROR, - "Failed to generate a message serializer:" + e.getMessage(), - type.getKey()); + for (Function factory : generators) { + MessageGenerator gen = factory.apply(processingEnv); + + try { + gen.generate(type.getKey(), type.getValue()); + } + catch (Exception e) { + processingEnv.getMessager().printMessage(Diagnostic.Kind.ERROR, + "Failed to generate a message " + gen.typeSuffix().toLowerCase() + ":" + e.getMessage(), type.getKey()); + } } } @@ -192,7 +228,7 @@ private boolean checkConstructors(TypeElement clazz) { * The resulting list is sorted in ascending order of the {@code @Order} value. * * @param type the {@code TypeElement} representing the class to inspect. - * @return a list of {@code VariableElement} objects representing all ordered fields, including those declared in superclasses. + * @return all ordered fields including those in superclasses, sorted by ascending {@code @Order} value. */ private List orderedFields(TypeElement type) { List> hierList = hierarchicalOrderedFields(type); @@ -246,7 +282,7 @@ private List> hierarchicalOrderedFields(TypeElement type) } /** - * Validates consistency of enum field mappers configuration: the same mapper is used for the same enum in different messages, + * Validates consistency of enum field mappers configuration: the same mapper is used for the same enum across different messages, * CustomMapper annotation is used only for enum fields. * * @param type Type implementing Message interface. @@ -254,7 +290,8 @@ private List> hierarchicalOrderedFields(TypeElement type) */ private void validateEnumFieldMapping(TypeElement type, Element el) { CustomMapper custMappAnn = el.getAnnotation(CustomMapper.class); - if (isEnumField(el)) { + + if (enumType(processingEnv, el.asType())) { String enumClsFullName = el.asType().toString(); String enumMapperClsName = custMappAnn != null ? custMappAnn.value() : DLFT_ENUM_MAPPER_CLS; String msgClsName = type.toString(); @@ -285,16 +322,6 @@ else if (custMappAnn != null) { } } - /** */ - private boolean isEnumField(Element el) { - TypeMirror elType = el.asType(); - - if (elType.getKind() != TypeKind.DECLARED) - return false; - - return processingEnv.getTypeUtils().asElement(elType).getKind() == ElementKind.ENUM; - } - /** Map class names to {@link TypeMirror} objects. */ private List typesToTypeMirrors(String[] types) { return Arrays.stream(types) @@ -308,4 +335,11 @@ private List typesToTypeMirrors(String[] types) { private boolean isAssignable(TypeMirror t, TypeElement clazz) { return processingEnv.getTypeUtils().isAssignable(clazz.asType(), t); } + + /** @return {@code true} if {@code clazz} or any of its superclasses declares a {@code @Marshalled} field. */ + private boolean hasMarshalledFields(TypeElement clazz) { + return SystemViewRowAttributeWalkerProcessor.superclasses(processingEnv, clazz) + .flatMap(c -> ElementFilter.fieldsIn(c.getEnclosedElements()).stream()) + .anyMatch(f -> f.getAnnotation(Marshalled.class) != null); + } } diff --git a/modules/codegen/src/main/java/org/apache/ignite/internal/MessageSerializerGenerator.java b/modules/codegen/src/main/java/org/apache/ignite/internal/MessageSerializerGenerator.java index caa9adcd650bd..c3305f8eadc16 100644 --- a/modules/codegen/src/main/java/org/apache/ignite/internal/MessageSerializerGenerator.java +++ b/modules/codegen/src/main/java/org/apache/ignite/internal/MessageSerializerGenerator.java @@ -17,12 +17,7 @@ package org.apache.ignite.internal; -import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.PrintWriter; -import java.io.Reader; import java.io.StringWriter; import java.io.Writer; import java.util.ArrayList; @@ -34,7 +29,6 @@ import java.util.Set; import java.util.TreeSet; import java.util.UUID; -import javax.annotation.processing.FilerException; import javax.annotation.processing.ProcessingEnvironment; import javax.lang.model.element.Element; import javax.lang.model.element.ElementKind; @@ -46,43 +40,16 @@ import javax.lang.model.type.PrimitiveType; import javax.lang.model.type.TypeKind; import javax.lang.model.type.TypeMirror; -import javax.lang.model.util.Elements; -import javax.tools.Diagnostic; -import javax.tools.FileObject; -import javax.tools.JavaFileObject; -import javax.tools.StandardLocation; import org.apache.ignite.internal.systemview.SystemViewRowAttributeWalkerProcessor; -import org.apache.ignite.internal.util.typedef.internal.SB; import org.jetbrains.annotations.Nullable; +import static org.apache.ignite.internal.MessageProcessor.CACHE_OBJECT_CLS; import static org.apache.ignite.internal.MessageProcessor.COMPRESSED_MESSAGE_CLASS; -import static org.apache.ignite.internal.MessageProcessor.MARSHALLABLE_MESSAGE_INTERFACE; +import static org.apache.ignite.internal.MessageProcessor.KEY_CACHE_OBJECT_CLS; import static org.apache.ignite.internal.MessageProcessor.MESSAGE_INTERFACE; -/** - * Generates serializer class for given {@code Message} class. The generated serializer follows the naming convention: - * {@code org.apache.ignite.internal.codegen.[MessageClassName]Serializer}. - */ -public class MessageSerializerGenerator { - /** */ - private static final String EMPTY = ""; - - /** */ - public static final String TAB = " "; - - /** */ - public static final String NL = System.lineSeparator(); - - /** */ - private static final String CLS_JAVADOC = "/** " + NL + - " * This class is generated automatically." + NL + - " *" + NL + - " * @see org.apache.ignite.internal.MessageProcessor" + NL + - " */"; - - /** */ - public static final String METHOD_JAVADOC = "/** */"; - +/** Generates {@code *Serializer} classes for {@code Message} types. */ +public class MessageSerializerGenerator extends MessageGenerator { /** */ private static final String RETURN_FALSE_STMT = "return false;"; @@ -93,159 +60,69 @@ public class MessageSerializerGenerator { private static final String COMPRESSED_MSG_ERROR = "CompressedMessage should not be used explicitly. " + "To compress the required field use the @Compress annotation."; - /** Collection of lines for {@code writeTo} method. */ + /** */ private final List write = new ArrayList<>(); - /** Collection of lines for {@code readFrom} method. */ - private final List read = new ArrayList<>(); - - /** Collection of message-specific imports. */ - private final Set imports = new TreeSet<>(); - - /** Collection of Serializer class fields containing mappers for message enum fields. */ - private final Set fields = new TreeSet<>(); - /** */ - private final ProcessingEnvironment env; - - /** Stored type of the message being processed. */ - private TypeElement type; - - /** The marshallable message type. */ - private final TypeMirror marshallableMsgType; + private final List read = new ArrayList<>(); - /** */ - private int indent; + /** Class-field declarations (enum mappers/values, collection descriptors) emitted at the top of the generated class. */ + private final Set clsFields = new TreeSet<>(); /** */ MessageSerializerGenerator(ProcessingEnvironment env) { - this.env = env; - - marshallableMsgType = env.getElementUtils().getTypeElement(MARSHALLABLE_MESSAGE_INTERFACE).asType(); + super(env); } - /** */ - void generate(TypeElement type, List fields) throws Exception { - assert this.type == null : "Message serializer generator isn't stateless and is supposed to be single-use."; - - this.type = type; + /** {@inheritDoc} */ + @Override String typeSuffix() { + return "Serializer"; + } + /** {@inheritDoc} */ + @Override void generateBody(List fields) throws Exception { generateMethods(fields); + // Include superclass types in imports so generated code can cast to them for inherited fields. SystemViewRowAttributeWalkerProcessor.superclasses(env, type).forEach(el -> imports.add(el.toString())); - - String serClsName = type.getSimpleName() + (marshallableMessage() ? "Marshallable" : "") + "Serializer"; - String serFqnClsName = env.getElementUtils().getPackageOf(type) + "." + serClsName; - String serCode = generateSerializerCode(serClsName); - - try { - JavaFileObject file = env.getFiler().createSourceFile(serFqnClsName); - - try (Writer writer = file.openWriter()) { - writer.append(serCode); - writer.flush(); - } - } - catch (FilerException e) { - // IntelliJ IDEA parses Ignite's pom.xml and configures itself to use this annotation processor on each Run. - // During a Run, it invokes the processor and may fail when attempting to generate sources that already exist. - // There is no a setting to disable this invocation. The IntelliJ community suggests a workaround — delegating - // all Run commands to Maven. However, this significantly slows down test startup time. - // This hack checks whether the content of a generating file is identical to already existed file, and skips - // handling this class if it is. - if (!identicalFileIsAlreadyGenerated(env, serCode, serFqnClsName)) { - env.getMessager().printMessage( - Diagnostic.Kind.ERROR, - "MessageSerializer " + serClsName + " is already generated. Try 'mvn clean install' to fix the issue."); - - throw e; - } - } } - /** Generates full code for a serializer class. */ - private String generateSerializerCode(String serClsName) throws IOException { - if (marshallableMessage()) { - fields.add("private final Marshaller marshaller;"); - fields.add("private final ClassLoader clsLdr;"); - } - + /** {@inheritDoc} */ + @Override String buildClassCode(String serClsName) throws IOException { try (Writer writer = new StringWriter()) { - writeClassHeader(writer, env.getElementUtils().getPackageOf(type).toString(), serClsName); + imports.add(type.toString()); + imports.add("org.apache.ignite.plugin.extensions.communication.MessageSerializer"); + imports.add("org.apache.ignite.plugin.extensions.communication.MessageWriter"); + imports.add("org.apache.ignite.plugin.extensions.communication.MessageReader"); - writeClassFields(writer); + writeClassHeader(writer, "MessageSerializer", serClsName); - writeConstructor(writer, serClsName); + writer.write(" {" + NL); + + writeClassFields(writer); - // Write #writeTo method. for (String w: write) writer.write(w + NL); - writer.write(TAB + "}" + NL + NL); + writer.write(NL); - // Write #readFrom method. for (String r: read) writer.write(r + NL); - writer.write(TAB + "}" + NL); - writer.write("}"); - writer.write(NL); - return writer.toString(); } } - /** */ - private void writeConstructor(Writer writer, String serClsName) throws IOException { - if (!marshallableMessage()) - return; - - ++indent; - - writer.write(identedLine(METHOD_JAVADOC)); - writer.write(NL); - writer.write(identedLine("public " + serClsName + "(Marshaller marshaller, ClassLoader clsLdr) {")); - - writer.write(NL); - - ++indent; - - writer.write(identedLine("this.marshaller = marshaller;")); - writer.write(NL); - writer.write(identedLine("this.clsLdr = clsLdr;")); - - --indent; - - writer.write(NL); - - writer.write(identedLine("}")); - writer.write(NL); - - --indent; - } - /** Generates code for {@code writeTo} and {@code readFrom}. */ private void generateMethods(List fields) throws Exception { - start(write, true); - start(read, false); - - indent++; - - int state = 0; - - for (VariableElement field: fields) - processField(field, state++); - - indent--; - - finish(write, false, false); - finish(read, true, marshallableMessage()); + generateMethod(write, fields, true); + generateMethod(read, fields, false); } /** - * Generates start of write/read methods: + * Generates the complete {@code writeTo}/{@code readFrom} method: *

      *     public boolean writeTo(Message m, MessageWriter writer) {
      *         if (!writer.isHeaderWritten()) {
@@ -257,74 +134,86 @@ private void generateMethods(List fields) throws Exception {
      * 
* * @param code Code lines. + * @param fields Ordered fields. * @param write Whether write code is generated. */ - private void start(Collection code, boolean write) { - indent = 1; - - code.add(identedLine(METHOD_JAVADOC)); + private void generateMethod(List code, List fields, boolean write) throws Exception { + code.add(indentedLine(METHOD_JAVADOC)); - code.add(identedLine("@Override public boolean %s(" + type.getSimpleName() + " msg, %s) {", - write ? "writeTo" : "readFrom", - write ? "MessageWriter writer" : "MessageReader reader")); + code.add(indentedLine("@Override public boolean %s(" + simpleNameWithGeneric(type) + " msg, %s) {", + write ? "writeTo" : "readFrom", write ? "MessageWriter writer" : "MessageReader reader")); indent++; if (write) { - code.add(identedLine("if (!writer.isHeaderWritten()) {")); + code.add(indentedLine("if (!writer.isHeaderWritten()) {")); indent++; - returnFalseIfWriteFailed(code, "writer.writeHeader", "directType()"); + returnFalseIf(code, "!writer.writeHeader(msg.directType())"); - if (write && marshallableMessage()) { - imports.add("org.apache.ignite.IgniteCheckedException"); - imports.add("org.apache.ignite.IgniteException"); - - code.add(EMPTY); - - code.add(identedLine("try {")); - - indent++; - - code.add(identedLine("msg.prepareMarshal(marshaller);")); + code.add(EMPTY); + code.add(indentedLine("writer.onHeaderWritten();")); - indent--; + indent--; - code.add(identedLine("}")); - code.add(identedLine("catch (IgniteCheckedException e) {")); + code.add(indentedLine("}")); + code.add(EMPTY); + } - indent++; + code.add(indentedLine("switch (%s.state()) {", write ? "writer" : "reader")); - code.add(identedLine("throw new IgniteException(\"Failed to marshal object \" + msg.getClass().getSimpleName(), e);")); + indent++; - indent--; + int state = 0; - code.add(identedLine("}")); - } + for (VariableElement field: fields) + processField(field, state++, write); - code.add(EMPTY); - code.add(identedLine("writer.onHeaderWritten();")); + indent--; - indent--; + finish(code); - code.add(identedLine("}")); - code.add(EMPTY); - } + indent--; - code.add(identedLine("switch (%s.state()) {", write ? "writer" : "reader")); + code.add(indentedLine("}")); } /** * @param field Field. * @param opt Case option. + * @param write Whether write code is generated. */ - private void processField(VariableElement field, int opt) throws Exception { + private void processField(VariableElement field, int opt, boolean write) throws Exception { if (assignableFrom(field.asType(), type(Throwable.class.getName()))) throw new UnsupportedOperationException("You should use ErrorMessage for serialization of throwables."); - writeField(field, opt); - readField(field, opt); + if (write) + writeField(opt, callExpr(field, true)); + else + readField(field, opt, callExpr(field, false)); + } + + /** @return Writer/reader call expression for {@code field}. */ + private String callExpr(VariableElement field, boolean write) throws Exception { + if (enumType(env, field.asType())) { + String prefix = registerEnumMapper(field); + + boolean custMapper = field.getAnnotation(CustomMapper.class) != null; + + if (write) { + return "writer.writeByte(" + (custMapper ? prefix + "Mapper" : "DefaultEnumMapper.INSTANCE") + + ".encode(" + fieldRef(field) + "))"; + } + + return custMapper + ? prefix + "Mapper.decode(reader.readByte())" + : "DefaultEnumMapper.INSTANCE.decode(" + prefix + "Vals, reader.readByte())"; + } + + FieldCall call = fieldCall(field); + + return write ? call.expr("writer.write", fieldRef(field)) : call.expr("reader.read", null); } /** @@ -337,18 +226,18 @@ private void processField(VariableElement field, int opt) throws Exception { * writer.incrementState(); * * - * @param field Field. * @param opt Case option. + * @param writeExpr Writer call expression. */ - private void writeField(VariableElement field, int opt) throws Exception { - write.add(identedLine("case %d:", opt)); + private void writeField(int opt, String writeExpr) { + write.add(indentedLine("case %d:", opt)); indent++; - returnFalseIfWriteFailed(field); + returnFalseIf(write, "!" + writeExpr); write.add(EMPTY); - write.add(identedLine("writer.incrementState();")); + write.add(indentedLine("writer.incrementState();")); write.add(EMPTY); indent--; @@ -367,29 +256,30 @@ private void writeField(VariableElement field, int opt) throws Exception { * * @param field Field. * @param opt Case option. + * @param readExpr Reader call expression. */ - private void readField(VariableElement field, int opt) throws Exception { - read.add(identedLine("case %d:", opt)); + private void readField(VariableElement field, int opt, String readExpr) { + read.add(indentedLine("case %d:", opt)); indent++; - returnFalseIfReadFailed(field); + read.add(indentedLine("%s = %s;", fieldRef(field), readExpr)); + read.add(EMPTY); + + returnFalseIf(read, "!reader.isLastRead()"); read.add(EMPTY); - read.add(identedLine("reader.incrementState();")); + read.add(indentedLine("reader.incrementState();")); read.add(EMPTY); indent--; } /** - * Discover access write methods, like {@code writeInt}. - * - * @param field Field to generate write code. + * Resolves the writer/reader call for {@code field} from its type, registering required imports and + * collection-descriptor class fields. Enum fields are handled separately in {@link #processField}. */ - private void returnFalseIfWriteFailed(VariableElement field) throws Exception { - String getExpr = field.getSimpleName().toString(); - + private FieldCall fieldCall(VariableElement field) throws Exception { TypeMirror type = field.asType(); boolean compress = field.getAnnotation(Compress.class) != null; @@ -397,337 +287,139 @@ private void returnFalseIfWriteFailed(VariableElement field) throws Exception { if (compress) checkTypeForCompress(type); - if (type.getKind().isPrimitive()) { - String typeName = capitalizeOnlyFirst(type.getKind().name()); - - returnFalseIfWriteFailed(write, field, "writer.write" + typeName, getExpr); - - return; - } + if (type.getKind().isPrimitive()) + return new FieldCall(capitalizeOnlyFirst(type.getKind().name()), null, false); if (type.getKind() == TypeKind.ARRAY) { - ArrayType arrType = (ArrayType)type; - TypeMirror componentType = arrType.getComponentType(); + TypeMirror compType = ((ArrayType)type).getComponentType(); - if (componentType.getKind().isPrimitive()) { - String typeName = capitalizeOnlyFirst(componentType.getKind().name()); + if (compType.getKind().isPrimitive()) + return new FieldCall(capitalizeOnlyFirst(compType.getKind().name()) + "Array", null, false); - returnFalseIfWriteFailed(write, field, "writer.write" + typeName + "Array", getExpr); + if (compType.getKind() == TypeKind.DECLARED) { + Element compElem = ((DeclaredType)compType).asElement(); - return; + if (!"java.lang".equals(env.getElementUtils().getPackageOf(compElem).getQualifiedName().toString())) + imports.add(((QualifiedNameable)compElem).getQualifiedName().toString()); } - returnFalseIfWriteFailed(write, field, "writer.writeObjectArray", getExpr, messageCollectionItemTypes(field, type)); - - return; + return new FieldCall("ObjectArray", messageCollectionItemTypes(field, type), false); } if (type.getKind() == TypeKind.DECLARED) { if (sameType(type, String.class)) - returnFalseIfWriteFailed(write, field, "writer.writeString", getExpr); - - else if (sameType(type, BitSet.class)) - returnFalseIfWriteFailed(write, field, "writer.writeBitSet", getExpr); - - else if (sameType(type, UUID.class)) - returnFalseIfWriteFailed(write, field, "writer.writeUuid", getExpr); + return new FieldCall("String", null, false); - else if (sameType(type, "org.apache.ignite.lang.IgniteUuid")) - returnFalseIfWriteFailed(write, field, "writer.writeIgniteUuid", getExpr); - - else if (sameType(type, "org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion")) - returnFalseIfWriteFailed(write, field, "writer.writeAffinityTopologyVersion", getExpr); + if (sameType(type, BitSet.class)) + return new FieldCall("BitSet", null, false); - else if (assignableFrom(erasedType(type), type(Map.class.getName()))) { - List args = new ArrayList<>(); + if (sameType(type, UUID.class)) + return new FieldCall("Uuid", null, false); - args.add(getExpr); - args.add(messageCollectionItemTypes(field, type)); + if (sameType(type, "org.apache.ignite.lang.IgniteUuid")) + return new FieldCall("IgniteUuid", null, false); - if (compress) - args.add("true"); // the value of the compress argument in the MessageWriter#writeMap method + if (sameType(type, "org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion")) + return new FieldCall("AffinityTopologyVersion", null, false); - returnFalseIfWriteFailed(write, field, "writer.writeMap", args.toArray(String[]::new)); - } + if (assignableFrom(erasedType(type), type(Map.class.getName()))) + return new FieldCall("Map", messageCollectionItemTypes(field, type), compress); - else if (assignableFrom(type, type("org.apache.ignite.internal.processors.cache.KeyCacheObject"))) - returnFalseIfWriteFailed(write, field, "writer.writeKeyCacheObject", getExpr); + if (assignableFrom(type, type(KEY_CACHE_OBJECT_CLS))) + return new FieldCall("KeyCacheObject", null, false); - else if (assignableFrom(type, type("org.apache.ignite.internal.processors.cache.CacheObject"))) - returnFalseIfWriteFailed(write, field, "writer.writeCacheObject", getExpr); + if (assignableFrom(type, type(CACHE_OBJECT_CLS))) + return new FieldCall("CacheObject", null, false); - else if (assignableFrom(type, type("org.apache.ignite.internal.util.GridLongList"))) - returnFalseIfWriteFailed(write, field, "writer.writeGridLongList", getExpr); + if (assignableFrom(type, type("org.apache.ignite.internal.util.GridLongList"))) + return new FieldCall("GridLongList", null, false); - else if (assignableFrom(type, type("org.apache.ignite.lang.IgniteProductVersion"))) - returnFalseIfWriteFailed(write, field, "writer.writeIgniteProductVersion", getExpr); + if (assignableFrom(type, type("org.apache.ignite.lang.IgniteProductVersion"))) + return new FieldCall("IgniteProductVersion", null, false); - else if (assignableFrom(type, type("org.apache.ignite.internal.processors.cache.version.GridCacheVersion"))) - returnFalseIfWriteFailed(write, field, "writer.writeGridCacheVersion", getExpr); + if (assignableFrom(type, type("org.apache.ignite.internal.processors.cache.version.GridCacheVersion"))) + return new FieldCall("GridCacheVersion", null, false); - else if (assignableFrom(type, type(MESSAGE_INTERFACE))) { + if (assignableFrom(type, type(MESSAGE_INTERFACE))) { if (sameType(type, COMPRESSED_MESSAGE_CLASS)) throw new IllegalArgumentException(COMPRESSED_MSG_ERROR); - if (compress) - returnFalseIfWriteFailed(write, field, "writer.writeMessage", getExpr, "true"); - else - returnFalseIfWriteFailed(write, field, "writer.writeMessage", getExpr); + return new FieldCall("Message", null, compress); } - else if (assignableFrom(erasedType(type), type(Collection.class.getName()))) - returnFalseIfWriteFailed(write, field, "writer.writeCollection", getExpr, messageCollectionItemTypes(field, type)); - - else if (enumType(env, type)) { - Element element = env.getTypeUtils().asElement(type); - imports.add(element.toString()); - - String enumName = element.getSimpleName().toString(); - String enumFieldPrefix = typeNameToFieldName(enumName); - - String mapperCallStmnt; - - CustomMapper custMapperAnn = field.getAnnotation(CustomMapper.class); - - if (custMapperAnn != null) { - String fullMapperName = custMapperAnn.value(); - if (fullMapperName == null || fullMapperName.isEmpty()) - throw new IllegalArgumentException("Please specify a not-null not-empty EnumMapper class name"); - - imports.add("org.apache.ignite.plugin.extensions.communication.mappers.EnumMapper"); - imports.add(fullMapperName); + if (assignableFrom(erasedType(type), type(Collection.class.getName()))) + return new FieldCall("Collection", messageCollectionItemTypes(field, type), false); - String simpleName = fullMapperName.substring(fullMapperName.lastIndexOf('.') + 1); - - String mapperFieldName = enumFieldPrefix + "Mapper"; - - fields.add("private final EnumMapper<" + enumName + "> " + mapperFieldName + " = new " + simpleName + "();"); - - mapperCallStmnt = mapperFieldName + ".encode"; - } - else { - imports.add(DLFT_ENUM_MAPPER_CLS); - String enumValuesFieldName = enumFieldPrefix + "Vals"; - - fields.add("private final " + enumName + "[] " + enumValuesFieldName + " = " + enumName + ".values();"); - - mapperCallStmnt = "DefaultEnumMapper.INSTANCE.encode"; - } - - returnFalseIfEnumWriteFailed(write, field, "writer.writeByte", mapperCallStmnt, getExpr); - } - else - throw new IllegalArgumentException("Unsupported declared type: " + type); - - return; + throw new IllegalArgumentException("Unsupported declared type: " + type); } throw new IllegalArgumentException("Unsupported type kind: " + type.getKind()); } /** - * Converts type name to camel case field name. Example: {@code "MyType"} -> {@code "myType"}. + * Registers imports and the mapper/values class field for an enum {@code field}. + * + * @return Class-field name prefix derived from the enum type name. */ - private String typeNameToFieldName(String typeName) { - char[] typeNameChars = typeName.toCharArray(); - typeNameChars[0] = Character.toLowerCase(typeNameChars[0]); - return new String(typeNameChars); - } + private String registerEnumMapper(VariableElement field) { + Element enumElem = env.getTypeUtils().asElement(field.asType()); - /** - * Generate code of writing header. - *
-     * if (!writer.writeHeader(msg.directType()))
-     *     return false;
-     * 
- */ - private void returnFalseIfWriteFailed(Collection code, String accessor, @Nullable String... args) { - String argsStr = String.join(", ", args); + imports.add(enumElem.toString()); - code.add(identedLine("if (!%s(msg.%s))", accessor, argsStr)); + String enumName = enumElem.getSimpleName().toString(); + String prefix = typeNameToFieldName(enumName); - indent++; + CustomMapper custMapperAnn = field.getAnnotation(CustomMapper.class); - code.add(identedLine(RETURN_FALSE_STMT)); + if (custMapperAnn != null) { + String fullMapperName = custMapperAnn.value(); - indent--; - } + if (fullMapperName == null || fullMapperName.isEmpty()) + throw new IllegalArgumentException("Please specify a not-null not-empty EnumMapper class name"); - /** - * Generate code of writing single field: - */ - private void returnFalseIfWriteFailed(Collection code, VariableElement field, String accessor, @Nullable String... args) { - String argsStr = String.join(", ", args); + imports.add("org.apache.ignite.plugin.extensions.communication.mappers.EnumMapper"); + imports.add(fullMapperName); + + String simpleName = fullMapperName.substring(fullMapperName.lastIndexOf('.') + 1); - if (type.equals(field.getEnclosingElement())) - code.add(identedLine("if (!%s(msg.%s))", accessor, argsStr)); + clsFields.add("private final EnumMapper<" + enumName + "> " + prefix + "Mapper = new " + simpleName + "();"); + } else { - // Field has to be requested from a super class object. - code.add(identedLine("if (!%s(((%s)msg).%s))", accessor, field.getEnclosingElement().getSimpleName(), argsStr)); + imports.add(DLFT_ENUM_MAPPER_CLS); + + clsFields.add("private final " + enumName + "[] " + prefix + "Vals = " + enumName + ".values();"); } - indent++; + return prefix; + } - code.add(identedLine(RETURN_FALSE_STMT)); + /** @return {@code "msg."} accessor, cast to the declaring superclass for inherited fields. */ + private String fieldRef(VariableElement field) { + String ref = type.equals(field.getEnclosingElement()) + ? "msg" + : "((" + field.getEnclosingElement().getSimpleName() + ")msg)"; - indent--; + return ref + "." + field.getSimpleName(); } - /** - * Generate code of writing single enum field mapped with EnumMapper: - */ - private void returnFalseIfEnumWriteFailed( - Collection code, - VariableElement field, - String writerCall, - String mapperCall, - String fieldGetterCall) { - if (type.equals(field.getEnclosingElement())) - code.add(identedLine("if (!%s(%s(msg.%s)))", writerCall, mapperCall, fieldGetterCall)); - else { - // Field has to be requested from a super class object. - code.add(identedLine("if (!%s(%s(((%s)msg).%s)))", - writerCall, mapperCall, field.getEnclosingElement().getSimpleName(), fieldGetterCall)); - } + /** Appends {@code if () return false;} to {@code code}. */ + private void returnFalseIf(Collection code, String cond) { + code.add(indentedLine("if (%s)", cond)); indent++; - code.add(identedLine(RETURN_FALSE_STMT)); + code.add(indentedLine(RETURN_FALSE_STMT)); indent--; } /** - * Discover access read methods, like {@code readInt}. - * - * @param field Field. + * Converts type name to camel case field name. Example: {@code "MyType"} -> {@code "myType"}. */ - private void returnFalseIfReadFailed(VariableElement field) throws Exception { - TypeMirror type = field.asType(); - - boolean compress = field.getAnnotation(Compress.class) != null; - - if (compress) - checkTypeForCompress(type); - - if (type.getKind().isPrimitive()) { - String typeName = capitalizeOnlyFirst(type.getKind().name()); - - returnFalseIfReadFailed(field, "reader.read" + typeName); - - return; - } - - if (type.getKind() == TypeKind.ARRAY) { - ArrayType arrType = (ArrayType)type; - TypeMirror componentType = arrType.getComponentType(); - - if (componentType.getKind().isPrimitive()) { - String typeName = capitalizeOnlyFirst(componentType.getKind().name()); - - returnFalseIfReadFailed(field, "reader.read" + typeName + "Array"); - - return; - } - - if (componentType.getKind() == TypeKind.ARRAY) { - returnFalseIfReadFailed(field, "reader.readObjectArray", messageCollectionItemTypes(field, type)); - - return; - } - - if (componentType.getKind() == TypeKind.DECLARED) { - Element componentElement = ((DeclaredType)componentType).asElement(); - - returnFalseIfReadFailed(field, "reader.readObjectArray", messageCollectionItemTypes(field, type)); - - if (!"java.lang".equals(env.getElementUtils().getPackageOf(componentElement).getQualifiedName().toString())) { - String importCls = ((QualifiedNameable)componentElement).getQualifiedName().toString(); - - imports.add(importCls); - } - - return; - } - } - - if (type.getKind() == TypeKind.DECLARED) { - if (sameType(type, String.class)) - returnFalseIfReadFailed(field, "reader.readString"); - - else if (sameType(type, BitSet.class)) - returnFalseIfReadFailed(field, "reader.readBitSet"); - - else if (sameType(type, UUID.class)) - returnFalseIfReadFailed(field, "reader.readUuid"); - - else if (sameType(type, "org.apache.ignite.lang.IgniteUuid")) - returnFalseIfReadFailed(field, "reader.readIgniteUuid"); - - else if (sameType(type, "org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion")) - returnFalseIfReadFailed(field, "reader.readAffinityTopologyVersion"); - - else if (assignableFrom(erasedType(type), type(Map.class.getName()))) { - List typeArgs = ((DeclaredType)type).getTypeArguments(); - - assert typeArgs.size() == 2; - - List args = new ArrayList<>(); - - args.add(messageCollectionItemTypes(field, type)); - - if (compress) - args.add("true"); // the value of the compress argument in the MessageReader#readMap method - - returnFalseIfReadFailed(field, "reader.readMap", args.toArray(String[]::new)); - } - - else if (assignableFrom(type, type("org.apache.ignite.internal.processors.cache.KeyCacheObject"))) - returnFalseIfReadFailed(field, "reader.readKeyCacheObject"); - - else if (assignableFrom(type, type("org.apache.ignite.internal.processors.cache.CacheObject"))) - returnFalseIfReadFailed(field, "reader.readCacheObject"); - - else if (assignableFrom(type, type("org.apache.ignite.internal.util.GridLongList"))) - returnFalseIfReadFailed(field, "reader.readGridLongList"); - - else if (assignableFrom(type, type("org.apache.ignite.lang.IgniteProductVersion"))) - returnFalseIfReadFailed(field, "reader.readIgniteProductVersion"); - - else if (assignableFrom(type, type("org.apache.ignite.internal.processors.cache.version.GridCacheVersion"))) - returnFalseIfReadFailed(field, "reader.readGridCacheVersion"); - - else if (assignableFrom(type, type(MESSAGE_INTERFACE))) { - if (sameType(type, COMPRESSED_MESSAGE_CLASS)) - throw new IllegalArgumentException(COMPRESSED_MSG_ERROR); - - if (compress) - returnFalseIfReadFailed(field, "reader.readMessage", "true"); - else - returnFalseIfReadFailed(field, "reader.readMessage"); - } - - else if (assignableFrom(erasedType(type), type(Collection.class.getName()))) { - returnFalseIfReadFailed(field, "reader.readCollection", messageCollectionItemTypes(field, type)); - } - else if (enumType(env, type)) { - String fieldPrefix = typeNameToFieldName(env.getTypeUtils().asElement(type).getSimpleName().toString()); - - boolean hasCustMapperAnn = field.getAnnotation(CustomMapper.class) != null; - - String mapperCallStmnt = hasCustMapperAnn ? fieldPrefix + "Mapper.decode" : "DefaultEnumMapper.INSTANCE.decode"; - String enumValsFieldName = hasCustMapperAnn ? null : fieldPrefix + "Vals"; - - returnFalseIfEnumReadFailed(field, mapperCallStmnt, enumValsFieldName); - } - - else - throw new IllegalArgumentException("Unsupported declared type: " + type); - - return; - } - - throw new IllegalArgumentException("Unsupported type kind: " + type.getKind()); + private String typeNameToFieldName(String typeName) { + char[] typeNameChars = typeName.toCharArray(); + typeNameChars[0] = Character.toLowerCase(typeNameChars[0]); + return new String(typeNameChars); } /** */ @@ -736,7 +428,7 @@ private String messageCollectionItemTypes(VariableElement field, TypeMirror type String descName = field.getSimpleName() + "CollDesc"; String typeName = desc.substring(desc.indexOf(' ') + 1, desc.indexOf('(')); - fields.add("private static final " + typeName + " " + descName + " = " + desc + ";"); + clsFields.add("private static final " + typeName + " " + descName + " = " + desc + ";"); return descName; } @@ -845,10 +537,10 @@ private String messageCollectionItemType(TypeMirror type) throws Exception { if (sameType(type, "org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion")) return "AFFINITY_TOPOLOGY_VERSION"; - if (sameType(type, "org.apache.ignite.internal.processors.cache.KeyCacheObject")) + if (sameType(type, KEY_CACHE_OBJECT_CLS)) return "KEY_CACHE_OBJECT"; - if (sameType(type, "org.apache.ignite.internal.processors.cache.CacheObject")) + if (sameType(type, CACHE_OBJECT_CLS)) return "CACHE_OBJECT"; if (sameType(type, "org.apache.ignite.internal.util.GridLongList")) @@ -885,190 +577,31 @@ private PrimitiveType unboxedType(TypeMirror type) { } } - /** - * Generate code of reading single field. - * - * @param field Field. - * @param mtd Method name. - */ - private void returnFalseIfReadFailed(VariableElement field, String mtd, String... args) { - String argsStr = String.join(", ", args); - - if (type.equals(field.getEnclosingElement())) - read.add(identedLine("msg.%s = %s(%s);", field.getSimpleName().toString(), mtd, argsStr)); - else { - // Field has to be requested from a super class object. - read.add(identedLine("((%s)msg).%s = %s(%s);", - field.getEnclosingElement().getSimpleName(), field.getSimpleName().toString(), mtd, argsStr)); - } - - read.add(EMPTY); - - read.add(identedLine("if (!reader.isLastRead())")); - - indent++; - - read.add(identedLine(RETURN_FALSE_STMT)); - - indent--; - } - - /** - * Generate code of reading single field: - * - * @param mapperDecodeCallStmnt Method name. - */ - private void returnFalseIfEnumReadFailed(VariableElement field, String mapperDecodeCallStmnt, String enumValuesFieldName) { - String readOp; - - if (enumValuesFieldName == null) - readOp = line("%s(reader.readByte())", mapperDecodeCallStmnt); - else - readOp = line("%s(%s, reader.readByte())", mapperDecodeCallStmnt, enumValuesFieldName); - - if (type.equals(field.getEnclosingElement())) - read.add(identedLine("msg.%s = %s;", field.getSimpleName().toString(), readOp)); - else { - // Field has to be requested from a super class object. - read.add(identedLine("((%s)msg).%s = %s;", - field.getEnclosingElement().getSimpleName(), field.getSimpleName().toString(), readOp)); - } - - read.add(EMPTY); - - read.add(identedLine("if (!reader.isLastRead())")); - - indent++; - - read.add(identedLine(RETURN_FALSE_STMT)); - - indent--; - } - - /** */ - private void finish(List code, boolean read, boolean marshallable) { + /** Closes the {@code switch} and emits the final {@code return true;} statement. */ + private void finish(List code) { String lastLine = code.get(code.size() - 1); if (EMPTY.equals(lastLine)) code.remove(code.size() - 1); - code.add(identedLine("}")); + code.add(indentedLine("}")); code.add(EMPTY); - if (read && marshallable) { - imports.add("org.apache.ignite.IgniteCheckedException"); - imports.add("org.apache.ignite.IgniteException"); - - code.add(identedLine("try {")); - - indent++; - - code.add(identedLine("msg.finishUnmarshal(marshaller, clsLdr);")); - - indent--; - - code.add(identedLine("}")); - code.add(identedLine("catch (IgniteCheckedException e) {")); - - indent++; - - code.add(identedLine("throw new IgniteException(\"Failed to unmarshal object \" + msg.getClass().getSimpleName(), e);")); - - indent--; - - code.add(identedLine("}")); - - code.add(EMPTY); - } - - code.add(identedLine("return true;")); - } - - /** - * Creates line with current indent from given arguments. - * - * @return Line with current indent. - */ - private String identedLine(String format, Object... args) { - SB sb = new SB(); - - for (int i = 0; i < indent; i++) - sb.a(TAB); - - sb.a(String.format(format, args)); - - return sb.toString(); - } - - /** - * Creates line from given arguments. - * - * @return Line. - */ - private String line(String format, Object... args) { - SB sb = new SB(); - - sb.a(String.format(format, args)); - - return sb.toString(); + code.add(indentedLine("return true;")); } - /** Write serializer class fields: enum values, custom enum mappers. */ + /** Write serializer class fields: enum values, custom enum mappers, collection descriptors. */ private void writeClassFields(Writer writer) throws IOException { - if (fields.isEmpty()) + if (clsFields.isEmpty()) return; - indent = 1; - - for (String field: fields) { - writer.write(identedLine(METHOD_JAVADOC)); + for (String field: clsFields) { + writer.write(indentedLine(METHOD_JAVADOC)); writer.write(NL); - writer.write(identedLine(field)); + writer.write(indentedLine(field)); writer.write(NL); } writer.write(NL); - - indent = 0; - } - - /** Write header of serializer class: license, imports, class declaration. */ - private void writeClassHeader(Writer writer, String pkgName, String serClsName) throws IOException { - try (InputStream in = getClass().getClassLoader().getResourceAsStream("license.txt"); - BufferedReader reader = new BufferedReader(new InputStreamReader(in))) { - - PrintWriter out = new PrintWriter(writer); - - String line; - - while ((line = reader.readLine()) != null) - out.println(line); - } - - writer.write(NL); - writer.write("package " + pkgName + ";" + NL + NL); - - imports.add(type.toString()); - - if (marshallableMessage()) - imports.add("org.apache.ignite.marshaller.Marshaller"); - - imports.add("org.apache.ignite.plugin.extensions.communication.MessageSerializer"); - imports.add("org.apache.ignite.plugin.extensions.communication.MessageWriter"); - imports.add("org.apache.ignite.plugin.extensions.communication.MessageReader"); - - for (String regularImport : imports) - writer.write("import " + regularImport + ";" + NL); - - writer.write(NL); - writer.write(CLS_JAVADOC); - writer.write(NL); - - writer.write("public class " + serClsName + " implements MessageSerializer<" + type.getSimpleName() + "> {" + NL); - } - - /** */ - private boolean marshallableMessage() { - return env.getTypeUtils().isAssignable(type.asType(), marshallableMsgType); } /** */ @@ -1081,11 +614,6 @@ private boolean sameType(TypeMirror type, Class cls) { return env.getTypeUtils().isSameType(type, type(cls.getCanonicalName())); } - /** */ - private boolean assignableFrom(TypeMirror type, TypeMirror superType) { - return env.getTypeUtils().isAssignable(type, superType); - } - /** */ public static boolean enumType(ProcessingEnvironment env, TypeMirror type) { Element element = env.getTypeUtils().asElement(type); @@ -1093,62 +621,11 @@ public static boolean enumType(ProcessingEnvironment env, TypeMirror type) { return element != null && element.getKind() == ElementKind.ENUM; } - /** */ - private TypeMirror type(String clazz) { - Elements elementUtils = env.getElementUtils(); - - TypeElement typeElement = elementUtils.getTypeElement(clazz); - - return typeElement != null ? typeElement.asType() : null; - } - - /** */ - private TypeMirror erasedType(TypeMirror type) { - return env.getTypeUtils().erasure(type); - } - /** Converts string "BYTE" to string "Byte", with first capital latter. */ private String capitalizeOnlyFirst(String input) { return input.substring(0, 1).toUpperCase() + input.substring(1).toLowerCase(); } - /** @return {@code true} if trying to generate file with the same content. */ - public static boolean identicalFileIsAlreadyGenerated(ProcessingEnvironment env, String srcCode, String fqnClsName) { - try { - String fileName = fqnClsName.replace('.', '/') + ".java"; - FileObject prevFile = env.getFiler().getResource(StandardLocation.SOURCE_OUTPUT, "", fileName); - - String prevFileContent; - try (Reader r = prevFile.openReader(true)) { - prevFileContent = content(r); - } - - // We are ok, for some reason the same file is already generated (Intellij IDEA might do it). - if (prevFileContent.contentEquals(srcCode)) - return true; - } - catch (Exception ignoredAttemptToGetExistingFile) { - // We have some other problem, not an existing file. - } - - return false; - } - - /** */ - private static String content(Reader reader) throws IOException { - BufferedReader br = new BufferedReader(reader); - StringBuilder sb = new StringBuilder(); - String line; - - while ((line = br.readLine()) != null) - sb.append(line).append(NL); - - // Delete last line separator. - sb.deleteCharAt(sb.length() - 1); - - return sb.toString(); - } - /** Checks that the Compress annotation is used only for supported types: Map and Message. */ private void checkTypeForCompress(TypeMirror type) { if (type.getKind() == TypeKind.DECLARED) { @@ -1160,6 +637,41 @@ private void checkTypeForCompress(TypeMirror type) { throw new IllegalArgumentException("Compress annotation is used for an unsupported type: " + type); } + /** Writer/reader call for a field: method name suffix with optional collection-descriptor and compress arguments. */ + private static final class FieldCall { + /** Suffix appended to {@code writer.write}/{@code reader.read} to form the method name. */ + private final String mtd; + + /** Name of the generated collection-descriptor class field, or {@code null} if not needed. */ + @Nullable private final String collDesc; + + /** Whether the {@code compress = true} argument is appended. */ + private final boolean compress; + + /** */ + private FieldCall(String mtd, @Nullable String collDesc, boolean compress) { + this.mtd = mtd; + this.collDesc = collDesc; + this.compress = compress; + } + + /** @return Full call expression; {@code valArg}, when given, is passed as the first argument (write side). */ + private String expr(String mtdPrefix, @Nullable String valArg) { + List args = new ArrayList<>(); + + if (valArg != null) + args.add(valArg); + + if (collDesc != null) + args.add(collDesc); + + if (compress) + args.add("true"); + + return mtdPrefix + mtd + "(" + String.join(", ", args) + ")"; + } + } + /** */ public static String simpleClassName(TypeMirror type) { if (type.getKind() == TypeKind.DECLARED) { diff --git a/modules/codegen/src/main/java/org/apache/ignite/internal/NioField.java b/modules/codegen/src/main/java/org/apache/ignite/internal/NioField.java new file mode 100644 index 0000000000000..d013c56726d7b --- /dev/null +++ b/modules/codegen/src/main/java/org/apache/ignite/internal/NioField.java @@ -0,0 +1,33 @@ +/* + * 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 java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Marks an {@link Order} field, of {@code Message} type, that is read on the network (NIO) thread rather than a + * worker thread. This is for routing headers such as the topic, which must be known before the message can be + * dispatched to a pool. + */ +@Retention(RetentionPolicy.CLASS) +@Target(ElementType.FIELD) +public @interface NioField { +} diff --git a/modules/codegen/src/main/java/org/apache/ignite/internal/idto/IDTOSerializerGenerator.java b/modules/codegen/src/main/java/org/apache/ignite/internal/idto/IDTOSerializerGenerator.java index 3118578540201..5688df94cca91 100644 --- a/modules/codegen/src/main/java/org/apache/ignite/internal/idto/IDTOSerializerGenerator.java +++ b/modules/codegen/src/main/java/org/apache/ignite/internal/idto/IDTOSerializerGenerator.java @@ -17,13 +17,9 @@ package org.apache.ignite.internal.idto; -import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; import java.io.ObjectInput; import java.io.ObjectOutput; -import java.io.PrintWriter; import java.io.Serializable; import java.io.StringWriter; import java.io.Writer; @@ -61,10 +57,11 @@ import org.apache.ignite.lang.IgniteBiTuple; import org.jetbrains.annotations.NotNull; -import static org.apache.ignite.internal.MessageSerializerGenerator.NL; -import static org.apache.ignite.internal.MessageSerializerGenerator.TAB; +import static org.apache.ignite.internal.MessageGenerator.NL; +import static org.apache.ignite.internal.MessageGenerator.TAB; +import static org.apache.ignite.internal.MessageGenerator.identicalFileIsAlreadyGenerated; +import static org.apache.ignite.internal.MessageGenerator.writeLicense; import static org.apache.ignite.internal.MessageSerializerGenerator.enumType; -import static org.apache.ignite.internal.MessageSerializerGenerator.identicalFileIsAlreadyGenerated; import static org.apache.ignite.internal.MessageSerializerGenerator.qualifiedClassName; import static org.apache.ignite.internal.idto.IgniteDataTransferObjectProcessor.DTO_CLASS; @@ -293,16 +290,7 @@ private String generateSerializerCode() throws IOException { * @throws IOException In case of error. */ private void writeClassHeader(Writer writer) throws IOException { - try (InputStream in = getClass().getClassLoader().getResourceAsStream("license.txt"); - BufferedReader reader = new BufferedReader(new InputStreamReader(in))) { - - PrintWriter out = new PrintWriter(writer); - - String line; - - while ((line = reader.readLine()) != null) - out.println(line); - } + writeLicense(writer); writer.write(NL); writer.write("package " + env.getElementUtils().getPackageOf(type).toString() + ";" + NL + NL); diff --git a/modules/codegen/src/main/java/org/apache/ignite/internal/idto/IgniteDataTransferObjectProcessor.java b/modules/codegen/src/main/java/org/apache/ignite/internal/idto/IgniteDataTransferObjectProcessor.java index ae119f63c3ae3..25f1cd441f9a7 100644 --- a/modules/codegen/src/main/java/org/apache/ignite/internal/idto/IgniteDataTransferObjectProcessor.java +++ b/modules/codegen/src/main/java/org/apache/ignite/internal/idto/IgniteDataTransferObjectProcessor.java @@ -17,11 +17,7 @@ package org.apache.ignite.internal.idto; -import java.io.BufferedReader; import java.io.IOException; -import java.io.InputStream; -import java.io.InputStreamReader; -import java.io.PrintWriter; import java.io.StringWriter; import java.io.Writer; import java.util.HashMap; @@ -42,9 +38,10 @@ import javax.tools.Diagnostic; import javax.tools.JavaFileObject; -import static org.apache.ignite.internal.MessageSerializerGenerator.NL; -import static org.apache.ignite.internal.MessageSerializerGenerator.TAB; -import static org.apache.ignite.internal.MessageSerializerGenerator.identicalFileIsAlreadyGenerated; +import static org.apache.ignite.internal.MessageGenerator.NL; +import static org.apache.ignite.internal.MessageGenerator.TAB; +import static org.apache.ignite.internal.MessageGenerator.identicalFileIsAlreadyGenerated; +import static org.apache.ignite.internal.MessageGenerator.writeLicense; import static org.apache.ignite.internal.idto.IDTOSerializerGenerator.CLS_JAVADOC; import static org.apache.ignite.internal.idto.IDTOSerializerGenerator.DTO_SERDES_INTERFACE; import static org.apache.ignite.internal.idto.IDTOSerializerGenerator.simpleName; @@ -227,16 +224,7 @@ private String factoryCode(Map genSerDes) throws IOExceptio * @throws IOException In case of error. */ private void writeClassHeader(Writer writer, Map dtoClss) throws IOException { - try (InputStream in = getClass().getClassLoader().getResourceAsStream("license.txt"); - BufferedReader reader = new BufferedReader(new InputStreamReader(in))) { - - PrintWriter out = new PrintWriter(writer); - - String line; - - while ((line = reader.readLine()) != null) - out.println(line); - } + writeLicense(writer); writer.write(NL); writer.write("package " + FACTORY_PKG_NAME + ";" + NL + NL); diff --git a/modules/control-utility/src/test/java/org/apache/ignite/util/CdcResendCommandTest.java b/modules/control-utility/src/test/java/org/apache/ignite/util/CdcResendCommandTest.java index e259864e68b50..4d6512d15f931 100644 --- a/modules/control-utility/src/test/java/org/apache/ignite/util/CdcResendCommandTest.java +++ b/modules/control-utility/src/test/java/org/apache/ignite/util/CdcResendCommandTest.java @@ -161,7 +161,7 @@ public void testResendConflictVersion() throws Exception { // Override data from clusterId=2. KeyCacheObject key = new KeyCacheObjectImpl(0, null, cachex.affinity().partition(0)); CacheObject val = new CacheObjectImpl(1, null); - val.prepareMarshal(cachex.context().cacheObjectContext()); + val.marshal(cachex.context().cacheObjectContext()); GridCacheVersion conflict = new GridCacheVersion(1, 0, 1, (byte)2); diff --git a/modules/core/pom.xml b/modules/core/pom.xml index 4f5c28a412581..be6674a979781 100644 --- a/modules/core/pom.xml +++ b/modules/core/pom.xml @@ -243,6 +243,13 @@ test + + com.tngtech.archunit + archunit-junit4 + 1.4.1 + test + + com.google.testing.compile compile-testing diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java index 430f5bfbf734f..965da1fa93b2f 100644 --- a/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java +++ b/modules/core/src/main/java/org/apache/ignite/IgniteSystemProperties.java @@ -1908,6 +1908,10 @@ public final class IgniteSystemProperties extends IgniteCommonsSystemProperties @SystemProperty(value = "Packages list to expose in configuration view") public static final String IGNITE_CONFIGURATION_VIEW_PACKAGES = "IGNITE_CONFIGURATION_VIEW_PACKAGES"; + /** Enables the assertion that a message is finish-unmarshalled at most once. For tests; off in production. */ + @SystemProperty("Enables the message finish-unmarshal-once self-check (tests only)") + public static final String IGNITE_MESSAGE_UNMARSHAL_ONCE_CHECK = "IGNITE_MESSAGE_UNMARSHAL_ONCE_CHECK"; + /** * Enforces singleton. */ 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 83cfc507f6000..77695bc2ed7cc 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 @@ -17,7 +17,6 @@ package org.apache.ignite.internal; -import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.internal.binary.BinaryMarshaller; import org.apache.ignite.internal.cache.query.QueryIndexMessage; import org.apache.ignite.internal.cache.query.index.IndexQueryResultMeta; @@ -30,6 +29,7 @@ import org.apache.ignite.internal.managers.communication.GridIoMessage; import org.apache.ignite.internal.managers.communication.GridIoUserMessage; import org.apache.ignite.internal.managers.communication.IgniteIoTestMessage; +import org.apache.ignite.internal.managers.communication.IgniteMessageFactory; import org.apache.ignite.internal.managers.communication.SessionChannelMessage; import org.apache.ignite.internal.managers.deployment.GridDeploymentInfoBean; import org.apache.ignite.internal.managers.deployment.GridDeploymentRequest; @@ -268,7 +268,6 @@ import org.apache.ignite.marshaller.Marshaller; import org.apache.ignite.marshaller.jdk.JdkMarshaller; import org.apache.ignite.plugin.extensions.communication.Message; -import org.apache.ignite.plugin.extensions.communication.MessageFactory; import org.apache.ignite.spi.collision.jobstealing.JobStealingRequest; import org.apache.ignite.spi.communication.tcp.internal.TcpConnectionRequestDiscoveryMessage; import org.apache.ignite.spi.communication.tcp.internal.TcpInverseConnectionResponseMessage; @@ -327,26 +326,25 @@ public class CoreMessagesProvider extends AbstractMarshallableMessageFactoryProv private short msgIdx; /** */ - private @Nullable MessageFactory factory; + private @Nullable IgniteMessageFactory factory; /** * Default plugin-purposes constructor. * - * @see #init(Marshaller, Marshaller, ClassLoader) + * @see #init(Marshaller, Marshaller) */ public CoreMessagesProvider() { // No-op. } /** - * Constructor allowing not to call {@link #init(Marshaller, Marshaller, ClassLoader)}. + * Constructor allowing not to call {@link #init(Marshaller, Marshaller)}. * * @param dfltMarsh Schema-less marshaller like {@link JdkMarshaller}. * @param schemaAwareMarsh Schema-aware marshaller like {@link BinaryMarshaller}. - * @param resolvedClsLdr Resolved (configured) class loader like {@link IgniteConfiguration#setClassLoader(ClassLoader)}. */ - public CoreMessagesProvider(Marshaller dfltMarsh, Marshaller schemaAwareMarsh, ClassLoader resolvedClsLdr) { - init(dfltMarsh, schemaAwareMarsh, resolvedClsLdr); + public CoreMessagesProvider(Marshaller dfltMarsh, Marshaller schemaAwareMarsh) { + init(dfltMarsh, schemaAwareMarsh); } /** @@ -354,7 +352,7 @@ public CoreMessagesProvider(Marshaller dfltMarsh, Marshaller schemaAwareMarsh, C * The listing order is important here. If wish to remove a message, put 'msgIdx++' on its place. If wish to add, * put it to end of a group. */ - @Override public void registerAll(MessageFactory factory) { + @Override public void registerAll(IgniteMessageFactory factory) { assert this.factory == null; this.factory = factory; @@ -366,7 +364,7 @@ public CoreMessagesProvider(Marshaller dfltMarsh, Marshaller schemaAwareMarsh, C // [5000 - 5500]: Utility messages. Most of them originally come from Discovery. msgIdx = 5000; withNoSchema(CompressedMessage.class); - withNoSchemaResolvedClassLoader(ErrorMessage.class); + withNoSchema(ErrorMessage.class); withNoSchema(InetSocketAddressMessage.class); withNoSchema(InetAddressMessage.class); withNoSchema(TcpDiscoveryNode.class); @@ -374,8 +372,8 @@ public CoreMessagesProvider(Marshaller dfltMarsh, Marshaller schemaAwareMarsh, C withNoSchema(GridByteArrayList.class); withNoSchema(CacheVersionedValue.class); withNoSchema(WALPointer.class); - withNoSchemaResolvedClassLoader(SerializableDataBagItemWrapper.class); - withSchemaResolvedClassLoader(GridTopicMessage.class); + withNoSchema(SerializableDataBagItemWrapper.class); + withSchema(GridTopicMessage.class); withNoSchema(GridIntList.class); // [5700 - 5900]: Discovery originated messages. @@ -472,12 +470,12 @@ public CoreMessagesProvider(Marshaller dfltMarsh, Marshaller schemaAwareMarsh, C withNoSchema(CacheStatisticsClearMessage.class); withNoSchema(ClientCacheChangeDummyDiscoveryMessage.class); withNoSchema(DynamicCacheChangeBatch.class); - withNoSchemaResolvedClassLoader(CacheClientReconnectDiscoveryData.class); - withNoSchemaResolvedClassLoader(CacheGroupRecoveryState.class); - withNoSchemaResolvedClassLoader(CacheJoinInfo.class); - withNoSchemaResolvedClassLoader(CacheJoinNodeDiscoveryData.class); - withNoSchemaResolvedClassLoader(CacheReconnectInfo.class); - withNoSchemaResolvedClassLoader(ClusterCacheGroupRecoveryData.class); + withNoSchema(CacheClientReconnectDiscoveryData.class); + withNoSchema(CacheGroupRecoveryState.class); + withNoSchema(CacheJoinInfo.class); + withNoSchema(CacheJoinNodeDiscoveryData.class); + withNoSchema(CacheReconnectInfo.class); + withNoSchema(ClusterCacheGroupRecoveryData.class); // [10000 - 10200]: Transaction and lock related messages. Most of them originally comes from Communication. msgIdx = 10000; @@ -549,7 +547,7 @@ public CoreMessagesProvider(Marshaller dfltMarsh, Marshaller schemaAwareMarsh, C withNoSchema(StartRequestData.class); withNoSchema(StartRoutineAckDiscoveryMessage.class); withNoSchema(StartRoutineDiscoveryMessage.class); - withNoSchemaResolvedClassLoader(StoredCacheData.class); + withNoSchema(StoredCacheData.class); // [10600-10800]: Affinity & partition maps. msgIdx = 10600; @@ -677,7 +675,7 @@ public CoreMessagesProvider(Marshaller dfltMarsh, Marshaller schemaAwareMarsh, C withNoSchema(MetadataRequestMessage.class); withNoSchema(MetadataResponseMessage.class); withNoSchema(MarshallerMappingItem.class); - withSchemaResolvedClassLoader(BinaryMetadataVersionInfo.class); + withSchema(BinaryMetadataVersionInfo.class); withNoSchema(CacheBinaryDataBagItem.class); withNoSchema(MappedName.class); withNoSchema(MarshallerDataBagItem.class); @@ -701,12 +699,12 @@ public CoreMessagesProvider(Marshaller dfltMarsh, Marshaller schemaAwareMarsh, C withNoSchema(IgniteDiagnosticResponse.class); withNoSchema(WalStateAckMessage.class); withNoSchema(CacheConfigurationEnrichment.class); - withNoSchemaResolvedClassLoader(DynamicCacheChangeRequest.class); + withNoSchema(DynamicCacheChangeRequest.class); withNoSchema(PartitionHashRecord.class); withNoSchema(TransactionsHashRecord.class); withNoSchema(ClusterIdAndTag.class); withNoSchema(ClusterUpdateNotifierDataBagItem.class); - withNoSchemaResolvedClassLoader(PluginsDataBagItem.class); + withNoSchema(PluginsDataBagItem.class); withSchema(EventsDataBagItem.class); // [13400 - 13500]: Operation context messages. @@ -724,28 +722,18 @@ public CoreMessagesProvider(Marshaller dfltMarsh, Marshaller schemaAwareMarsh, C assert msgIdx <= MAX_MESSAGE_ID; } - /** Registers message using {@link #dfltMarsh} and {@link #dftlClsLdr}. */ + /** Registers message using {@link #dfltMarsh}. */ private void withNoSchema(Class cls) { - register(cls, dfltMarsh, dftlClsLdr); + register(cls, dfltMarsh); } - /** Registers message using {@link #schemaAwareMarsh} and {@link #dftlClsLdr}. */ + /** Registers message using {@link #schemaAwareMarsh}. */ private void withSchema(Class cls) { - register(cls, schemaAwareMarsh, dftlClsLdr); - } - - /** Registers message using {@link #dfltMarsh} and {@link #resolvedClsLdr}. */ - private void withNoSchemaResolvedClassLoader(Class cls) { - register(cls, dfltMarsh, resolvedClsLdr); - } - - /** Registers message using {@link #schemaAwareMarsh} and {@link #resolvedClsLdr}. */ - private void withSchemaResolvedClassLoader(Class cls) { - register(cls, schemaAwareMarsh, resolvedClsLdr); + register(cls, schemaAwareMarsh); } /** Registers message using incrementing {@link #msgIdx} as the message id/type. */ - private void register(Class cls, Marshaller marsh, ClassLoader clsLrd) { - register(factory, cls, msgIdx++, marsh, clsLrd); + private void register(Class cls, Marshaller marsh) { + register(factory, cls, msgIdx++, marsh); } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/DeferredUnmarshalMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/DeferredUnmarshalMessage.java new file mode 100644 index 0000000000000..74f8bd846a52d --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/DeferredUnmarshalMessage.java @@ -0,0 +1,32 @@ +/* + * 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.plugin.extensions.communication.Message; + +/** + * A {@link Message} whose payload is unmarshalled by the consumer on its own execution path instead of the generic + * inbound pass of {@code GridIoManager}. The consumer is responsible for unmarshalling every remotely received + * message exactly once, and gains what the generic pass cannot offer: the proper thread pool instead of a NIO + * thread (Calcite messages in the query task executor), the peer-deployment class loader able to see user classes + * instead of the configuration one, and a protocol-level failure response to the sender (cache messages in + * {@code GridCacheIoManager}, data streamer entries in the update job, continuous-query entries in + * {@code CacheContinuousQueryHandler}). + */ +public interface DeferredUnmarshalMessage extends Message { +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridEventConsumeHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/GridEventConsumeHandler.java index 1ac2ce2bc9227..cad29b7b12909 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/GridEventConsumeHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/GridEventConsumeHandler.java @@ -563,7 +563,7 @@ void p2pUnmarshal(Marshaller marsh, @Nullable ClassLoader ldr) throws IgniteChec } /** {@inheritDoc} */ - @Override public void prepare(GridDeploymentInfo depInfo) { + @Override public void deploy(GridDeploymentInfo depInfo) { assert evt instanceof CacheEvent; this.depInfo = depInfo; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridJobExecuteRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/GridJobExecuteRequest.java index 37e23f5b8b9a0..376d05db9db07 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/GridJobExecuteRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/GridJobExecuteRequest.java @@ -451,7 +451,7 @@ public AffinityTopologyVersion topologyVersion() { /** * @param marsh Marshaller. */ - public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { + public void marshal(Marshaller marsh) throws IgniteCheckedException { jobBytes = U.marshal(marsh, job); topPredBytes = U.marshal(marsh, topPred); siblingsBytes = U.marshal(marsh, siblings); @@ -463,7 +463,7 @@ public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { * @param marsh Marshaller. * @param ldr Class loader. */ - public void finishUnmarshal(Marshaller marsh, ClassLoader ldr) throws IgniteCheckedException { + public void unmarshal(Marshaller marsh, ClassLoader ldr) throws IgniteCheckedException { assert top != null || topPredBytes != null; assert sesAttrsBytes != null || !sesFullSup; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridJobSiblingsResponse.java b/modules/core/src/main/java/org/apache/ignite/internal/GridJobSiblingsResponse.java index 99f537e9ab325..d31c9fff4aeef 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/GridJobSiblingsResponse.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/GridJobSiblingsResponse.java @@ -18,19 +18,18 @@ package org.apache.ignite.internal; import java.util.Collection; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.compute.ComputeJobSibling; import org.apache.ignite.internal.util.typedef.internal.S; -import org.apache.ignite.internal.util.typedef.internal.U; -import org.apache.ignite.marshaller.Marshaller; +import org.apache.ignite.plugin.extensions.communication.Message; import org.jetbrains.annotations.Nullable; /** * Job siblings response. */ -public class GridJobSiblingsResponse implements MarshallableMessage { +public class GridJobSiblingsResponse implements Message { /** */ - private @Nullable Collection siblings; + @Marshalled("siblingsBytes") + @Nullable Collection siblings; /** */ @Order(0) @@ -57,23 +56,6 @@ public GridJobSiblingsResponse(@Nullable Collection siblings) return siblings; } - /** {@inheritDoc} */ - @Override public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { - if (siblings != null) - siblingsBytes = U.marshal(marsh, siblings); - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { - assert marsh != null; - - if (siblingsBytes != null) { - siblings = U.unmarshal(marsh, siblingsBytes, null); - - siblingsBytes = null; - } - } - /** {@inheritDoc} */ @Override public String toString() { return S.toString(GridJobSiblingsResponse.class, this); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/GridTopicMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/GridTopicMessage.java index 2f34b53f27360..71251ddd84bf2 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/GridTopicMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/GridTopicMessage.java @@ -60,13 +60,13 @@ public static int ordinal(GridTopicMessage msg) { } /** {@inheritDoc} */ - @Override public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { + @Override public void marshal(Marshaller marsh) throws IgniteCheckedException { if (ord < 0 && topic != null) topicBytes = U.marshal(marsh, topic); } /** {@inheritDoc} */ - @Override public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { + @Override public void unmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { if (ord < 0 && topicBytes != null) { topic = U.unmarshal(marsh, topicBytes, clsLdr); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java index 063774e7b13b5..dfbf768541cc9 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/IgniteKernal.java @@ -222,6 +222,7 @@ import org.apache.ignite.thread.IgniteThread; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import org.jetbrains.annotations.TestOnly; import static java.util.Collections.singleton; import static java.util.Optional.ofNullable; @@ -1318,15 +1319,19 @@ else if (e instanceof IgniteCheckedException) startTimer.finishGlobalStage("Await exchange"); } + /** Test entry to {@link #initMessageFactory()}, which production reaches via {@link #start}. */ + @TestOnly + public void initMessageFactoryForTest() throws IgniteCheckedException { + initMessageFactory(); + } + /** */ private void initMessageFactory() throws IgniteCheckedException { MessageFactoryProvider[] msgs = ctx.plugins().extensions(MessageFactoryProvider.class); List compMsgs = new ArrayList<>(); - ClassLoader resolvedClsLdr = U.resolveClassLoader(ctx.config()); - - compMsgs.add(new CoreMessagesProvider(ctx.marshallerContext().jdkMarshaller(), ctx.marshaller(), resolvedClsLdr)); + compMsgs.add(new CoreMessagesProvider(ctx.marshallerContext().jdkMarshaller(), ctx.marshaller())); for (IgniteComponentType compType : IgniteComponentType.values()) { MessageFactoryProvider f = compType.messageFactory(); @@ -1348,21 +1353,20 @@ private void initMessageFactory() throws IgniteCheckedException { msgs = F.concat(msgs, compMsgs.toArray(new MessageFactoryProvider[compMsgs.size()])); for (MessageFactoryProvider msg : msgs) - initProvider(msg, resolvedClsLdr); + initProvider(msg); msgFactory = new IgniteMessageFactoryImpl(msgs); } /** - * Re-init {@link AbstractMarshallableMessageFactoryProvider} with a proper marshaller and classloader. + * Re-init {@link AbstractMarshallableMessageFactoryProvider} with a proper marshaller. * * @param factoryProvider Message factory provider. - * @param clsLdr Class loader. */ - private void initProvider(MessageFactoryProvider factoryProvider, ClassLoader clsLdr) { + private void initProvider(MessageFactoryProvider factoryProvider) { if (factoryProvider instanceof AbstractMarshallableMessageFactoryProvider) { ((AbstractMarshallableMessageFactoryProvider)factoryProvider).init(ctx.marshallerContext().jdkMarshaller(), - ctx.marshaller(), clsLdr); + ctx.marshaller()); } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/MarshallableMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/MarshallableMessage.java index 72b67ab2c4afd..b90bae6eb0778 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/MarshallableMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/MarshallableMessage.java @@ -21,14 +21,14 @@ import org.apache.ignite.marshaller.Marshaller; import org.apache.ignite.plugin.extensions.communication.Message; -/** A {@link Message} which still requires external custom pre-marshalling and post-unmarshalling. */ +/** A {@link Message} requiring a custom marshal/unmarshal step via {@link Marshaller}. */ public interface MarshallableMessage extends Message { - /** @param marsh External custom marshaller. */ - public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException; + /** @param marsh Marshaller for marshalling. */ + public void marshal(Marshaller marsh) throws IgniteCheckedException; /** - * @param marsh External custom marshaller. - * @param clsLdr External class loader to post-unmarshall. + * @param marsh Marshaller for unmarshalling. + * @param clsLdr Class loader for unmarshalling. */ - public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException; + public void unmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException; } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/TxEntriesInfo.java b/modules/core/src/main/java/org/apache/ignite/internal/TxEntriesInfo.java index a5a9fcc6bc2f7..d2999ac6b455d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/TxEntriesInfo.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/TxEntriesInfo.java @@ -20,14 +20,17 @@ import java.util.Collection; import java.util.HashSet; import java.util.Objects; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheMapEntry; import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.plugin.extensions.communication.CacheIdAware; -/** */ -public final class TxEntriesInfo extends IgniteDiagnosticRequest.DiagnosticBaseInfo { +/** + * Diagnostic info block that dumps the state of cache entries for the given keys. Requested when a transaction + * lock future waits for a remote node's response for too long. + */ +public final class TxEntriesInfo extends IgniteDiagnosticRequest.DiagnosticBaseInfo implements CacheIdAware { /** */ @Order(0) int cacheId; @@ -52,7 +55,6 @@ public TxEntriesInfo() { this.keys = new HashSet<>(keys); } - /** {@inheritDoc} */ @Override public void appendInfo(StringBuilder sb, GridKernalContext ctx) { sb.append(U.nl()); @@ -65,16 +67,6 @@ public TxEntriesInfo() { return; } - try { - for (KeyCacheObject key : keys) - key.finishUnmarshal(cctx.cacheObjectContext(), null); - } - catch (IgniteCheckedException e) { - ctx.cluster().diagnosticLog().error("Failed to unmarshal key: " + e, e); - - sb.append("Failed to unmarshal key: ").append(e).append(U.nl()); - } - sb.append("Cache entries [cacheId=").append(cacheId) .append(", cacheName=").append(cctx.name()).append("]: "); @@ -111,4 +103,9 @@ public TxEntriesInfo() { @Override public int hashCode() { return Objects.hash(getClass(), cacheId); } + + /** {@inheritDoc} */ + @Override public int cacheId() { + return cacheId; + } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/direct/stream/DirectByteBufferStream.java b/modules/core/src/main/java/org/apache/ignite/internal/direct/stream/DirectByteBufferStream.java index ada462de4f370..6b673aa88d469 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/direct/stream/DirectByteBufferStream.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/direct/stream/DirectByteBufferStream.java @@ -41,6 +41,7 @@ import org.apache.ignite.internal.processors.cacheobject.IgniteCacheObjectProcessor; import org.apache.ignite.internal.util.GridLongList; import org.apache.ignite.internal.util.GridUnsafe; +import org.apache.ignite.internal.util.nio.MessageSerialization; import org.apache.ignite.internal.util.tostring.GridToStringExclude; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; @@ -927,7 +928,7 @@ public void writeGridLongList(@Nullable GridLongList val) { public void writeMessage(Message msg, MessageWriter writer) { if (msg != null) { if (buf.hasRemaining()) - nestedWrite(writer, () -> msgFactory.serializer(msg.directType()).writeTo(msg, writer)); + nestedWrite(writer, () -> MessageSerialization.writeTo(msgFactory, msg, writer)); else lastFinished = false; } @@ -1573,7 +1574,7 @@ public T readMessage(MessageReader reader) { try { reader.beforeNestedRead(); - lastFinished = msgFactory.serializer(msg.directType()).readFrom(msg, reader); + lastFinished = MessageSerialization.readFrom(msgFactory, msg, reader); } finally { reader.afterNestedRead(lastFinished); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/CompressedMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/CompressedMessage.java index 57756c385848c..8b302db06035f 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/CompressedMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/CompressedMessage.java @@ -26,14 +26,14 @@ import java.util.zip.Inflater; import org.apache.ignite.IgniteException; import org.apache.ignite.internal.util.typedef.internal.S; -import org.apache.ignite.plugin.extensions.communication.Message; +import org.apache.ignite.plugin.extensions.communication.NonMarshallableMessage; /** * Internal message used when transmitting fields annotated with @Compress over the network. *

* WARNING: CompressedMessage is not intended for explicit use in messages. */ -public class CompressedMessage implements Message { +public class CompressedMessage implements NonMarshallableMessage { /** Chunk size. */ static final int CHUNK_SIZE = 10 * 1024; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/ErrorMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/ErrorMessage.java index 02bb9ec0af99a..8ab1f9eb5a4d0 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/ErrorMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/ErrorMessage.java @@ -29,6 +29,7 @@ /** * Message used to transfer {@link Throwable} objects. */ +// TODO IGNITE-28912: move to a common package. @SuppressWarnings({"NullableProblems", "unused"}) public class ErrorMessage implements MarshallableMessage { /** Error bytes. */ @@ -54,7 +55,7 @@ public ErrorMessage(@Nullable Throwable err) { } /** {@inheritDoc} */ - @Override public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { + @Override public void marshal(Marshaller marsh) throws IgniteCheckedException { if (err == null) return; @@ -67,7 +68,7 @@ public ErrorMessage(@Nullable Throwable err) { } /** {@inheritDoc} */ - @Override public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { + @Override public void unmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { if (errBytes == null) return; 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 08befbe25008a..19ad848aad223 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 @@ -76,6 +76,7 @@ import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.events.DiscoveryEvent; import org.apache.ignite.events.Event; +import org.apache.ignite.internal.DeferredUnmarshalMessage; import org.apache.ignite.internal.GridKernalContext; import org.apache.ignite.internal.GridTopic; import org.apache.ignite.internal.IgniteClientDisconnectedCheckedException; @@ -468,6 +469,9 @@ public void resetMetrics() { msg.getClass().getName() + ". Most likely GridCommunicationSpi is being used directly, " + "which is illegal - make sure to send messages only via GridProjection API."); } + catch (IgniteCheckedException e) { + throw new IgniteException(e); + } } @Override public void onDisconnected(UUID nodeId) { @@ -501,6 +505,8 @@ public void resetMetrics() { msg0.senderNodeId(nodeId); + msg0.onAfterRead(); + if (msg0.request()) { IgniteIoTestMessage res = new IgniteIoTestMessage(msg0.id(), false, null); @@ -510,6 +516,8 @@ public void resetMetrics() { res.copyDataFromRequest(msg0); try { + res.onBeforeWrite(); + sendToGridTopic(node, GridTopic.TOPIC_IO_TEST, res, GridIoPolicy.SYSTEM_POOL); } catch (IgniteCheckedException e) { @@ -554,6 +562,8 @@ public IgniteInternalFuture sendIoTest(List nodes, byte[] payload, ioTestMap().put(id, fut); + msg.onBeforeWrite(); + for (int i = 0; i < nodes.size(); i++) { ClusterNode node = nodes.get(i); @@ -591,6 +601,8 @@ public IgniteInternalFuture> sendIoTest( ioTestMap().put(id, fut); + msg.onBeforeWrite(); + try { sendToGridTopic(node, GridTopic.TOPIC_IO_TEST, msg, GridIoPolicy.SYSTEM_POOL); } @@ -1175,10 +1187,22 @@ private void onChannelOpened0(UUID rmtNodeId, GridIoMessage initMsg, Channel cha byte plc = initMsg.policy(); + // Not a double unmarshal: the @NioField routing header is restored here on the NIO thread, its full + // payload below on a pool thread — disjoint fields. + MessageMarshalling.unmarshalNio(initMsg, ctx); + pools.poolForPolicy(plc).execute(new Runnable() { @Override public void run() { - processOpenedChannel(initMsg.topic(), rmtNodeId, (SessionChannelMessage)initMsg.message(), - (SocketChannel)channel); + try { + MessageMarshalling.unmarshal(initMsg, ctx); + + processOpenedChannel(initMsg.topic(), rmtNodeId, (SessionChannelMessage)initMsg.message(), + (SocketChannel)channel); + } + catch (IgniteCheckedException e) { + U.error(log, "Failed to process channel creation event due to exception " + + "[rmtNodeId=" + rmtNodeId + ", initMsg=" + initMsg + ']', e); + } } }); } @@ -1196,7 +1220,7 @@ private void onChannelOpened0(UUID rmtNodeId, GridIoMessage initMsg, Channel cha * @param msg Message bytes. * @param msgC Closure to call when message processing finished. */ - private void onMessage0(UUID nodeId, GridIoMessage msg, IgniteRunnable msgC) { + private void onMessage0(UUID nodeId, GridIoMessage msg, IgniteRunnable msgC) throws IgniteCheckedException { assert nodeId != null; assert msg != null; @@ -1241,6 +1265,10 @@ private void onMessage0(UUID nodeId, GridIoMessage msg, IgniteRunnable msgC) { } } + // After the delayed-message gate: a replayed message re-enters this method, so its NIO-thread header + // unmarshal is kept here to run exactly once. + MessageMarshalling.unmarshalNio(msg, ctx); + // If message is P2P, then process in P2P service. // This is done to avoid extra waiting and potential deadlocks // as thread pool may not have any available threads to give. @@ -1307,16 +1335,7 @@ private void processP2PMessage( try { threadProcessingMessage(true, msgC); - GridMessageListener lsnr = listenerGet0(msg.topic()); - - if (lsnr == null) - return; - - Object obj = msg.message(); - - assert obj != null; - - invokeListener(msg.policy(), lsnr, nodeId, obj); + processRegularMessage0(msg, nodeId); } finally { threadProcessingMessage(false, null); @@ -1450,11 +1469,22 @@ private void processRegularMessage0(GridIoMessage msg, UUID nodeId) { if (lsnr == null) return; - Object obj = msg.message(); + unmarshalPayload(msg); - assert obj != null; + invokeListener(msg.policy(), lsnr, nodeId, msg.message()); + } - invokeListener(msg.policy(), lsnr, nodeId, obj); + /** */ + private void unmarshalPayload(GridIoMessage msg) { + if (msg.message() instanceof DeferredUnmarshalMessage) + return; + + try { + MessageMarshalling.unmarshal(msg.message(), ctx); + } + catch (IgniteCheckedException e) { + throw new IgniteException("Failed to unmarshal message payload", e); + } } /** @@ -1942,6 +1972,8 @@ private IgniteInternalFuture openChannel( false ); + marshal(ioMsg); + try { return ((TcpCommunicationSpi)(CommunicationSpi)getSpi()).openChannel(node, ioMsg); } @@ -1992,7 +2024,6 @@ private void send( GridIoMessage ioMsg = createGridIoMessage(topic, msg, plc, ordered, timeout, skipOnTimeout); if (locNodeId.equals(node.id())) { - assert plc != P2P_POOL; CommunicationListener commLsnr = this.commLsnr; @@ -2011,25 +2042,162 @@ else if (async) ackC.apply(null); } else { - try { - if ((CommunicationSpi)getSpi() instanceof TcpCommunicationSpi) - getTcpCommunicationSpi().sendMessage(node, ioMsg, ackC); - else - getSpi().sendMessage(node, ioMsg); - } - catch (IgniteSpiException e) { - if (e.getCause() instanceof ClusterTopologyCheckedException) - throw (ClusterTopologyCheckedException)e.getCause(); + marshal(ioMsg); - if (!ctx.discovery().alive(node)) - throw new ClusterTopologyCheckedException("Failed to send message, node left: " + node.id(), e); + sendMarshalled(node, ioMsg, ackC); + } + } + } + + /** + * Wraps {@code msg} into a marshalled {@link GridIoMessage} without sending it. Message marshalling is not + * idempotent (see {@code MessageMarshalOnceTest}), so {@link #sendWithRetry} prepares the message once and + * re-sends it via {@link #sendPrepared} on each attempt. + */ + private GridIoMessage prepare(Object topic, Message msg, byte plc, boolean ordered, long timeout, + boolean skipOnTimeout) throws IgniteCheckedException { + assert !ordered || timeout > 0 || skipOnTimeout; + + GridIoMessage ioMsg = createGridIoMessage(topic, msg, plc, ordered, timeout, skipOnTimeout); + + marshal(ioMsg); + + return ioMsg; + } + + /** + * Marshals {@code ioMsg} enforcing the marshal-once contract: a wrap is marshalled exactly once before + * transmission (marshalling is not idempotent, see {@code MessageMarshalOnceTest}). + */ + private void marshal(GridIoMessage ioMsg) throws IgniteCheckedException { + assert !ioMsg.marshalled() : "GridIoMessage is marshalled twice: " + ioMsg; + + MessageMarshalling.marshal(ioMsg, ctx, null); + + ioMsg.markMarshalled(); + } + + /** + * Sends a message created by {@link #prepare} to a remote node. Sending does not mutate the message, + * so it can be safely retried. + */ + public void sendPrepared(ClusterNode node, GridIoMessage ioMsg) throws IgniteCheckedException { + assert !locNodeId.equals(node.id()) : node; + assert ioMsg.marshalled() : "Message must be prepared via prepare() before sendPrepared(): " + ioMsg; - throw new IgniteCheckedException("Failed to send message (node may have left the grid or " + - "TCP connection cannot be established due to firewall issues) " + - "[node=" + node + ", topic=" + topic + - ", msg=" + msg + ", policy=" + plc + ']', e); + try (TraceSurroundings ignored = support(null)) { + sendMarshalled(node, ioMsg, null); + } + } + + /** + * Sends a message to a remote node, marshalling it once and retrying only the transmission: repeat failed + * attempts reuse the prepared message. Waits {@code IgniteConfiguration#getNetworkSendRetryDelay()} between + * attempts; {@code retryPlc} decides whether an attempt failure is retried. + * + * @param node Destination node. + * @param topic Topic to send the message to. + * @param msg Message to send. + * @param plc Type of processing. + * @param ordered Ordered flag. + * @param timeout Timeout to keep a message on receiving queue. + * @param skipOnTimeout Whether message can be skipped on timeout. + * @param retryPlc Failure policy. + */ + public void sendWithRetry(ClusterNode node, Object topic, Message msg, byte plc, boolean ordered, long timeout, + boolean skipOnTimeout, SendRetryPolicy retryPlc) throws IgniteCheckedException { + GridIoMessage ioMsg = prepare(topic, msg, plc, ordered, timeout, skipOnTimeout); + + for (int attempt = 1;; attempt++) { + try { + sendPrepared(node, ioMsg); + + return; + } + catch (ClusterTopologyCheckedException e) { + throw e; + } + catch (IgniteCheckedException e) { + if (!retryPlc.onFailure(node, e, attempt)) + throw e; + } + + U.sleep(ctx.config().getNetworkSendRetryDelay()); + } + } + + /** Failure policy for {@link #sendWithRetry}: decides whether a failed transmission attempt is retried. */ + @FunctionalInterface public interface SendRetryPolicy { + /** + * @param node Destination node of the failed attempt. + * @param e Transmission failure. + * @param attempt Failed attempt number, starting with {@code 1}. + * @return {@code true} to retry, {@code false} to rethrow {@code e}. + * @throws IgniteCheckedException To replace {@code e} with a more specific failure. + */ + public boolean onFailure(ClusterNode node, IgniteCheckedException e, int attempt) throws IgniteCheckedException; + } + + /** + * Sends an already-marshalled message to a remote node. Marshalling is the caller's job, so one {@code ioMsg} can + * be prepared once and delivered to many nodes (see {@link #sendToMany}). + */ + private void sendMarshalled(ClusterNode node, GridIoMessage ioMsg, IgniteInClosure ackC) + throws IgniteCheckedException { + assert ioMsg.marshalled() : "GridIoMessage is transmitted unmarshalled: " + ioMsg; + + try { + if ((CommunicationSpi)getSpi() instanceof TcpCommunicationSpi) + getTcpCommunicationSpi().sendMessage(node, ioMsg, ackC); + else + getSpi().sendMessage(node, ioMsg); + } + catch (IgniteSpiException e) { + if (e.getCause() instanceof ClusterTopologyCheckedException) + throw (ClusterTopologyCheckedException)e.getCause(); + + if (!ctx.discovery().alive(node)) + throw new ClusterTopologyCheckedException("Failed to send message, node left: " + node.id(), e); + + throw new IgniteCheckedException("Failed to send message (node may have left the grid or " + + "TCP connection cannot be established due to firewall issues) " + + "[node=" + node + ", topic=" + ioMsg.topic() + + ", msg=" + ioMsg.message() + ", policy=" + ioMsg.policy() + ']', e); + } + } + + /** + * Marshals {@code msg} once and delivers it to every node, instead of re-marshalling per destination. The local + * node, if present, goes through the regular per-node path, unmarshalled. + */ + private void sendToMany(Collection nodes, Object topic, Message msg, byte plc, + boolean ordered, long timeout, boolean skipOnTimeout) throws IgniteCheckedException { + try (TraceSurroundings ignored = support(null)) { + GridIoMessage ioMsg = null; + + IgniteCheckedException err = null; + + for (ClusterNode node : nodes) { + try { + if (locNodeId.equals(node.id())) + send(node, topic, msg, plc, ordered, timeout, skipOnTimeout, null, false); + else { + if (ioMsg == null) + ioMsg = prepare(topic, msg, plc, ordered, timeout, skipOnTimeout); + + sendMarshalled(node, ioMsg, null); + } + } + catch (IgniteCheckedException e) { + if (err == null) + err = e; + else + err.addSuppressed(e); } } + + if (err != null) + throw err; } } @@ -2185,22 +2353,7 @@ void sendOrderedMessageToGridTopic( throws IgniteCheckedException { assert timeout > 0 || skipOnTimeout; - IgniteCheckedException err = null; - - for (ClusterNode node : nodes) { - try { - send(node, topic, msg, plc, true, timeout, skipOnTimeout, null, false); - } - catch (IgniteCheckedException e) { - if (err == null) - err = e; - else - err.addSuppressed(e); - } - } - - if (err != null) - throw err; + sendToMany(nodes, topic, msg, plc, true, timeout, skipOnTimeout); } /** @@ -2216,22 +2369,7 @@ public void sendToGridTopic( Message msg, byte plc ) throws IgniteCheckedException { - IgniteCheckedException err = null; - - for (ClusterNode node : nodes) { - try { - send(node, topic, msg, plc, false, 0, false, null, false); - } - catch (IgniteCheckedException e) { - if (err == null) - err = e; - else - err.addSuppressed(e); - } - } - - if (err != null) - throw err; + sendToMany(nodes, topic, msg, plc, false, 0, false); } /** @@ -3809,7 +3947,19 @@ void unwind(GridMessageListener lsnr) { MTC.span().addTag(SpanTags.MESSAGE, () -> traceName(fmc.message)); - invokeListener(plc, lsnr, nodeId, mc.message.message()); + try { + unmarshalPayload(mc.message); + } + catch (IgniteException e) { + // Skip the poisoned message: rethrowing would abandon the rest of the set until + // the next message arrives on this topic. + U.error(log, "Failed to unmarshal ordered message (will skip) [nodeId=" + nodeId + + ", msg=" + mc.message + ']', e); + + continue; + } + + invokeListener(mc.message.policy(), lsnr, nodeId, mc.message.message()); } finally { if (mc.closure != null) 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 8296b60f81e92..e0b690f1f1719 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.NioField; import org.apache.ignite.internal.OperationContextMessage; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.cache.GridCacheMessage; @@ -42,6 +43,7 @@ public class GridIoMessage implements Message, SpanTransport, MessageWrapper { byte plc; /** Topic message. */ + @NioField @Order(1) @GridToStringInclude GridTopicMessage topicMsg; @@ -71,6 +73,9 @@ public class GridIoMessage implements Message, SpanTransport, MessageWrapper { @GridToStringInclude public @Nullable OperationContextMessage opCtxMsg; + /** Set once the payload is marshalled; guards double marshal and unmarshalled transmit. Not on the wire. */ + private transient boolean marshalled; + /** * Default constructor. */ @@ -145,6 +150,16 @@ public boolean skipOnTimeout() { return skipOnTimeout; } + /** Marks this message as marshalled. */ + void markMarshalled() { + marshalled = true; + } + + /** @return {@code true} if this message has been marshalled. */ + boolean marshalled() { + return marshalled; + } + /** * @return {@code True} if message is ordered, {@code false} otherwise. */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/IgniteIoTestMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/IgniteIoTestMessage.java index d95ead4f902de..897d627f7f87c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/IgniteIoTestMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/IgniteIoTestMessage.java @@ -18,16 +18,14 @@ package org.apache.ignite.internal.managers.communication; import java.util.UUID; -import org.apache.ignite.IgniteCheckedException; -import org.apache.ignite.internal.MarshallableMessage; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.util.typedef.internal.S; -import org.apache.ignite.marshaller.Marshaller; +import org.apache.ignite.plugin.extensions.communication.Message; /** * */ -public class IgniteIoTestMessage implements MarshallableMessage { +public class IgniteIoTestMessage implements Message { /** */ private static final byte FLAG_PROC_FROM_NIO = 1; @@ -240,10 +238,7 @@ public long responseReceivedTsMillis() { return resRcvTsMillis; } - /** - * This method is called to initialize tracing variables. - * TODO: introduce direct message lifecycle API? - */ + /** Captures the received timestamp at the first call; later calls are no-ops. */ public void onAfterRead() { if (req && reqRcvTs == 0) { reqRcvTs = System.nanoTime(); @@ -258,10 +253,7 @@ public void onAfterRead() { } } - /** - * This method is called to initialize tracing variables. - * TODO: introduce direct message lifecycle API? - */ + /** Captures the sending timestamp at the first call; later calls are no-ops. */ public void onBeforeWrite() { if (req && reqSndTs == 0) { reqSndTs = System.nanoTime(); @@ -324,16 +316,6 @@ public void senderNodeId(UUID sndNodeId) { this.sndNodeId = sndNodeId; } - /** {@inheritDoc} */ - @Override public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { - onBeforeWrite(); - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { - onAfterRead(); - } - /** {@inheritDoc} */ @Override public String toString() { return S.toString(IgniteIoTestMessage.class, this); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/IgniteMessageFactory.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/IgniteMessageFactory.java new file mode 100644 index 0000000000000..13c8760b4c34f --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/IgniteMessageFactory.java @@ -0,0 +1,92 @@ +/* + * 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.managers.communication; + +import java.util.function.Supplier; +import org.apache.ignite.IgniteException; +import org.apache.ignite.internal.processors.cache.GridCacheMessage; +import org.apache.ignite.internal.processors.cache.GridCacheMessageDeployer; +import org.apache.ignite.plugin.extensions.communication.Message; +import org.apache.ignite.plugin.extensions.communication.MessageFactory; +import org.apache.ignite.plugin.extensions.communication.MessageMarshaller; +import org.apache.ignite.plugin.extensions.communication.MessageSerializer; +import org.jetbrains.annotations.Nullable; + +/** + * Internal extension of {@link MessageFactory} that also registers and resolves the marshal and deployment + * companions of a message. Kept out of the public factory interface: marshallers and deployers are bound to + * kernal and cache internals ({@code GridKernalContext}, {@code GridCacheSharedContext}) the public SPI module + * must not depend on. + * + * @see MessageMarshaller + * @see GridCacheMessageDeployer + */ +public interface IgniteMessageFactory extends MessageFactory { + /** {@inheritDoc} */ + @Override default void register(short directType, Supplier supplier, MessageSerializer serializer) + throws IgniteException { + register(directType, supplier, serializer, null, null); + } + + /** + * Registers a message with the given direct type, serializer, and marshaller. All messages must be registered + * during construction of the class that implements this interface. + * + * @param directType Direct type ({@link Message#directType()}) to register the message under. + * @param supplier Message supplier. + * @param serializer Message serializer. + * @param marshaller Message marshaller, or {@code null} for non-marshallable messages. + * @throws IgniteException If a message is already registered under the given direct type. + */ + default void register(short directType, Supplier supplier, MessageSerializer serializer, + @Nullable MessageMarshaller marshaller) throws IgniteException { + register(directType, supplier, serializer, marshaller, null); + } + + /** + * Registers a message with the given direct type, serializer, marshaller, and deployer. All messages must be + * registered during construction of the class that implements this interface. + * + * @param directType Direct type ({@link Message#directType()}) to register the message under. + * @param supplier Message supplier. + * @param serializer Message serializer. + * @param marshaller Message marshaller, or {@code null} for non-marshallable messages. + * @param deployer Message deployer, or {@code null} for messages without deployable fields. + * @throws IgniteException If a message is already registered under the given direct type. + */ + public void register(short directType, Supplier supplier, MessageSerializer serializer, + @Nullable MessageMarshaller marshaller, @Nullable GridCacheMessageDeployer deployer) throws IgniteException; + + /** + * Returns {@code MessageMarshaller} for provided type, or {@code null} if none is registered + * (e.g. for {@code NonMarshallableMessage} types). + * + * @param type Message type. + * @return Message marshaller, or {@code null}. + */ + public @Nullable MessageMarshaller marshaller(short type); + + /** + * Returns {@code GridCacheMessageDeployer} for provided type, or {@code null} if none is registered + * (e.g. for messages without deployable fields). + * + * @param type Message type. + * @return Message deployer, or {@code null}. + */ + public @Nullable GridCacheMessageDeployer deployer(short type); +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/IgniteMessageFactoryImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/IgniteMessageFactoryImpl.java index 6c1d45ef16438..d0e90a7b561ce 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/IgniteMessageFactoryImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/IgniteMessageFactoryImpl.java @@ -20,16 +20,22 @@ import java.lang.reflect.Array; import java.util.function.Supplier; import org.apache.ignite.IgniteException; +import org.apache.ignite.internal.MarshallableMessage; +import org.apache.ignite.internal.processors.cache.DeployableMessage; +import org.apache.ignite.internal.processors.cache.GridCacheMessage; +import org.apache.ignite.internal.processors.cache.GridCacheMessageDeployer; import org.apache.ignite.plugin.extensions.communication.Message; -import org.apache.ignite.plugin.extensions.communication.MessageFactory; import org.apache.ignite.plugin.extensions.communication.MessageFactoryProvider; +import org.apache.ignite.plugin.extensions.communication.MessageMarshaller; import org.apache.ignite.plugin.extensions.communication.MessageSerializer; +import org.apache.ignite.plugin.extensions.communication.NonMarshallableMessage; import org.jetbrains.annotations.Nullable; /** - * Message factory implementation which is responsible for instantiation of all communication messages. + * Message factory implementation responsible for instantiation of all messages sent between nodes, both over the + * communication SPI and via discovery. */ -public class IgniteMessageFactoryImpl implements MessageFactory { +public class IgniteMessageFactoryImpl implements IgniteMessageFactory { /** Offset. */ private static final int OFF = -Short.MIN_VALUE; @@ -37,13 +43,20 @@ public class IgniteMessageFactoryImpl implements MessageFactory { private static final int ARR_SIZE = 1 << Short.SIZE; /** Message suppliers. */ - private final Supplier[] msgSuppliers = (Supplier[])Array.newInstance(Supplier.class, ARR_SIZE); + private final Supplier[] msgSuppliers = (Supplier[])Array.newInstance(Supplier.class, ARR_SIZE); /** Message serializers. */ - private final MessageSerializer[] msgSerializers = (MessageSerializer[])Array.newInstance(MessageSerializer.class, ARR_SIZE); + private final MessageSerializer[] msgSerializers = (MessageSerializer[])Array.newInstance(MessageSerializer.class, ARR_SIZE); + + /** Message marshallers (null entry = no marshaller registered for that type). */ + private final MessageMarshaller[] msgMarshallers = (MessageMarshaller[])Array.newInstance(MessageMarshaller.class, ARR_SIZE); + + /** Message deployers (null entry = no deployer registered for that type). */ + private final GridCacheMessageDeployer[] msgDeployers = + (GridCacheMessageDeployer[])Array.newInstance(GridCacheMessageDeployer.class, ARR_SIZE); /** Initialized flag. If {@code true} then new message type couldn't be registered. */ - private boolean initialized; + private final boolean initialized; /** Min index of registered message supplier. */ private int minIdx = Integer.MAX_VALUE; @@ -54,11 +67,7 @@ public class IgniteMessageFactoryImpl implements MessageFactory { /** Count of registered message suppliers. */ private int cnt; - /** - * Contructor. - * - * @param factories Concrete message factories or message factory providers. Cfn't be empty or {@code null}. - */ + /** @param factories Message factory providers. Can't be empty or {@code null}. */ public IgniteMessageFactoryImpl(MessageFactoryProvider[] factories) { if (factories == null || factories.length == 0) throw new IllegalArgumentException("Message factory couldn't be initialized. Factories aren't provided."); @@ -69,15 +78,38 @@ public IgniteMessageFactoryImpl(MessageFactoryProvider[] factories) { initialized = true; } - /** {@inheritDoc} */ - @Override public void register(short directType, Supplier supplier, MessageSerializer serializer) throws IgniteException { + /** + * Registers a message with a serializer, an optional marshaller, and an optional deployer. + * + * @param directType Direct type ({@link Message#directType()}) to register the message under. + * @param supplier Message supplier. + * @param serializer Message serializer. + * @param marshaller Message marshaller, or {@code null} for {@link NonMarshallableMessage} types. + * @param deployer Message deployer, or {@code null} for messages without deployable fields. + */ + @Override public void register(short directType, Supplier supplier, MessageSerializer serializer, + @Nullable MessageMarshaller marshaller, @Nullable GridCacheMessageDeployer deployer) throws IgniteException { if (initialized) { throw new IllegalStateException("Message factory is already initialized. " + "Registration of new message types is forbidden."); } try { - supplier.get().registerAsDirectType(directType); + Message msg = supplier.get(); + + if (marshaller == null && msg instanceof MarshallableMessage) { + throw new IgniteException("Failed to register a message: it implements MarshallableMessage but no" + + " marshaller is provided [directType=" + directType + + ", cls=" + msg.getClass().getName() + ']'); + } + + if (deployer == null && msg instanceof DeployableMessage) { + throw new IgniteException("Failed to register a message: it implements DeployableMessage but no" + + " deployer is provided [directType=" + directType + + ", cls=" + msg.getClass().getName() + ']'); + } + + msg.registerAsDirectType(directType); } catch (NoClassDefFoundError | ExceptionInInitializerError e) { // Optional dependency not available (e.g. JTS for GridH2Geometry). @@ -86,11 +118,13 @@ public IgniteMessageFactoryImpl(MessageFactoryProvider[] factories) { int idx = directTypeToIndex(directType); - Supplier curr = msgSuppliers[idx]; + Supplier curr = msgSuppliers[idx]; if (curr == null) { msgSuppliers[idx] = supplier; msgSerializers[idx] = serializer; + msgMarshallers[idx] = marshaller; + msgDeployers[idx] = deployer; minIdx = Math.min(idx, minIdx); @@ -103,14 +137,14 @@ public IgniteMessageFactoryImpl(MessageFactoryProvider[] factories) { } /** - * Creates new message instance of provided direct type. + * Creates a new message instance of the provided direct type. * * @param directType Message direct type. * @return Message instance. - * @throws IgniteException If there are no any message factory for given {@code directType}. + * @throws UnknownMessageException If no message is registered under the given {@code directType}. */ - @Override public @Nullable Message create(short directType) { - Supplier supplier = msgSuppliers[directTypeToIndex(directType)]; + @Override public M create(short directType) { + Supplier supplier = msgSuppliers[directTypeToIndex(directType)]; if (supplier == null) throw new UnknownMessageException(directType); @@ -118,13 +152,9 @@ public IgniteMessageFactoryImpl(MessageFactoryProvider[] factories) { return supplier.get(); } - /** - * @param directType Message direct type. - * @return Message instance. - * @throws IgniteException If there are no any message factory for given {@code directType}. - */ - @Override public MessageSerializer serializer(short directType) { - MessageSerializer serializer = msgSerializers[directTypeToIndex(directType)]; + /** {@inheritDoc} */ + @Override public MessageSerializer serializer(short directType) { + MessageSerializer serializer = msgSerializers[directTypeToIndex(directType)]; if (serializer == null) throw new IgniteException("Message serializer not found for a message type: " + directType); @@ -132,6 +162,16 @@ public IgniteMessageFactoryImpl(MessageFactoryProvider[] factories) { return serializer; } + /** {@inheritDoc} */ + @Override public @Nullable MessageMarshaller marshaller(short directType) { + return msgMarshallers[directTypeToIndex(directType)]; + } + + /** {@inheritDoc} */ + @Override public @Nullable GridCacheMessageDeployer deployer(short directType) { + return msgDeployers[directTypeToIndex(directType)]; + } + /** * Returns direct types of all registered messages. * diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/MessageMarshalling.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/MessageMarshalling.java new file mode 100644 index 0000000000000..0e1ac93d34545 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/MessageMarshalling.java @@ -0,0 +1,140 @@ +/* + * 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.managers.communication; + +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.processors.cache.CacheObjectContext; +import org.apache.ignite.plugin.extensions.communication.Message; +import org.apache.ignite.plugin.extensions.communication.MessageMarshaller; +import org.jetbrains.annotations.Nullable; + +/** + * Resolve-and-dispatch entry points for {@link MessageMarshaller}: each looks up the marshaller registered for the + * message's direct type in {@code kctx.messageFactory()} and delegates to it, or skips when none is registered. + */ +public final class MessageMarshalling { + /** */ + private MessageMarshalling() { + // No-op. + } + + /** + * Marshals {@code msg} through its registered marshaller; a no-op when none is registered. + * + * @param msg Message to marshal. + * @param kctx Kernal context. + * @param cacheObjCtx Cache object context of the enclosing message, or {@code null} at the top level. + */ + public static void marshal(M msg, GridKernalContext kctx, @Nullable CacheObjectContext cacheObjCtx) + throws IgniteCheckedException { + marshal(factory(kctx), msg, kctx, cacheObjCtx); + } + + /** + * Marshals {@code msg} through its registered marshaller; a no-op when none is registered. Callers marshalling + * many messages resolve {@code msgFactory} once and use this overload. + * + * @param msgFactory Message factory to resolve the marshaller from. + * @param msg Message to marshal. + * @param kctx Kernal context. + * @param cacheObjCtx Cache object context of the enclosing message, or {@code null} at the top level. + */ + public static void marshal(IgniteMessageFactory msgFactory, M msg, GridKernalContext kctx, + @Nullable CacheObjectContext cacheObjCtx) throws IgniteCheckedException { + MessageMarshaller m = resolve(msgFactory, msg); + + if (m != null) + m.marshal(msg, kctx, cacheObjCtx); + } + + /** + * Unmarshals {@code msg} through its registered marshaller with full cache context; a no-op when none is registered. + * + * @param msg Message to unmarshal. + * @param kctx Kernal context. + * @param cacheObjCtx Cache object context of the enclosing message, or {@code null} at the top level. + * @param clsLdr Class loader for unmarshalling. + */ + public static void unmarshal(M msg, GridKernalContext kctx, @Nullable CacheObjectContext cacheObjCtx, + ClassLoader clsLdr) throws IgniteCheckedException { + unmarshal(factory(kctx), msg, kctx, cacheObjCtx, clsLdr); + } + + /** + * Unmarshals {@code msg} through its registered marshaller with full cache context; a no-op when none is + * registered. Callers unmarshalling many messages resolve {@code msgFactory} once and use this overload. + * + * @param msgFactory Message factory to resolve the marshaller from. + * @param msg Message to unmarshal. + * @param kctx Kernal context. + * @param cacheObjCtx Cache object context of the enclosing message, or {@code null} at the top level. + * @param clsLdr Class loader for unmarshalling. + */ + public static void unmarshal(IgniteMessageFactory msgFactory, M msg, GridKernalContext kctx, + @Nullable CacheObjectContext cacheObjCtx, ClassLoader clsLdr) throws IgniteCheckedException { + assert !MessageUnmarshalOnceCheck.ENABLED || MessageUnmarshalOnceCheck.firstUnmarshal(msg, true) + : "Finish-unmarshalled more than once: " + msg.getClass().getName(); + + MessageMarshaller m = resolve(msgFactory, msg); + + if (m != null) + m.unmarshal(msg, kctx, cacheObjCtx, clsLdr); + } + + /** + * Cache-free {@code unmarshal} through the registered marshaller; a no-op when none is registered. + * + * @param msg Message to unmarshal. + * @param kctx Kernal context. + */ + public static void unmarshal(M msg, GridKernalContext kctx) throws IgniteCheckedException { + assert !MessageUnmarshalOnceCheck.ENABLED || MessageUnmarshalOnceCheck.firstUnmarshal(msg, false) + : "Finish-unmarshalled more than once: " + msg.getClass().getName(); + + MessageMarshaller m = resolve(factory(kctx), msg); + + if (m != null) + m.unmarshal(msg, kctx); + } + + /** + * Unmarshals only {@code @NioField} fields on the NIO thread through the registered marshaller; a no-op when none + * is registered. + * + * @param msg Message to unmarshal. + * @param kctx Kernal context. + */ + public static void unmarshalNio(M msg, GridKernalContext kctx) throws IgniteCheckedException { + MessageMarshaller m = resolve(factory(kctx), msg); + + if (m != null) + m.unmarshalNio(msg, kctx); + } + + /** @return the message factory of {@code kctx}. */ + private static IgniteMessageFactory factory(GridKernalContext kctx) { + return (IgniteMessageFactory)kctx.messageFactory(); + } + + /** @return the marshaller registered for {@code msg}'s direct type, or {@code null} if none. */ + @SuppressWarnings("unchecked") + private static @Nullable MessageMarshaller resolve(IgniteMessageFactory msgFactory, M msg) { + return (MessageMarshaller)msgFactory.marshaller(msg.directType()); + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/MessageUnmarshalOnceCheck.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/MessageUnmarshalOnceCheck.java new file mode 100644 index 0000000000000..aa2e48289a7c8 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/communication/MessageUnmarshalOnceCheck.java @@ -0,0 +1,108 @@ +/* + * 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.managers.communication; + +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.WeakReference; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import org.apache.ignite.IgniteSystemProperties; +import org.apache.ignite.internal.MarshallableMessage; +import org.apache.ignite.plugin.extensions.communication.Message; + +/** + * Detects a {@link MarshallableMessage} instance being finish-unmarshalled twice within the same pass — a class-loader + * or receive-path bug. The cache-free and cache-aware passes over one message are both legitimate and tracked apart. + * Gated by {@link #ENABLED}, so it runs only under tests and is folded away in production. + */ +public class MessageUnmarshalOnceCheck { + /** + * When {@code true}, the no-double-unmarshal check runs. {@code static final} so the JIT folds the guard away + * in production (even with assertions on); enabled only by tests via {@code IGNITE_MESSAGE_UNMARSHAL_ONCE_CHECK}. + */ + public static final boolean ENABLED = IgniteSystemProperties.getBoolean(IgniteSystemProperties.IGNITE_MESSAGE_UNMARSHAL_ONCE_CHECK); + + /** Cleared referents, drained on each call to evict their stale {@link IdRef}s from {@link #seen}. */ + private static final ReferenceQueue refQueue = new ReferenceQueue<>(); + + /** Finish-unmarshalled instances, held weakly and keyed by identity so they vanish with the message. */ + private static final Set seen = ConcurrentHashMap.newKeySet(); + + /** */ + private MessageUnmarshalOnceCheck() { + // No-op. + } + + /** + * @param msg Message about to be finish-unmarshalled. + * @param cacheMode {@code true} for the cache-aware pass, {@code false} for the cache-free pass; the two passes + * over one message are legitimate and tracked separately, so only a repeat of the same pass is reported. + * @return {@code true} if {@code msg} is not a {@link MarshallableMessage} or is finish-unmarshalled the first + * time in this pass. + */ + public static boolean firstUnmarshal(Message msg, boolean cacheMode) { + if (!(msg instanceof MarshallableMessage)) + return true; + + // Static set: evict entries whose message was already collected, so it doesn't grow across the suite. + for (Reference r; (r = refQueue.poll()) != null; ) + seen.remove(r); + + return seen.add(new IdRef(msg, cacheMode)); + } + + /** Weak reference to a message keyed by identity and pass, so distinct messages and the two passes stay distinct. */ + private static final class IdRef extends WeakReference { + /** Referent {@code identityHashCode} folded with {@code cacheMode}, captured up front as the referent may be cleared later. */ + private final int hash; + + /** Unmarshal pass: {@code true} = cache-aware, {@code false} = cache-free. */ + private final boolean cacheMode; + + /** + * @param msg Tracked message. + * @param cacheMode Unmarshal pass. + */ + private IdRef(Message msg, boolean cacheMode) { + super(msg, refQueue); + + this.cacheMode = cacheMode; + hash = 31 * System.identityHashCode(msg) + (cacheMode ? 1 : 0); + } + + /** {@inheritDoc} */ + @Override public int hashCode() { + return hash; + } + + /** {@inheritDoc} */ + @Override public boolean equals(Object o) { + if (this == o) + return true; + + if (!(o instanceof IdRef ref)) + return false; + + // Read the referent once: a concurrent GC could otherwise clear it between the null check and the compare. + Message m = get(); + + return m != null && m == ref.get() && cacheMode == ref.cacheMode; + } + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/eventstorage/GridEventStorageMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/eventstorage/GridEventStorageMessage.java index 688145e87b971..ec7c9f079c995 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/managers/eventstorage/GridEventStorageMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/eventstorage/GridEventStorageMessage.java @@ -26,6 +26,7 @@ import org.apache.ignite.events.Event; import org.apache.ignite.internal.GridTopicMessage; import org.apache.ignite.internal.MarshallableMessage; +import org.apache.ignite.internal.Marshalled; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.managers.communication.ErrorMessage; import org.apache.ignite.internal.util.tostring.GridToStringInclude; @@ -52,7 +53,8 @@ public class GridEventStorageMessage implements MarshallableMessage { byte[] filterBytes; /** */ - private Collection evts; + @Marshalled("evtsBytes") + Collection evts; /** */ @Order(2) @@ -197,27 +199,21 @@ String userVersion() { } /** {@inheritDoc} */ - @Override public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { + @Override public void marshal(Marshaller marsh) throws IgniteCheckedException { if (filter != null) filterBytes = U.marshal(marsh, filter); - - if (evts != null) - evtsBytes = U.marshal(marsh, evts); } /** {@inheritDoc} */ - @Override public void finishUnmarshal(Marshaller marsh, ClassLoader ldr) throws IgniteCheckedException { - if (evtsBytes != null) { - evts = U.unmarshal(marsh, evtsBytes, ldr); - - evtsBytes = null; - } + @Override public void unmarshal(Marshaller marsh, ClassLoader ldr) throws IgniteCheckedException { + // No-op. } /** * @param marsh Marshaller. * @param filterClsLdr Class loader for filter. */ + // TODO IGNITE-28901: revise the filters marshalling. public void finishUnmarshalFilters(Marshaller marsh, ClassLoader filterClsLdr) throws IgniteCheckedException { if (filterBytes != null && filter == null) { filter = U.unmarshal(marsh, filterBytes, filterClsLdr); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/plugin/AbstractMarshallableMessageFactoryProvider.java b/modules/core/src/main/java/org/apache/ignite/internal/plugin/AbstractMarshallableMessageFactoryProvider.java index 5ac1f2472997f..9db37d8d6ce15 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/plugin/AbstractMarshallableMessageFactoryProvider.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/plugin/AbstractMarshallableMessageFactoryProvider.java @@ -18,78 +18,175 @@ package org.apache.ignite.internal.plugin; import java.lang.reflect.Constructor; +import java.util.function.Supplier; import org.apache.ignite.IgniteException; -import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.internal.MarshallableMessage; import org.apache.ignite.internal.binary.BinaryMarshaller; -import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.internal.managers.communication.IgniteMessageFactory; +import org.apache.ignite.internal.processors.cache.GridCacheMessage; +import org.apache.ignite.internal.processors.cache.GridCacheMessageDeployer; import org.apache.ignite.marshaller.Marshaller; import org.apache.ignite.marshaller.jdk.JdkMarshaller; import org.apache.ignite.plugin.extensions.communication.Message; -import org.apache.ignite.plugin.extensions.communication.MessageFactory; import org.apache.ignite.plugin.extensions.communication.MessageFactoryProvider; +import org.apache.ignite.plugin.extensions.communication.MessageMarshaller; import org.apache.ignite.plugin.extensions.communication.MessageSerializer; +import org.apache.ignite.plugin.extensions.communication.NonMarshallableMessage; +import org.jetbrains.annotations.Nullable; /** * An extension of {@link MessageFactoryProvider} allowing to use provided schema-aware marshaller - * and resolved class loader to register {@link MarshallableMessage}. + * to register {@link MarshallableMessage}. */ public abstract class AbstractMarshallableMessageFactoryProvider implements MessageFactoryProvider { + /** Generated-companion constructors per message class, including cached negative lookups. */ + private static final ClassValue COMPANIONS = new ClassValue<>() { + @Override protected Companions computeValue(Class cls) { + return new Companions(companionCtor(cls, "Serializer"), companionCtor(cls, "Marshaller"), companionCtor(cls, "Deployer")); + } + }; + /** Default schema-less marshaller. */ protected Marshaller dfltMarsh; - /** Default class loader. */ - protected final ClassLoader dftlClsLdr = U.gridClassLoader(); - /** Schema-aware marshaller like {@link BinaryMarshaller}. */ protected Marshaller schemaAwareMarsh; - /** Resolved (configured) class loader like {@link IgniteConfiguration#setClassLoader(ClassLoader)}. */ - protected ClassLoader resolvedClsLdr; - /** * @param dfltMarsh Default schema-less marshaller like {@link JdkMarshaller}. * @param schemaAwareMarsh Schema-aware marshaller like {@link BinaryMarshaller}. - * @param resolvedClsLdr Resolved (configured) class loader like {@link IgniteConfiguration#setClassLoader(ClassLoader)}. */ - public void init(Marshaller dfltMarsh, Marshaller schemaAwareMarsh, ClassLoader resolvedClsLdr) { + public void init(Marshaller dfltMarsh, Marshaller schemaAwareMarsh) { this.dfltMarsh = dfltMarsh; this.schemaAwareMarsh = schemaAwareMarsh; - this.resolvedClsLdr = resolvedClsLdr; } - /** Registers message automatically generating message supplier and serializer. */ - protected static void register(MessageFactory factory, Class cls, short id, Marshaller marsh, - ClassLoader clsLrd) { + /** Registers a message with its generated serializer, marshaller (if marshallable), and deployer (if any). */ + protected static void register(IgniteMessageFactory factory, Class cls, short id, Marshaller marsh) { Constructor ctor; - MessageSerializer serializer; try { ctor = cls.getConstructor(); + } + catch (NoSuchMethodException e) { + throw new IgniteException("Failed to register message of type " + cls.getSimpleName(), e); + } + + register(factory, cls, id, () -> { + try { + return ctor.newInstance(); + } + catch (Exception e) { + throw new IgniteException("Failed to create message of type " + cls.getSimpleName(), e); + } + }, marsh); + } + + /** + * Registers a message with a caller-provided {@code supplier} and its generated serializer, marshaller (if + * marshallable), and deployer (if any). Use this overload when {@code cls} is package-private and so cannot be + * instantiated by reflection from this package — pass an in-package {@code ::new} reference as {@code supplier}. + */ + protected static void register(IgniteMessageFactory factory, Class cls, short id, + Supplier supplier, Marshaller marsh) { + MessageSerializer serializer = requireGenerated(cls, "Serializer", marsh); + + // A MarshallableMessage always gets a generated marshaller (the hook call alone is a statement), so its + // absence is a build problem. For the rest the generator skips statement-free marshallers, so absence + // legitimately means "nothing to marshal"; the message and its companions ship in the same jar, hence + // a missing class cannot be a packaging accident that spares the (required) serializer. + MessageMarshaller marshaller = NonMarshallableMessage.class.isAssignableFrom(cls) + ? null + : MarshallableMessage.class.isAssignableFrom(cls) + ? requireGenerated(cls, "Marshaller", marsh) + : loadGenerated(cls, "Marshaller", marsh); + + // Deployers are generated for GridCacheMessage subclasses only, so the class lookup is skipped for the rest; + // a DeployableMessage left without a deployer is then rejected at registration. + GridCacheMessageDeployer deployer = GridCacheMessage.class.isAssignableFrom(cls) + ? loadGenerated(cls, "Deployer", marsh) + : null; + + factory.register(id, supplier, serializer, marshaller, deployer); + } + + /** Loads the generated companion like {@link #loadGenerated}, failing fast when it is missing. */ + private static T requireGenerated(Class cls, String suffix, Marshaller marsh) { + T res = loadGenerated(cls, suffix, marsh); + + if (res == null) { + throw new IgniteException("No " + cls.getSimpleName() + suffix + " found for " + cls.getName() + + ". Either the class is not processed by codegen or the generated sources are stale," + + " try 'mvn clean install'."); + } + + return res; + } - boolean marshallable = MarshallableMessage.class.isAssignableFrom(cls); + /** + * Instantiates the generated companion class {@code Serializer/Marshaller/Deployer}, or returns + * {@code null} when it does not exist. The sole declared constructor is used, passing {@code marsh} when it takes + * one. Constructor lookups, including missing companions, are cached per message class in {@link #COMPANIONS}. + */ + @SuppressWarnings("unchecked") + private static @Nullable T loadGenerated(Class cls, String suffix, Marshaller marsh) { + Constructor ctor = COMPANIONS.get(cls).ctor(suffix); - Class serCls = Class.forName(cls.getName() + (marshallable ? "MarshallableSerializer" : "Serializer")); + if (ctor == null) + return null; - serializer = marshallable - ? (MessageSerializer)serCls.getConstructor(Marshaller.class, ClassLoader.class).newInstance(marsh, clsLrd) - : (MessageSerializer)serCls.getConstructor().newInstance(); + try { + return (T)(ctor.getParameterCount() == 0 ? ctor.newInstance() : ctor.newInstance(marsh)); } catch (Exception e) { - throw new IgniteException("Failed to register message of type " + cls.getSimpleName(), e); + throw new IgniteException("Failed to instantiate " + cls.getSimpleName() + suffix, e); + } + } + + /** @return the sole public constructor of the generated companion {@code }, or {@code null} when it does not exist. */ + private static @Nullable Constructor companionCtor(Class cls, String suffix) { + try { + // The companion lives next to the message class, so it must be looked up in the same class loader. + return Class.forName(cls.getName() + suffix, true, cls.getClassLoader()).getConstructors()[0]; + } + catch (ClassNotFoundException ignored) { + return null; } + } + + /** Generated-companion constructors of one message class; a {@code null} entry means the companion is not generated. */ + private static final class Companions { + /** */ + private final @Nullable Constructor serializer; + + /** */ + private final @Nullable Constructor marshaller; + + /** */ + private final @Nullable Constructor deployer; + + /** */ + Companions(@Nullable Constructor serializer, @Nullable Constructor marshaller, @Nullable Constructor deployer) { + this.serializer = serializer; + this.marshaller = marshaller; + this.deployer = deployer; + } + + /** @return the constructor of the {@code suffix} companion, or {@code null} when it is not generated. */ + @Nullable Constructor ctor(String suffix) { + switch (suffix) { + case "Serializer": + return serializer; + + case "Marshaller": + return marshaller; - factory.register( - id, - () -> { - try { - return ctor.newInstance(); - } - catch (Exception e) { - throw new IgniteException("Failed to create message of type " + cls.getSimpleName(), e); - } - }, - serializer - ); + case "Deployer": + return deployer; + + default: + throw new IllegalArgumentException("Unknown companion suffix: " + suffix); + } + } } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheEntryPredicate.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheEntryPredicate.java index 36312a1591135..d8c8e7083ee62 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheEntryPredicate.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheEntryPredicate.java @@ -17,7 +17,6 @@ package org.apache.ignite.internal.processors.cache; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.lang.IgnitePredicate; import org.apache.ignite.plugin.extensions.communication.Message; @@ -25,19 +24,6 @@ * */ public interface CacheEntryPredicate extends IgnitePredicate, Message { - /** - * @param ctx Context. - * @throws IgniteCheckedException If failed. - */ - public void prepareMarshal(GridCacheContext ctx) throws IgniteCheckedException; - - /** - * @param ctx Context. - * @param ldr Class loader. - * @throws IgniteCheckedException If failed. - */ - public void finishUnmarshal(GridCacheContext ctx, ClassLoader ldr) throws IgniteCheckedException; - /** * @param locked Entry locked */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheEntryPredicateAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheEntryPredicateAdapter.java index 0c30dc615aa66..d41a3da341e63 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheEntryPredicateAdapter.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheEntryPredicateAdapter.java @@ -18,7 +18,6 @@ package org.apache.ignite.internal.processors.cache; import java.util.Objects; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.binary.BinaryObject; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.util.tostring.GridToStringInclude; @@ -118,17 +117,4 @@ public CacheEntryPredicateType type() { throw new IllegalStateException("Unknown cache entry predicate type: " + type); } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheContext ctx, ClassLoader ldr) throws IgniteCheckedException { - if (type == CacheEntryPredicateType.VALUE) - val.finishUnmarshal(ctx.cacheObjectContext(), ldr); - } - - /** {@inheritDoc} */ - @Override public void prepareMarshal(GridCacheContext ctx) throws IgniteCheckedException { - if (type == CacheEntryPredicateType.VALUE) - val.prepareMarshal(ctx.cacheObjectContext()); - } - } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheInvokeDirectResult.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheInvokeDirectResult.java index 1276c6b63c82c..4490be4c1dfc9 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheInvokeDirectResult.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheInvokeDirectResult.java @@ -19,7 +19,6 @@ import javax.cache.processor.EntryProcessor; import javax.cache.processor.MutableEntry; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.managers.communication.ErrorMessage; import org.apache.ignite.internal.util.tostring.GridToStringInclude; @@ -111,19 +110,6 @@ public CacheObject result() { return ErrorMessage.error(errMsg); } - /** - * @param ctx Cache context. - * @throws IgniteCheckedException If failed. - */ - public void prepareMarshal(GridCacheContext ctx) throws IgniteCheckedException { - key.prepareMarshal(ctx.cacheObjectContext()); - - assert unprepareRes == null : "marshalResult() was not called for the result: " + this; - - if (res != null) - res.prepareMarshal(ctx.cacheObjectContext()); - } - /** * Converts the entry processor unprepared result to a cache object instance. * @@ -139,19 +125,6 @@ public void marshalResult(GridCacheContext ctx) { } } - /** - * @param ctx Cache context. - * @param ldr Class loader. - * @throws IgniteCheckedException If failed. - */ - public void finishUnmarshal(GridCacheContext ctx, ClassLoader ldr) throws IgniteCheckedException { - key.finishUnmarshal(ctx.cacheObjectContext(), ldr); - - if (res != null) - res.finishUnmarshal(ctx.cacheObjectContext(), ldr); - } - - /** {@inheritDoc} */ @Override public String toString() { return S.toString(CacheInvokeDirectResult.class, this); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectByteArrayImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectByteArrayImpl.java index 2119c99b9c1bb..608d6fdc8868b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectByteArrayImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectByteArrayImpl.java @@ -56,7 +56,7 @@ public CacheObjectByteArrayImpl(byte[] val) { } /** {@inheritDoc} */ - @Override public void finishUnmarshal(CacheObjectValueContext ctx, ClassLoader ldr) throws IgniteCheckedException { + @Override public void unmarshal(CacheObjectValueContext ctx, ClassLoader ldr) throws IgniteCheckedException { // No-op. } @@ -118,7 +118,7 @@ public CacheObjectByteArrayImpl(byte[] val) { } /** {@inheritDoc} */ - @Override public void prepareMarshal(CacheObjectValueContext ctx) throws IgniteCheckedException { + @Override public void marshal(CacheObjectValueContext ctx) throws IgniteCheckedException { // No-op. } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectImpl.java index fabf36ac20a08..cc4be8e76e5cf 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectImpl.java @@ -105,7 +105,7 @@ else if (ctx.isPeerClassLoadingEnabled()) } /** {@inheritDoc} */ - @Override public void prepareMarshal(CacheObjectValueContext ctx) throws IgniteCheckedException { + @Override public void marshal(CacheObjectValueContext ctx) throws IgniteCheckedException { assert val != null || valBytes != null; if (valBytes == null) @@ -113,7 +113,7 @@ else if (ctx.isPeerClassLoadingEnabled()) } /** {@inheritDoc} */ - @Override public void finishUnmarshal(CacheObjectValueContext ctx, ClassLoader ldr) throws IgniteCheckedException { + @Override public void unmarshal(CacheObjectValueContext ctx, ClassLoader ldr) throws IgniteCheckedException { assert val != null || valBytes != null; if (val == null && ctx.storeValue()) diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectNotResolvedException.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectNotResolvedException.java new file mode 100644 index 0000000000000..38985bcdfce56 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/CacheObjectNotResolvedException.java @@ -0,0 +1,32 @@ +/* + * 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.processors.cache; + +/** + * Thrown by {@link KeyCacheObjectImpl#hashCode()} when the object has not been deserialized yet, + * typically because the owning cache has been removed before {@code unmarshal} could complete. + */ +public class CacheObjectNotResolvedException extends RuntimeException { + /** */ + private static final long serialVersionUID = 0L; + + /** */ + public CacheObjectNotResolvedException() { + super("Cache object is not deserialized (likely the owning cache was concurrently removed).", null, true, false); + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DeployableMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DeployableMessage.java new file mode 100644 index 0000000000000..a9848ab3e104e --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DeployableMessage.java @@ -0,0 +1,35 @@ +/* + * 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.processors.cache; + +import org.apache.ignite.IgniteCheckedException; + +/** + * A {@link GridCacheMessage} with custom deployment logic that cannot be inferred from field types (conditional + * deployment, non-standard accessors, etc.). The generated {@code *Deployer} calls {@link #deploy} after + * its inferred field deployment, mirroring how a generated marshaller calls {@code MarshallableMessage#marshal}. + */ +public interface DeployableMessage { + /** + * Prepares deployment info for fields whose handling cannot be inferred from their type. + * + * @param ctx Cache shared context. + * @throws IgniteCheckedException If failed. + */ + void deploy(GridCacheSharedContext ctx) throws IgniteCheckedException; +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeRequest.java index 79c2f7d90bf42..43e375c45d7d0 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/DynamicCacheChangeRequest.java @@ -19,25 +19,23 @@ import java.io.Serializable; import java.util.UUID; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.configuration.NearCacheConfiguration; import org.apache.ignite.internal.CoreMessagesProvider; import org.apache.ignite.internal.GridKernalContext; -import org.apache.ignite.internal.MarshallableMessage; +import org.apache.ignite.internal.Marshalled; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.query.QuerySchema; import org.apache.ignite.internal.util.tostring.GridToStringExclude; import org.apache.ignite.internal.util.typedef.T2; -import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteUuid; -import org.apache.ignite.marshaller.Marshaller; +import org.apache.ignite.plugin.extensions.communication.Message; import org.jetbrains.annotations.Nullable; /** * Cache start/stop request. */ -public class DynamicCacheChangeRequest implements MarshallableMessage, Serializable { +public class DynamicCacheChangeRequest implements Message, Serializable { /** */ private static final long serialVersionUID = 0L; @@ -56,7 +54,8 @@ public class DynamicCacheChangeRequest implements MarshallableMessage, Serializa /** Cache start configuration. */ @GridToStringExclude - private CacheConfiguration startCfg; + @Marshalled("cfgBytes") + CacheConfiguration startCfg; /** Bytes of {@link #startCfg}. */ @Order(3) @@ -72,7 +71,8 @@ public class DynamicCacheChangeRequest implements MarshallableMessage, Serializa /** Near cache configuration. */ @GridToStringExclude - private NearCacheConfiguration nearCacheCfg; + @Marshalled("nearCfgBytes") + NearCacheConfiguration nearCacheCfg; /** Bytes of {@link #nearCacheCfg}. */ @Order(6) @@ -123,6 +123,7 @@ public class DynamicCacheChangeRequest implements MarshallableMessage, Serializa boolean resetLostPartitions; /** Dynamic schema. */ + @Marshalled("schemaBytes") QuerySchema schema; /** Bytes of {@link #schema}. */ @@ -166,32 +167,6 @@ public DynamicCacheChangeRequest(UUID reqId, String cacheName, UUID initiatingNo this.initiatingNodeId = initiatingNodeId; } - /** {@inheritDoc} */ - @Override public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { - cfgBytes = U.marshal(marsh, startCfg); - - if (nearCacheCfg != null) - nearCfgBytes = U.marshal(marsh, nearCacheCfg); - - if (schema != null) - schemaBytes = U.marshal(marsh, schema); - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { - startCfg = U.unmarshal(marsh, cfgBytes, clsLdr); - - if (nearCfgBytes != null) - nearCacheCfg = U.unmarshal(marsh, nearCfgBytes, clsLdr); - - if (schemaBytes != null) - schema = U.unmarshal(marsh, schemaBytes, clsLdr); - - cfgBytes = null; - nearCfgBytes = null; - schemaBytes = null; - } - /** * @param ctx Context. * @param cacheName Cache name. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java index 2fe29746e7a7e..f6d51ada3ff7e 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheAdapter.java @@ -212,19 +212,6 @@ public abstract class GridCacheAdapter implements IgniteInternalCache, Object>() { - @Nullable @Override public Object applyx(IgniteInternalFuture fut) - throws IgniteCheckedException { - return fut.get().value(); - } - - @Override public String toString() { - return "Cache return value to value converter."; - } - }; - /** {@link GridCacheReturn}-to-null conversion. */ protected static final IgniteClosure RET2NULL = new CX1, Object>() { @@ -252,6 +239,19 @@ public abstract class GridCacheAdapter implements IgniteInternalCache, Object>() { + @Nullable @Override public Object applyx(IgniteInternalFuture fut) + throws IgniteCheckedException { + return fut.get().value(ctx); + } + + @Override public String toString() { + return "Cache return value to value converter."; + } + }; + /** Last asynchronous future. */ protected ThreadLocal lastFut = new ThreadLocal() { @Override protected FutureHolder initialValue() { @@ -1827,7 +1827,7 @@ protected V getAndPut0(final K key, final V val, @Nullable final CacheEntryPredi throws IgniteCheckedException { return syncOp(new SyncOp(true) { @Override public V op(GridNearTxLocal tx) throws IgniteCheckedException { - return (V)tx.putAsync(ctx, null, key, val, true, filter).get().value(); + return (V)tx.putAsync(ctx, null, key, val, true, filter).get().value(ctx); } @Override public String toString() { @@ -1880,7 +1880,7 @@ public IgniteInternalFuture getAndPutAsync0(final K key, @Nullable final CacheEntryPredicate filter) { return asyncOp(new AsyncOp() { @Override public IgniteInternalFuture op(GridNearTxLocal tx, AffinityTopologyVersion readyTopVer) { - return tx.putAsync(ctx, readyTopVer, key, val, true, filter).chain(RET2VAL); + return tx.putAsync(ctx, readyTopVer, key, val, true, filter).chain(ret2val); } @Override public String toString() { @@ -2067,7 +2067,7 @@ private EntryProcessorResult invoke0( (EntryProcessor)entryProcessor, args); - Map> resMap = fut.get().value(); + Map> resMap = fut.get().value(ctx); if (statsEnabled) metrics0().addInvokeTimeNanos(System.nanoTime() - start); @@ -2110,7 +2110,7 @@ private EntryProcessorResult invoke0( IgniteInternalFuture fut = tx.invokeAsync(ctx, null, keys, invokeVals, args); - Map> res = fut.get().value(); + Map> res = fut.get().value(ctx); if (statsEnabled) metrics0().addInvokeTimeNanos(System.nanoTime() - start); @@ -2161,7 +2161,7 @@ private EntryProcessorResult invoke0( if (performanceStatsEnabled) writeStatistics(OperationType.CACHE_INVOKE, start); - Map> resMap = ret.value(); + Map> resMap = ret.value(ctx); if (resMap != null) { assert resMap.isEmpty() || resMap.size() == 1 : resMap.size(); @@ -2220,7 +2220,7 @@ private EntryProcessorResult invoke0( assert ret != null; - return ret.value() != null ? ret.value() : Collections.emptyMap(); + return ret.value(ctx) != null ? ret.value(ctx) : Collections.emptyMap(); } }); } @@ -2271,8 +2271,8 @@ private EntryProcessorResult invoke0( assert ret != null; - return ret.value() != null - ? ret.>>value() + return ret.value(ctx) != null + ? ret.>>value(ctx) : Collections.>emptyMap(); } }); @@ -2303,7 +2303,7 @@ private EntryProcessorResult invoke0( args ); - Map> val = fut.get().value(); + Map> val = fut.get().value(ctx); if (statsEnabled) metrics0().addInvokeTimeNanos(System.nanoTime() - start); @@ -2549,7 +2549,7 @@ protected V getAndRemove0(final K key) throws IgniteCheckedException { null, /*singleRmv*/false); - V ret = fut.get().value(); + V ret = fut.get().value(ctx); if (ctx.config().getInterceptor() != null) { K key = keepBinary ? (K)ctx.unwrapBinaryIfNeeded(key0, true, false, null) : key0; @@ -2600,7 +2600,7 @@ protected IgniteInternalFuture getAndRemoveAsync0(final K key) { Collections.singletonList(key), /*retval*/true, null, - /*singleRmv*/false).chain(RET2VAL); + /*singleRmv*/false).chain(ret2val); } @Override public String toString() { diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheDeployable.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheDeployable.java index 057ce897bac52..ffd5953a2f7e1 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheDeployable.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheDeployable.java @@ -24,11 +24,11 @@ */ public interface GridCacheDeployable { /** - * Prepare deployment information. + * Applies the given deployment information. * * @param depInfo Deployment information. */ - public void prepare(GridDeploymentInfo depInfo); + public void deploy(GridDeploymentInfo depInfo); /** * @return Deployment bean. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheDeploymentManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheDeploymentManager.java index ce2ceaa577771..125fe4ce94743 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheDeploymentManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheDeploymentManager.java @@ -411,7 +411,7 @@ public void prepare(GridCacheDeployable deployable) throws IgnitePeerToPeerClass checkDeploymentIsCorrect(dep, deployable, true); if (dep != null) - deployable.prepare(dep); + deployable.deploy(dep); if (log.isDebugEnabled()) log.debug("Prepared grid cache deployable [dep=" + dep + ", deployable=" + deployable + ']'); @@ -449,7 +449,7 @@ private void checkDeploymentIsCorrect(GridDeploymentInfoBean deployment, GridCac assert depEnabled; // Do not return info if mode is CONTINUOUS. - // In this case deployment info will be set by GridCacheMessage.prepareObject(). + // In this case deployment info will be set by GridCacheMessage.deployObject(). if (cctx.gridConfig().getDeploymentMode() == CONTINUOUS) return null; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryInfo.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryInfo.java index d8d710f62368f..d5da34b18b589 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryInfo.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheEntryInfo.java @@ -18,17 +18,19 @@ package org.apache.ignite.internal.processors.cache; import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.MarshallableMessage; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.util.tostring.GridToStringInclude; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; -import org.apache.ignite.plugin.extensions.communication.Message; +import org.apache.ignite.marshaller.Marshaller; +import org.apache.ignite.plugin.extensions.communication.CacheIdAware; /** * Entry information that gets passed over wire. */ -public class GridCacheEntryInfo implements Message { +public class GridCacheEntryInfo implements MarshallableMessage, CacheIdAware { /** */ private static final int SIZE_OVERHEAD = 3 * 8 /* reference */ + 4 /* int */ + 2 * 8 /* long */ + 32 /* version */; @@ -63,10 +65,8 @@ public class GridCacheEntryInfo implements Message { /** Deleted flag. */ private boolean deleted; - /** - * @return Cache ID. - */ - public int cacheId() { + /** {@inheritDoc} */ + @Override public int cacheId() { return cacheId; } @@ -175,16 +175,6 @@ public void setDeleted(boolean deleted) { this.deleted = deleted; } - /** - * @param ctx Context. - * @param ldr Loader. - * @throws IgniteCheckedException If failed. - */ - public void unmarshalValue(GridCacheContext ctx, ClassLoader ldr) throws IgniteCheckedException { - if (val != null) - val.finishUnmarshal(ctx.cacheObjectContext(), ldr); - } - /** * @param ctx Cache object context. * @return Marshalled size. @@ -201,26 +191,8 @@ public int marshalledSize(CacheObjectContext ctx) throws IgniteCheckedException return SIZE_OVERHEAD + size; } - /** - * @param ctx Cache context. - * @throws IgniteCheckedException In case of error. - */ - public void marshal(GridCacheContext ctx) throws IgniteCheckedException { - marshal(ctx.cacheObjectContext()); - } - - /** - * @param ctx Cache context. - * @throws IgniteCheckedException In case of error. - */ - public void marshal(CacheObjectContext ctx) throws IgniteCheckedException { - assert key != null; - - key.prepareMarshal(ctx); - - if (val != null) - val.prepareMarshal(ctx); - + /** {@inheritDoc} */ + @Override public void marshal(Marshaller marsh) throws IgniteCheckedException { if (expireTime == 0) expireTime = -1; else { @@ -231,30 +203,8 @@ public void marshal(CacheObjectContext ctx) throws IgniteCheckedException { } } - /** - * Unmarshalls entry. - * - * @param ctx Cache context. - * @param clsLdr Class loader. - * @throws IgniteCheckedException If unmarshalling failed. - */ - public void unmarshal(GridCacheContext ctx, ClassLoader clsLdr) throws IgniteCheckedException { - unmarshal(ctx.cacheObjectContext(), clsLdr); - } - - /** - * Unmarshalls entry. - * - * @param ctx Cache context. - * @param clsLdr Class loader. - * @throws IgniteCheckedException If unmarshalling failed. - */ - public void unmarshal(CacheObjectContext ctx, ClassLoader clsLdr) throws IgniteCheckedException { - key.finishUnmarshal(ctx, clsLdr); - - if (val != null) - val.finishUnmarshal(ctx, clsLdr); - + /** {@inheritDoc} */ + @Override public void unmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { long remaining = expireTime; expireTime = remaining < 0 ? 0 : U.currentTimeMillis() + remaining; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheIdMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheIdMessage.java index f0ebb72b7b5b1..1236d67451ac1 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheIdMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheIdMessage.java @@ -20,20 +20,19 @@ import org.apache.ignite.internal.Order; import org.apache.ignite.internal.util.tostring.GridToStringInclude; import org.apache.ignite.internal.util.typedef.internal.S; +import org.apache.ignite.plugin.extensions.communication.CacheIdAware; /** * Message related to particular cache. */ -public abstract class GridCacheIdMessage extends GridCacheMessage { +public abstract class GridCacheIdMessage extends GridCacheMessage implements CacheIdAware { /** Cache ID. */ @GridToStringInclude @Order(0) public int cacheId; - /** - * @return Cache ID. - */ - public int cacheId() { + /** {@inheritDoc} */ + @Override public int cacheId() { return cacheId; } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheIoManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheIoManager.java index 4dfdb6b35997d..5f950c022dd14 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheIoManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheIoManager.java @@ -39,8 +39,10 @@ import org.apache.ignite.internal.IgniteClientDisconnectedCheckedException; import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException; +import org.apache.ignite.internal.managers.communication.GridIoManager.SendRetryPolicy; import org.apache.ignite.internal.managers.communication.GridIoPolicy; import org.apache.ignite.internal.managers.communication.GridMessageListener; +import org.apache.ignite.internal.managers.communication.MessageMarshalling; import org.apache.ignite.internal.managers.deployment.GridDeploymentInfo; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.distributed.dht.CacheGetFuture; @@ -115,12 +117,37 @@ public class GridCacheIoManager extends GridCacheSharedManagerAdapter { /** Common message handler identifier that does not correspond to any particular cache. */ public static final int COMMON_MESSAGE_HANDLER_ID = 0; - /** Delay in milliseconds between retries. */ - private long retryDelay; - /** Number of retries using to send messages. */ private int retryCnt; + /** Retry policy of {@link #send(ClusterNode, GridCacheMessage, byte)}: pings the node and retries up to {@link #retryCnt} times. */ + private final SendRetryPolicy sendRetryPlc = (node, e, attempt) -> { + if (!cctx.discovery().alive(node.id()) || !cctx.discovery().pingNode(node.id())) + throw new ClusterTopologyCheckedException("Node left grid while sending message to: " + node.id(), e); + + if (attempt > retryCnt || cctx.kernalContext().isStopping()) + return false; + + if (log.isDebugEnabled()) + log.debug("Failed to send message to node (will retry): " + node.id()); + + return true; + }; + + /** Retry policy of {@link #sendOrderedMessage}: retries up to {@link #retryCnt} times while the node stays in topology. */ + private final SendRetryPolicy orderedSendRetryPlc = (node, e, attempt) -> { + if (cctx.discovery().node(node.id()) == null) + throw new ClusterTopologyCheckedException("Node left grid while sending ordered message to: " + node.id(), e); + + if (attempt > retryCnt) + return false; + + if (log.isDebugEnabled()) + log.debug("Failed to send message to node (will retry): " + node.id()); + + return true; + }; + /** */ private final MessageHandlers cacheHandlers = new MessageHandlers(); @@ -489,7 +516,6 @@ private void sendMessageForMissedHandler( /** {@inheritDoc} */ @Override public void start0() throws IgniteCheckedException { - retryDelay = cctx.gridConfig().getNetworkSendRetryDelay(); retryCnt = cctx.gridConfig().getNetworkSendRetryCount(); depEnabled = cctx.gridDeploy().enabled(); @@ -741,7 +767,8 @@ else if (cacheMsg instanceof GridNearAtomicCheckUpdateRequest) * @param plc Message policy. * @throws IgniteCheckedException If failed. */ - private void processFailedMessage(UUID nodeId, + public void processFailedMessage( + UUID nodeId, GridCacheMessage msg, IgniteBiInClosure c, byte plc) @@ -1095,7 +1122,7 @@ private boolean onSend(GridCacheMessage msg, @Nullable UUID destNodeId) throws I msg.messageId(idGen.incrementAndGet()); if (destNodeId == null || !cctx.localNodeId().equals(destNodeId)) { - msg.prepareMarshal(cctx); + GridCacheMessageDeployer.deploy(cctx.kernalContext().messageFactory(), msg, cctx); if (msg instanceof GridCacheDeployable && msg.addDeploymentInfo()) cctx.deploy().prepare((GridCacheDeployable)msg); @@ -1136,32 +1163,10 @@ public void send(ClusterNode node, GridCacheMessage msg, byte plc) throws Ignite if (log.isDebugEnabled()) log.debug("Sending cache message [msg=" + msg + ", node=" + U.toShortString(node) + ']'); - int cnt = 0; - - while (true) { - try { - cctx.gridIO().sendToGridTopic(node, TOPIC_CACHE, msg, plc); - - if (log.isDebugEnabled()) - log.debug("Sent cache message [msg=" + msg + ", node=" + U.toShortString(node) + ']'); + cctx.gridIO().sendWithRetry(node, TOPIC_CACHE, msg, plc, false, 0, false, sendRetryPlc); - return; - } - catch (ClusterTopologyCheckedException e) { - throw e; - } - catch (IgniteCheckedException e) { - if (!cctx.discovery().alive(node.id()) || !cctx.discovery().pingNode(node.id())) - throw new ClusterTopologyCheckedException("Node left grid while sending message to: " + node.id(), e); - - if (cnt++ >= retryCnt || cctx.kernalContext().isStopping()) - throw e; - else if (log.isDebugEnabled()) - log.debug("Failed to send message to node (will retry): " + node.id()); - } - - U.sleep(retryDelay); - } + if (log.isDebugEnabled()) + log.debug("Sent cache message [msg=" + msg + ", node=" + U.toShortString(node) + ']'); } /** @@ -1197,33 +1202,16 @@ public void sendOrderedMessage(ClusterNode node, Object topic, GridCacheMessage msg.lastAffinityChangedTopologyVersion(cctx.exchange().lastAffinityChangedTopologyVersion(msg.topologyVersion())); - int cnt = 0; - - while (true) { - try { - cctx.gridIO().sendOrderedMessage(node, topic, msg, plc, timeout, false); + if (node.isLocal()) { + cctx.gridIO().sendOrderedMessage(node, topic, msg, plc, timeout, false); - if (log.isDebugEnabled()) - log.debug("Sent ordered cache message [topic=" + topic + ", msg=" + msg + - ", nodeId=" + node.id() + ']'); + return; + } - return; - } - catch (ClusterTopologyCheckedException e) { - throw e; - } - catch (IgniteCheckedException e) { - if (cctx.discovery().node(node.id()) == null) - throw new ClusterTopologyCheckedException("Node left grid while sending ordered message to: " + node.id(), e); - - if (cnt++ >= retryCnt) - throw e; - else if (log.isDebugEnabled()) - log.debug("Failed to send message to node (will retry): " + node.id()); - } + cctx.gridIO().sendWithRetry(node, topic, msg, plc, true, timeout, false, orderedSendRetryPlc); - U.sleep(retryDelay); - } + if (log.isDebugEnabled()) + log.debug("Sent ordered cache message [topic=" + topic + ", msg=" + msg + ", nodeId=" + node.id() + ']'); } /** @@ -1551,12 +1539,12 @@ private void unmarshall(UUID nodeId, GridCacheMessage cacheMsg) { log.debug("Set P2P context [senderId=" + nodeId + ", msg=" + cacheMsg + ']'); } - cacheMsg.finishUnmarshal(cctx, cctx.deploy().globalLoader()); + MessageMarshalling.unmarshal(cacheMsg, cctx.kernalContext(), null, cctx.deploy().globalLoader()); } catch (IgniteCheckedException e) { cacheMsg.onClassError(e); } - catch (BinaryObjectException e) { + catch (BinaryObjectException | CacheObjectNotResolvedException e) { cacheMsg.onClassError(new IgniteCheckedException(e)); } catch (Error e) { diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java index d2ead2bb39d93..e50b225d1ef93 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMapEntry.java @@ -282,12 +282,12 @@ protected void value(@Nullable CacheObject val) { lockEntry(); try { - key.prepareMarshal(cctx.cacheObjectContext()); + key.marshal(cctx.cacheObjectContext()); kb = key.valueBytes(cctx.cacheObjectContext()); if (val != null) { - val.prepareMarshal(cctx.cacheObjectContext()); + val.marshal(cctx.cacheObjectContext()); vb = val.valueBytes(cctx.cacheObjectContext()); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMessage.java index ec670da2d1cbf..bbbefa0495d60 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMessage.java @@ -24,6 +24,7 @@ import javax.cache.processor.EntryProcessor; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteLogger; +import org.apache.ignite.internal.DeferredUnmarshalMessage; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.managers.deployment.GridDeployment; import org.apache.ignite.internal.managers.deployment.GridDeploymentInfo; @@ -31,18 +32,19 @@ import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.transactions.IgniteTxEntry; import org.apache.ignite.internal.util.tostring.GridToStringInclude; +import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.T2; -import org.apache.ignite.internal.util.typedef.internal.CU; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.marshaller.Marshaller; -import org.apache.ignite.plugin.extensions.communication.Message; import org.jetbrains.annotations.Nullable; /** * Parent of all cache messages. + * + * @see DeployableMessage */ -public abstract class GridCacheMessage implements Message { +public abstract class GridCacheMessage implements DeferredUnmarshalMessage { /** Maximum number of cache lookup indexes. */ public static final int MAX_CACHE_MSG_LOOKUP_INDEX = 7; @@ -200,27 +202,28 @@ public void lastAffinityChangedTopologyVersion(AffinityTopologyVersion topVer) { public abstract boolean addDeploymentInfo(); /** - * @param o Object to prepare for marshalling. + * @param o Object to deploy. * @param ctx Context. * @throws IgniteCheckedException If failed. */ - protected final void prepareObject(@Nullable Object o, GridCacheContext ctx) throws IgniteCheckedException { - prepareObject(o, ctx.shared()); + public final void deployObject(@Nullable Object o, @Nullable GridCacheContext ctx) throws IgniteCheckedException { + if (ctx != null) + deployObject(o, ctx.shared()); } /** - * @param o Object to prepare for marshalling. + * @param o Object to deploy. * @param ctx Context. * @throws IgniteCheckedException If failed. */ - protected final void prepareObject(@Nullable Object o, GridCacheSharedContext ctx) throws IgniteCheckedException { + final void deployObject(@Nullable Object o, GridCacheSharedContext ctx) throws IgniteCheckedException { assert addDepInfo || forceAddDepInfo; if (!skipPrepare && o != null) { GridDeploymentInfo d = ctx.deploy().globalDeploymentInfo(); if (d != null) { - prepare(d); + deploy(d); // Global deployment has been injected. skipPrepare = true; @@ -233,16 +236,22 @@ protected final void prepareObject(@Nullable Object o, GridCacheSharedContext ct ClassLoader ldr = U.detectClassLoader(cls); if (ldr instanceof GridDeploymentInfo) - prepare((GridDeploymentInfo)ldr); + deploy((GridDeploymentInfo)ldr); } } } + /** Forces deployment info to be added when peer-class-loading is enabled. */ + public final void forceDeploymentInfo(GridCacheSharedContext ctx) { + if (!addDepInfo && ctx.deploymentEnabled()) + addDepInfo = true; + } + /** * @param depInfo Deployment to set. - * @see GridCacheDeployable#prepare(GridDeploymentInfo) + * @see GridCacheDeployable#deploy(GridDeploymentInfo) */ - public final void prepare(GridDeploymentInfo depInfo) { + public final void deploy(GridDeploymentInfo depInfo) { if (depInfo != this.depInfo) { if (this.depInfo != null && depInfo instanceof GridDeployment) // Make sure not to replace remote deployment with local. @@ -262,72 +271,39 @@ public GridDeploymentInfoBean deployInfo() { return depInfo; } - /** - * This method is called before the whole message is serialized - * and is responsible for pre-marshalling state. - * - * @param ctx Cache context. - * @throws IgniteCheckedException If failed. - */ - public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - // No-op. - } - - /** - * This method is called after the message is deserialized and is responsible for - * unmarshalling state marshalled in {@link #prepareMarshal(GridCacheSharedContext)} method. - * - * @param ctx Context. - * @param ldr Class loader. - * @throws IgniteCheckedException If failed. - */ - public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - // No-op. - } - /** * @param info Entry to marshal. * @param ctx Context. * @param cacheObjCtx Cache object context. * @throws IgniteCheckedException If failed. */ - protected final void marshalInfo(GridCacheEntryInfo info, - GridCacheSharedContext ctx, + public final void deployInfo(GridCacheEntryInfo info, + GridCacheSharedContext ctx, CacheObjectContext cacheObjCtx ) throws IgniteCheckedException { assert ctx != null; if (info != null) { - info.marshal(cacheObjCtx); - if (addDepInfo) { if (info.key() != null) - prepareObject(info.key().value(cacheObjCtx, false), ctx); + deployObject(info.key().value(cacheObjCtx, false), ctx); CacheObject val = info.value(); if (val != null) { - val.finishUnmarshal(cacheObjCtx, ctx.deploy().globalLoader()); + val.unmarshal(cacheObjCtx, ctx.deploy().globalLoader()); - prepareObject(val.value(cacheObjCtx, false), ctx); + deployObject(val.value(cacheObjCtx, false), ctx); } } } } - /** - * @param info Entry to unmarshal. - * @param ctx Context. - * @param ldr Loader. - * @throws IgniteCheckedException If failed. - */ - protected final void unmarshalInfo(GridCacheEntryInfo info, GridCacheContext ctx, - ClassLoader ldr) throws IgniteCheckedException { - assert ldr != null; - assert ctx != null; - - if (info != null) - info.unmarshal(ctx.cacheObjectContext(), ldr); + /** Deploys all {@code infos}, resolving shared and cache-object contexts from {@code cctx}; no-op when {@code cctx} is absent. */ + public final void deployInfos(@Nullable Iterable infos, @Nullable GridCacheContext cctx) + throws IgniteCheckedException { + if (cctx != null) + deployInfos(infos, cctx.shared(), cctx.cacheObjectContext()); } /** @@ -335,32 +311,14 @@ protected final void unmarshalInfo(GridCacheEntryInfo info, GridCacheContext ctx * @param ctx Context. * @throws IgniteCheckedException If failed. */ - protected final void marshalInfos( - Iterable infos, - GridCacheSharedContext ctx, - CacheObjectContext cacheObjCtx - ) throws IgniteCheckedException { + final void deployInfos(@Nullable Iterable infos, GridCacheSharedContext ctx, + CacheObjectContext cacheObjCtx) throws IgniteCheckedException { assert ctx != null; - if (infos != null) + if (infos != null) { for (GridCacheEntryInfo e : infos) - marshalInfo(e, ctx, cacheObjCtx); - } - - /** - * @param infos Entries to unmarshal. - * @param ctx Context. - * @param ldr Loader. - * @throws IgniteCheckedException If failed. - */ - protected final void unmarshalInfos(Iterable infos, - GridCacheContext ctx, ClassLoader ldr) throws IgniteCheckedException { - assert ldr != null; - assert ctx != null; - - if (infos != null) - for (GridCacheEntryInfo e : infos) - unmarshalInfo(e, ctx, ldr); + deployInfo(e, ctx, cacheObjCtx); + } } /** @@ -368,29 +326,26 @@ protected final void unmarshalInfos(Iterable infos * @param ctx Context. * @throws IgniteCheckedException If failed. */ - protected final void marshalTx(Iterable txEntries, GridCacheSharedContext ctx) + public final void deployTx(Iterable txEntries, GridCacheSharedContext ctx) throws IgniteCheckedException { assert ctx != null; if (txEntries != null) { - boolean transferExpiry = transferExpiryPolicy(); boolean p2pEnabled = ctx.deploymentEnabled(); for (IgniteTxEntry e : txEntries) { - e.marshal(ctx, transferExpiry); - - GridCacheContext cctx = e.context(); + GridCacheContext cctx = e.context(); if (addDepInfo) { if (e.key() != null) - prepareObject(e.key().value(cctx.cacheObjectContext(), false), ctx); + deployObject(e.key().value(cctx.cacheObjectContext(), false), ctx); if (e.value() != null) - prepareObject(e.value().value(cctx.cacheObjectContext(), false), ctx); + deployObject(e.value().value(cctx.cacheObjectContext(), false), ctx); if (e.entryProcessors() != null) { for (T2, Object[]> entProc : e.entryProcessors()) - prepareObject(entProc.get1(), ctx); + deployObject(entProc.get1(), ctx); } } else if (p2pEnabled && e.entryProcessors() != null) { @@ -398,134 +353,101 @@ else if (p2pEnabled && e.entryProcessors() != null) { forceAddDepInfo = true; for (T2, Object[]> entProc : e.entryProcessors()) - prepareObject(entProc.get1(), ctx); + deployObject(entProc.get1(), ctx); } } } } /** - * @return {@code True} if entries expire policy should be marshalled. - */ - protected boolean transferExpiryPolicy() { - return false; - } - - /** - * @param txEntries Entries to unmarshal. - * @param ctx Context. - * @param ldr Loader. + * @param args Arguments to marshal. + * @param marsh Marshaller. + * @return Marshalled collection. * @throws IgniteCheckedException If failed. */ - protected final void unmarshalTx(Iterable txEntries, - GridCacheSharedContext ctx, - ClassLoader ldr) throws IgniteCheckedException { - assert ldr != null; - assert ctx != null; + protected final @Nullable List marshallInvokeArguments(@Nullable Object[] args, Marshaller marsh) + throws IgniteCheckedException { - if (txEntries != null) { - for (IgniteTxEntry e : txEntries) { - e.prepareUnmarshal(ctx, topologyVersion(), false); + if (F.isEmpty(args)) + return null; - e.unmarshal(ctx, false, ldr); - } - } + List argsBytes = new ArrayList<>(args.length); + + for (Object arg : args) + argsBytes.add(arg == null ? null : U.marshal(marsh, arg)); + + return argsBytes; } /** * @param args Arguments to marshal. * @param ctx Context. - * @return Marshalled collection. * @throws IgniteCheckedException If failed. */ - @Nullable protected final byte[][] marshalInvokeArguments(@Nullable Object[] args, GridCacheContext ctx) + public final void deployInvokeArguments(@Nullable Object[] args, @Nullable GridCacheContext ctx) throws IgniteCheckedException { - assert ctx != null; - - if (args == null || args.length == 0) - return null; - - byte[][] argsBytes = new byte[args.length][]; - - for (int i = 0; i < args.length; i++) { - Object arg = args[i]; - - if (addDepInfo) - prepareObject(arg, ctx.shared()); - - argsBytes[i] = arg == null ? null : CU.marshal(ctx, arg); - } + if (ctx == null || args == null || !addDepInfo) + return; - return argsBytes; + for (Object arg : args) + deployObject(arg, ctx.shared()); } - /** * @param byteCol Collection to unmarshal. - * @param ctx Context. + * @param marsh Marshaller. * @param ldr Loader. * @return Unmarshalled collection. * @throws IgniteCheckedException If failed. */ - @Nullable protected final Object[] unmarshalInvokeArguments(@Nullable byte[][] byteCol, - GridCacheSharedContext ctx, + protected final Object @Nullable [] unmarshalInvokeArguments(@Nullable List byteCol, + Marshaller marsh, ClassLoader ldr) throws IgniteCheckedException { - assert ldr != null; - assert ctx != null; - if (byteCol == null) return null; - Object[] args = new Object[byteCol.length]; + Object[] args = new Object[byteCol.size()]; - Marshaller marsh = ctx.marshaller(); + int i = 0; - for (int i = 0; i < byteCol.length; i++) - args[i] = byteCol[i] == null ? null : U.unmarshal(marsh, byteCol[i], U.resolveClassLoader(ldr, ctx.gridConfig())); + for (byte[] bytes : byteCol) + args[i++] = bytes == null ? null : U.unmarshal(marsh, bytes, ldr); return args; } /** * @param col Collection to marshal. - * @param ctx Context. + * @param marsh Marshaller. * @return Marshalled collection. * @throws IgniteCheckedException If failed. */ - @Nullable protected List marshalCollection(@Nullable Collection col, - GridCacheContext ctx) throws IgniteCheckedException { - assert ctx != null; - + protected @Nullable List marshallCollection(@Nullable Collection col, Marshaller marsh) throws IgniteCheckedException { if (col == null) return null; List byteCol = new ArrayList<>(col.size()); - for (Object o : col) { - if (addDepInfo) - prepareObject(o, ctx.shared()); - - byteCol.add(o == null ? null : CU.marshal(ctx, o)); - } + for (Object o : col) + byteCol.add(o == null ? null : U.marshal(marsh, o)); return byteCol; } /** - * @param col Collection. - * @param ctx Cache context. + * Deploys each element of {@code col} via {@link #deployObject} on each item. + * + * @param col Collection to marshal. + * @param ctx Context. * @throws IgniteCheckedException If failed. */ - @SuppressWarnings("ForLoopReplaceableByForEach") - public final void prepareMarshalCacheObjects(@Nullable List col, - GridCacheContext ctx) throws IgniteCheckedException { - if (col == null) + public final void deployCollection(@Nullable Collection col, + @Nullable GridCacheContext ctx) throws IgniteCheckedException { + if (ctx == null || col == null || !addDepInfo) return; - int size = col.size(); - - for (int i = 0; i < size; i++) - prepareMarshalCacheObject(col.get(i), ctx); + for (Object o : col) + deployObject(o, ctx.shared()); } /** @@ -533,13 +455,9 @@ public final void prepareMarshalCacheObjects(@Nullable List ctx) throws IgniteCheckedException { + if (ctx != null && obj != null && addDepInfo) + deployObject(obj.value(ctx.cacheObjectContext(), false), ctx.shared()); } /** @@ -547,85 +465,33 @@ protected final void prepareMarshalCacheObject(CacheObject obj, GridCacheContext * @param ctx Cache context. * @throws IgniteCheckedException If failed. */ - protected final void prepareMarshalCacheObjects(@Nullable Collection col, - GridCacheContext ctx) throws IgniteCheckedException { - if (col == null) + public final void deployCacheObjects(@Nullable Collection col, + @Nullable GridCacheContext ctx) throws IgniteCheckedException { + if (col == null || ctx == null || !addDepInfo) return; for (CacheObject obj : col) { - if (obj != null) { - obj.prepareMarshal(ctx.cacheObjectContext()); - - if (addDepInfo) - prepareObject(obj.value(ctx.cacheObjectContext(), false), ctx.shared()); - } - } - } - - /** - * @param col Collection. - * @param ctx Context. - * @param ldr Class loader. - * @throws IgniteCheckedException If failed. - */ - @SuppressWarnings("ForLoopReplaceableByForEach") - public final void finishUnmarshalCacheObjects(@Nullable List col, - GridCacheContext ctx, - ClassLoader ldr - ) throws IgniteCheckedException { - if (col == null) - return; - - int size = col.size(); - - for (int i = 0; i < size; i++) { - CacheObject obj = col.get(i); - if (obj != null) - obj.finishUnmarshal(ctx.cacheObjectContext(), ldr); - } - } - - /** - * @param col Collection. - * @param ctx Context. - * @param ldr Class loader. - * @throws IgniteCheckedException If failed. - */ - protected final void finishUnmarshalCacheObjects(@Nullable Collection col, - GridCacheContext ctx, - ClassLoader ldr - ) throws IgniteCheckedException { - if (col == null) - return; - - for (CacheObject obj : col) { - if (obj != null) - obj.finishUnmarshal(ctx.cacheObjectContext(), ldr); + deployObject(obj.value(ctx.cacheObjectContext(), false), ctx.shared()); } } /** * @param byteCol Collection to unmarshal. - * @param ctx Context. + * @param marsh Marshaller. * @param ldr Loader. * @return Unmarshalled collection. * @throws IgniteCheckedException If failed. */ - @Nullable protected List unmarshalCollection(@Nullable Collection byteCol, - GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - assert ldr != null; - assert ctx != null; - + protected @Nullable List unmarshalCollection(@Nullable Collection byteCol, + Marshaller marsh, ClassLoader ldr) throws IgniteCheckedException { if (byteCol == null) return null; List col = new ArrayList<>(byteCol.size()); - Marshaller marsh = ctx.marshaller(); - for (byte[] bytes : byteCol) - col.add(bytes == null ? null : U.unmarshal(marsh, bytes, U.resolveClassLoader(ldr, ctx.gridConfig()))); + col.add(bytes == null ? null : U.unmarshal(marsh, bytes, ldr)); return col; } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMessageDeployer.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMessageDeployer.java new file mode 100644 index 0000000000000..151c7f5ffa83d --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheMessageDeployer.java @@ -0,0 +1,55 @@ +/* + * 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.processors.cache; + +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.managers.communication.IgniteMessageFactory; +import org.apache.ignite.plugin.extensions.communication.MessageFactory; +import org.jetbrains.annotations.Nullable; + +/** + * Per-message deployer generated for a {@link GridCacheMessage} whose fields need deployment: the generated + * {@code Deployer} deploys them via {@code GridCacheMessage}'s public {@code deploy*} methods. The static + * {@link #deploy(MessageFactory, GridCacheMessage, GridCacheSharedContext)} resolves the deployer from the message + * factory and dispatches, mirroring the static {@code MessageMarshaller#marshal}. + */ +public interface GridCacheMessageDeployer { + /** Deploys all deployable fields of {@code msg}. */ + void deploy(M msg, GridCacheSharedContext ctx) throws IgniteCheckedException; + + /** + * Resolves {@code msg}'s deployer from the message factory and deploys the message's fields. A no-op when the + * message has no deployer, or {@code msg} is {@code null} — generated deployers delegate nested message fields + * here without null checks. Called both when sending a message and from a generated deployer for a nested message. + */ + @SuppressWarnings({"unchecked", "rawtypes"}) + static void deploy(MessageFactory factory, @Nullable GridCacheMessage msg, GridCacheSharedContext ctx) + throws IgniteCheckedException { + if (msg == null) + return; + + // Deployment info is collected only when peer class loading may need it; skip the field scans otherwise. + if (!msg.addDeploymentInfo() && !ctx.deploymentEnabled()) + return; + + GridCacheMessageDeployer deployer = ((IgniteMessageFactory)factory).deployer(msg.directType()); + + if (deployer != null) + deployer.deploy(msg, ctx); + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheReturn.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheReturn.java index b18f4ddef15b7..20203b5d8bb97 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheReturn.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheReturn.java @@ -22,7 +22,6 @@ import java.util.HashMap; import java.util.Map; import javax.cache.processor.EntryProcessorResult; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.binary.BinaryObject; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.UnregisteredBinaryTypeException; @@ -31,13 +30,14 @@ import org.apache.ignite.internal.util.typedef.internal.CU; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.plugin.extensions.communication.CacheIdAware; import org.apache.ignite.plugin.extensions.communication.Message; import org.jetbrains.annotations.Nullable; /** * Return value for cases where both, value and success flag need to be returned. */ -public class GridCacheReturn implements Message { +public class GridCacheReturn implements Message, CacheIdAware { /** Value. */ @GridToStringInclude(sensitive = true) private volatile Object v; @@ -121,7 +121,26 @@ public GridCacheReturn( /** * @return Value. */ - @Nullable public V value() { + @Nullable public V value(GridCacheContext ctx) { + if (v == null) { + if (cacheObj != null) + v = ctx.cacheObjectContext().unwrapBinaryIfNeeded(cacheObj, true, false, ctx.deploy().globalLoader()); + + if (invokeRes && invokeResCol != null) { + Map map0 = U.newHashMap(invokeResCol.size()); + + for (CacheInvokeDirectResult res : invokeResCol) { + CacheInvokeResult res0 = res.error() == null ? + CacheInvokeResult.fromResult(ctx.cacheObjectContext().unwrapBinaryIfNeeded(res.result(), true, false, null)) : + CacheInvokeResult.fromError(CU.prepareEntryProcessorError(res.error())); + + map0.put(ctx.cacheObjectContext().unwrapBinaryIfNeeded(res.key(), true, false, null), res0); + } + + v = map0; + } + } + return (V)v; } @@ -286,22 +305,20 @@ else if (err instanceof UnregisteredBinaryTypeException) } } - /** - * @return Cache ID. - */ - public int cacheId() { + /** {@inheritDoc} */ + @Override public int cacheId() { return cacheId; } /** * @param other Other result to merge with. */ - public synchronized void mergeEntryProcessResults(GridCacheReturn other) { + public synchronized void mergeEntryProcessResults(GridCacheContext ctx, GridCacheReturn other) { assert invokeRes || v == null : "Invalid state to merge: " + this; assert other.invokeRes; assert loc == other.loc : loc; - if (other.v == null) + if (other.value(ctx) == null) return; invokeRes = true; @@ -329,55 +346,6 @@ public void marshalResult(GridCacheContext ctx) { } } - /** - * @param ctx Cache context. - * @throws IgniteCheckedException If failed. - */ - public void prepareMarshal(GridCacheContext ctx) throws IgniteCheckedException { - assert !loc; - - if (cacheObj != null) - cacheObj.prepareMarshal(ctx.cacheObjectContext()); - - if (invokeRes && invokeResCol != null) { - for (CacheInvokeDirectResult res : invokeResCol) - res.prepareMarshal(ctx); - } - } - - /** - * @param ctx Cache context. - * @param ldr Class loader. - * @throws IgniteCheckedException If failed. - */ - public void finishUnmarshal(GridCacheContext ctx, ClassLoader ldr) throws IgniteCheckedException { - loc = true; - - if (cacheObj != null) { - cacheObj.finishUnmarshal(ctx.cacheObjectContext(), ldr); - - v = ctx.cacheObjectContext().unwrapBinaryIfNeeded(cacheObj, true, false, ldr); - } - - if (invokeRes && invokeResCol != null) { - for (CacheInvokeDirectResult res : invokeResCol) - res.finishUnmarshal(ctx, ldr); - - Map map0 = U.newHashMap(invokeResCol.size()); - - for (CacheInvokeDirectResult res : invokeResCol) { - CacheInvokeResult res0 = res.error() == null ? - CacheInvokeResult.fromResult(ctx.cacheObjectContext().unwrapBinaryIfNeeded(res.result(), true, false, null)) : - CacheInvokeResult.fromError(CU.prepareEntryProcessorError(res.error())); - - map0.put(ctx.cacheObjectContext().unwrapBinaryIfNeeded(res.key(), true, false, null), res0); - } - - v = map0; - } - } - - /** {@inheritDoc} */ @Override public String toString() { return S.toString(GridCacheReturn.class, this); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java index 48a3328d0469b..c97aefd68213f 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/IgniteCacheOffheapManagerImpl.java @@ -995,13 +995,19 @@ private long allocateForTree() throws IgniteCheckedException { assert info.ttl() == TTL_ETERNAL : info.ttl(); - batch.add(new DataRowCacheAware(info.key(), - info.value(), - info.version(), - part.id(), - info.expireTime(), - info.cacheId(), - grp.storeCacheIdInDataPage())); + try { + batch.add(new DataRowCacheAware(info.key(), + info.value(), + info.version(), + part.id(), + info.expireTime(), info.cacheId(), grp.storeCacheIdInDataPage())); + } + catch (IllegalStateException th) { + if (ctx.cacheContext(info.cacheId()) != null) + throw th; // Not a removed-cache race — propagate. + + // Ignoring removed cache entries. + } if (batch.size() == PRELOAD_SIZE_UNDER_CHECKPOINT_LOCK || !infos.hasNext()) { ctx.database().checkpointReadLock(); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/KeyCacheObjectImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/KeyCacheObjectImpl.java index f781fb3218b42..721eb3d813994 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/KeyCacheObjectImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/KeyCacheObjectImpl.java @@ -108,19 +108,20 @@ public KeyCacheObjectImpl(Object val, byte[] valBytes, int part) { /** {@inheritDoc} */ @Override public int hashCode() { - assert val != null; + if (val == null) + throw new CacheObjectNotResolvedException(); return IgniteUtils.hashCode(val); } /** {@inheritDoc} */ - @Override public void prepareMarshal(CacheObjectValueContext ctx) throws IgniteCheckedException { + @Override public void marshal(CacheObjectValueContext ctx) throws IgniteCheckedException { if (valBytes == null) valBytes = ctx.marshal(val); } /** {@inheritDoc} */ - @Override public void finishUnmarshal(CacheObjectValueContext ctx, ClassLoader ldr) throws IgniteCheckedException { + @Override public void unmarshal(CacheObjectValueContext ctx, ClassLoader ldr) throws IgniteCheckedException { if (val == null) { assert valBytes != null; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/StoredCacheData.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/StoredCacheData.java index dc94809a9446c..415bd5f890fc8 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/StoredCacheData.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/StoredCacheData.java @@ -19,11 +19,10 @@ import java.io.Serializable; import java.util.Collection; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.cache.QueryEntity; import org.apache.ignite.cdc.CdcCacheEvent; import org.apache.ignite.configuration.CacheConfiguration; -import org.apache.ignite.internal.MarshallableMessage; +import org.apache.ignite.internal.Marshalled; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.managers.encryption.GroupKeyEncrypted; import org.apache.ignite.internal.pagemem.store.IgnitePageStoreManager; @@ -32,9 +31,8 @@ import org.apache.ignite.internal.util.typedef.internal.A; import org.apache.ignite.internal.util.typedef.internal.CU; import org.apache.ignite.internal.util.typedef.internal.S; -import org.apache.ignite.internal.util.typedef.internal.U; -import org.apache.ignite.marshaller.Marshaller; import org.apache.ignite.marshaller.jdk.JdkMarshaller; +import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.plugin.extensions.communication.MessageFactory; /** @@ -45,13 +43,14 @@ *

* All changes must be made with the respect of RU rules. */ -public class StoredCacheData implements Serializable, CdcCacheEvent, MarshallableMessage { +public class StoredCacheData implements Serializable, CdcCacheEvent, Message { /** */ private static final long serialVersionUID = 0L; /** Cache configuration. */ @GridToStringInclude - private CacheConfiguration ccfg; + @Marshalled("ccfgBytes") + CacheConfiguration ccfg; /** Serialized {@link #ccfg}. */ @Order(0) @@ -59,7 +58,8 @@ public class StoredCacheData implements Serializable, CdcCacheEvent, Marshallabl /** Query entities. */ @GridToStringInclude - private Collection qryEntities; + @Marshalled("qryEntitiesBytes") + Collection qryEntities; /** Serialized {@link #qryEntities}. */ @Order(1) @@ -224,27 +224,4 @@ public StoredCacheData withSplittedCacheConfig(CacheConfigurationSplitter splitt return ccfg; } - /** {@inheritDoc} */ - @Override public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { - if (ccfg != null) - ccfgBytes = U.marshal(marsh, ccfg); - - if (qryEntities != null) - qryEntitiesBytes = U.marshal(marsh, qryEntities); - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { - if (ccfgBytes != null) { - ccfg = U.unmarshal(marsh, ccfgBytes, clsLdr); - - ccfgBytes = null; - } - - if (qryEntitiesBytes != null) { - qryEntities = U.unmarshal(marsh, qryEntitiesBytes, clsLdr); - - qryEntitiesBytes = null; - } - } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/BinaryMetadataVersionInfo.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/BinaryMetadataVersionInfo.java index 9fe6d19da4421..ca112d9f8777c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/BinaryMetadataVersionInfo.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/BinaryMetadataVersionInfo.java @@ -17,12 +17,10 @@ package org.apache.ignite.internal.processors.cache.binary; import java.io.Serializable; -import org.apache.ignite.IgniteCheckedException; -import org.apache.ignite.internal.MarshallableMessage; +import org.apache.ignite.internal.Marshalled; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.binary.BinaryMetadata; -import org.apache.ignite.internal.util.typedef.internal.U; -import org.apache.ignite.marshaller.Marshaller; +import org.apache.ignite.plugin.extensions.communication.Message; /** * Wrapper for {@link BinaryMetadata} which is stored in metadata local cache on each node. @@ -30,12 +28,13 @@ * The version refers solely to the internal protocol for updating BinaryMetadata and is unknown externally. * It can be updated dynamically from different nodes and threads on the same node. */ -public final class BinaryMetadataVersionInfo implements Serializable, MarshallableMessage { +public final class BinaryMetadataVersionInfo implements Serializable, Message { /** */ private static final long serialVersionUID = 0L; /** The actual binary metadata. */ - private BinaryMetadata metadata; + @Marshalled("metadataBytes") + BinaryMetadata metadata; /** Serialized binary metadata. */ @Order(0) @@ -129,22 +128,6 @@ boolean removing() { return removing; } - /** {@inheritDoc} */ - @Override public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { - if (metadata != null) - metadataBytes = U.marshal(marsh, metadata); - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { - if (metadataBytes != null) { - metadata = U.unmarshal(marsh, metadataBytes, clsLdr); - - // It is not required anymore. - metadataBytes = null; - } - } - /** {@inheritDoc} */ @Override public String toString() { return "[typeId=" + metadata.typeId() + diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/MetadataUpdateProposedMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/MetadataUpdateProposedMessage.java index 90820675c6252..deb2440f2d868 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/MetadataUpdateProposedMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/binary/MetadataUpdateProposedMessage.java @@ -17,18 +17,15 @@ package org.apache.ignite.internal.processors.cache.binary; import java.util.UUID; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.binary.BinaryObjectException; -import org.apache.ignite.internal.MarshallableMessage; +import org.apache.ignite.internal.Marshalled; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.binary.BinaryMetadata; import org.apache.ignite.internal.binary.BinaryMetadataHandler; import org.apache.ignite.internal.managers.communication.ErrorMessage; import org.apache.ignite.internal.managers.discovery.DiscoveryCustomMessage; import org.apache.ignite.internal.util.typedef.internal.S; -import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteUuid; -import org.apache.ignite.marshaller.Marshaller; import org.jetbrains.annotations.Nullable; /** @@ -73,13 +70,14 @@ * it gets blocked until {@link MetadataUpdateAcceptedMessage} arrives with accepted version * equals to pending version of this metadata to the moment when is was initially read by the thread. */ -public final class MetadataUpdateProposedMessage extends DiscoveryCustomMessage implements MarshallableMessage { +public final class MetadataUpdateProposedMessage extends DiscoveryCustomMessage { /** Node UUID which initiated metadata update. */ @Order(0) UUID origNodeId; /** */ - private BinaryMetadata metadata; + @Marshalled("metadataBytes") + BinaryMetadata metadata; /** Serialized {@link #metadata}. */ @Order(1) @@ -191,18 +189,6 @@ public int typeId() { return typeId; } - /** {@inheritDoc} */ - @Override public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { - if (metadata != null) - metadataBytes = U.marshal(marsh, metadata); - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(Marshaller marsh, ClassLoader ldr) throws IgniteCheckedException { - if (metadataBytes != null) - metadata = U.unmarshal(marsh, metadataBytes, ldr); - } - /** {@inheritDoc} */ @Override public String toString() { return S.toString(MetadataUpdateProposedMessage.class, this); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheTtlUpdateRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheTtlUpdateRequest.java index c83e732f6181a..306b2f6d90181 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheTtlUpdateRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridCacheTtlUpdateRequest.java @@ -19,12 +19,9 @@ import java.util.ArrayList; import java.util.List; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; -import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheIdMessage; -import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.util.tostring.GridToStringInclude; @@ -155,35 +152,11 @@ public List nearVersions() { return nearVers; } - /** {@inheritDoc} */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - - GridCacheContext cctx = ctx.cacheContext(cacheId); - - prepareMarshalCacheObjects(keys, cctx); - - prepareMarshalCacheObjects(nearKeys, cctx); - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) - throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - GridCacheContext cctx = ctx.cacheContext(cacheId); - - finishUnmarshalCacheObjects(keys, cctx, ldr); - - finishUnmarshalCacheObjects(nearKeys, cctx, ldr); - } - /** {@inheritDoc} */ @Override public boolean addDeploymentInfo() { return false; } - /** {@inheritDoc} */ @Override public String toString() { return S.toString(GridCacheTtlUpdateRequest.class, this, "super", super.toString()); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedLockRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedLockRequest.java index 82875ddab682d..a488669cb0db5 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedLockRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedLockRequest.java @@ -20,10 +20,8 @@ import java.util.ArrayList; import java.util.List; import java.util.UUID; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteLogger; import org.apache.ignite.internal.Order; -import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; @@ -382,26 +380,6 @@ public long timeout() { return ctx.txLockMessageLogger(); } - /** {@inheritDoc} - * @param ctx*/ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - - GridCacheContext cctx = ctx.cacheContext(cacheId); - - prepareMarshalCacheObjects(keys, cctx); - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - GridCacheContext cctx = ctx.cacheContext(cacheId); - - finishUnmarshalCacheObjects(keys, cctx, ldr); - } - - /** {@inheritDoc} */ @Override public String toString() { return S.toString(GridDistributedLockRequest.class, this, "keysCnt", retVals.length, diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedLockResponse.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedLockResponse.java index cbf10745a7a19..04a4c67b5a89c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedLockResponse.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedLockResponse.java @@ -19,7 +19,6 @@ import java.util.ArrayList; import java.util.List; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteLogger; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.managers.communication.ErrorMessage; @@ -159,22 +158,6 @@ protected int valuesSize() { return ctx.txLockMessageLogger(); } - /** {@inheritDoc} - * @param ctx*/ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - - prepareMarshalCacheObjects(vals, ctx.cacheContext(cacheId)); - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - finishUnmarshalCacheObjects(vals, ctx.cacheContext(cacheId), ldr); - } - - /** {@inheritDoc} */ @Override public String toString() { return S.toString(GridDistributedLockResponse.class, this, diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedTxPrepareRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedTxPrepareRequest.java index 68a53ca1936bc..53a45d8b32541 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedTxPrepareRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridDistributedTxPrepareRequest.java @@ -20,13 +20,11 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.Map; import java.util.UUID; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteLogger; +import org.apache.ignite.internal.Marshalled; import org.apache.ignite.internal.Order; -import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx; import org.apache.ignite.internal.processors.cache.transactions.IgniteTxEntry; @@ -37,7 +35,6 @@ import org.apache.ignite.internal.util.tostring.GridToStringBuilder; import org.apache.ignite.internal.util.tostring.GridToStringExclude; import org.apache.ignite.internal.util.tostring.GridToStringInclude; -import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.transactions.TransactionConcurrency; import org.apache.ignite.transactions.TransactionIsolation; import org.jetbrains.annotations.Nullable; @@ -102,7 +99,8 @@ public class GridDistributedTxPrepareRequest extends GridDistributedBaseMessage /** DHT versions to verify. */ @GridToStringInclude - private Map dhtVers; + @Marshalled(keys = "dhtVerKeys", values = "dhtVerVals") + public Map dhtVers; /** */ @Order(7) @@ -371,57 +369,6 @@ public void applicationAttributes(Map appAttrs) { this.txState = txState; } - /** {@inheritDoc} */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - - if (writes != null) - marshalTx(writes, ctx); - - if (reads != null) - marshalTx(reads, ctx); - - if (dhtVers != null && dhtVerKeys == null) { - for (IgniteTxKey key : dhtVers.keySet()) { - GridCacheContext cctx = ctx.cacheContext(key.cacheId()); - - key.prepareMarshal(cctx); - } - - dhtVerKeys = dhtVers.keySet(); - dhtVerVals = dhtVers.values(); - } - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - if (writes != null) - unmarshalTx(writes, ctx, ldr); - - if (reads != null) - unmarshalTx(reads, ctx, ldr); - - if (dhtVerKeys != null && dhtVers == null) { - assert dhtVerVals != null; - assert dhtVerKeys.size() == dhtVerVals.size(); - - Iterator keyIt = dhtVerKeys.iterator(); - Iterator verIt = dhtVerVals.iterator(); - - dhtVers = U.newHashMap(dhtVerKeys.size()); - - while (keyIt.hasNext()) { - IgniteTxKey key = keyIt.next(); - - key.finishUnmarshal(ctx.cacheContext(key.cacheId()), ldr); - - dhtVers.put(key, verIt.next()); - } - } - } - /** {@inheritDoc} */ @Override public boolean addDeploymentInfo() { return addDepInfo || forceAddDepInfo; @@ -452,7 +399,6 @@ private boolean isFlag(int mask) { return (flags & mask) != 0; } - /** {@inheritDoc} */ @Override public String toString() { StringBuilder flags = new StringBuilder(); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridNearUnlockRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridNearUnlockRequest.java index 7f46f96774850..268b923232f0c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridNearUnlockRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/GridNearUnlockRequest.java @@ -19,7 +19,6 @@ import java.util.ArrayList; import java.util.List; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteLogger; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; @@ -93,27 +92,11 @@ public void addKey(KeyCacheObject key) { return keys != null && !keys.isEmpty() ? keys.get(0).partition() : -1; } - /** {@inheritDoc} - * @param ctx*/ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - - prepareMarshalCacheObjects(keys, ctx.cacheContext(cacheId)); - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - finishUnmarshalCacheObjects(keys, ctx.cacheContext(cacheId), ldr); - } - /** {@inheritDoc} */ @Override public IgniteLogger messageLogger(GridCacheSharedContext ctx) { return ctx.txLockMessageLogger(); } - - + /** {@inheritDoc} */ @Override public String toString() { return S.toString(GridNearUnlockRequest.class, this, "super", super.toString()); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheAdapter.java index 7277db3ccd698..ec2e09483c0d1 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheAdapter.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtCacheAdapter.java @@ -1214,9 +1214,9 @@ protected void processNearSingleGetRequest(final UUID nodeId, final GridNearSing res0 = info; } else if (req.needVersion()) - res0 = new CacheVersionedValue(info.value(), info.version()); + res0 = new CacheVersionedValue(info.value(), info.version(), info.cacheId()); else - res0 = new CacheVersionedValue(info.value(), null); + res0 = new CacheVersionedValue(info.value(), null, info.cacheId()); } res = new GridNearSingleGetResponse( diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtLockFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtLockFuture.java index 10d87957edbac..91edf83d70998 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtLockFuture.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtLockFuture.java @@ -1033,9 +1033,6 @@ private void map(Iterable entries) { } assert added.dhtLocal(); - - if (added.ownerVersion() != null) - req.owned(e.key(), added.ownerVersion()); } catch (GridCacheEntryRemovedException ex) { if (log.isDebugEnabled()) { diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtLockRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtLockRequest.java index 0c51befe57960..3d20269b8d91c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtLockRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtLockRequest.java @@ -18,18 +18,12 @@ package org.apache.ignite.internal.processors.cache.distributed.dht; import java.util.BitSet; -import java.util.Map; import java.util.UUID; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; -import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.processors.cache.distributed.GridDistributedLockRequest; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; -import org.apache.ignite.internal.util.GridLeanMap; -import org.apache.ignite.internal.util.tostring.GridToStringExclude; -import org.apache.ignite.internal.util.tostring.GridToStringInclude; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.lang.IgniteUuid; import org.apache.ignite.transactions.TransactionIsolation; @@ -48,38 +42,24 @@ public class GridDhtLockRequest extends GridDistributedLockRequest { @Order(1) IgniteUuid miniId; - /** Owner mapped version, if any. */ - @GridToStringInclude - private Map owned; - - /** Array of keys from {@link #owned}. Used during marshalling and unmarshalling. */ - @Order(2) - @GridToStringExclude - KeyCacheObject[] ownedKeys; - - /** Array of values from {@link #owned}. Used during marshalling and unmarshalling. */ - @Order(3) - @GridToStringExclude - GridCacheVersion[] ownedValues; - /** Topology version. */ - @Order(4) + @Order(2) AffinityTopologyVersion topVer; /** Task name hash. */ - @Order(5) + @Order(3) int taskNameHash; /** Indexes of keys needed to be preloaded. */ - @Order(6) + @Order(4) BitSet preloadKeys; /** TTL for read operation. */ - @Order(7) + @Order(5) long accessTtl; /** Transaction label. */ - @Order(8) + @Order(6) String txLbl; /** @@ -218,19 +198,6 @@ public boolean needPreloadKey(int idx) { return preloadKeys != null && preloadKeys.get(idx); } - /** - * Sets owner and its mapped version. - * - * @param key Key. - * @param ownerMapped Owner mapped version. - */ - public void owned(KeyCacheObject key, GridCacheVersion ownerMapped) { - if (owned == null) - owned = new GridLeanMap<>(3); - - owned.put(key, ownerMapped); - } - /** * @param idx Entry index to check. * @return {@code True} if near entry should be invalidated. @@ -260,42 +227,6 @@ public long accessTtl() { return txLbl; } - /** {@inheritDoc} */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - - if (owned != null && ownedKeys == null) { - ownedKeys = new KeyCacheObject[owned.size()]; - ownedValues = new GridCacheVersion[ownedKeys.length]; - - int i = 0; - - for (Map.Entry entry : owned.entrySet()) { - ownedKeys[i] = entry.getKey(); - ownedValues[i] = entry.getValue(); - i++; - } - } - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - if (ownedKeys != null) { - owned = new GridLeanMap<>(ownedKeys.length); - - for (int i = 0; i < ownedKeys.length; i++) { - ownedKeys[i].finishUnmarshal(ctx.cacheContext(cacheId).cacheObjectContext(), ldr); - owned.put(ownedKeys[i], ownedValues[i]); - } - - ownedKeys = null; - ownedValues = null; - } - } - - /** {@inheritDoc} */ @Override public String toString() { return S.toString(GridDhtLockRequest.class, this, "super", super.toString()); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtLockResponse.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtLockResponse.java index e73f606c827eb..cf0b9b0680113 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtLockResponse.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtLockResponse.java @@ -23,6 +23,7 @@ import java.util.List; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.Order; +import org.apache.ignite.internal.processors.cache.DeployableMessage; import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheEntryInfo; import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; @@ -36,7 +37,7 @@ * DHT cache lock response. */ @SuppressWarnings("AssignmentOrReturnOfFieldWithMutableType") -public class GridDhtLockResponse extends GridDistributedLockResponse { +public class GridDhtLockResponse extends GridDistributedLockResponse implements DeployableMessage { /** Mini future ID. */ @Order(0) IgniteUuid miniId; @@ -124,24 +125,14 @@ public Collection preloadEntries() { } /** {@inheritDoc} */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); + @Override public void deploy(GridCacheSharedContext ctx) throws IgniteCheckedException { + if (preloadEntries != null) { + GridCacheContext cctx = ctx.cacheContext(cacheId); - GridCacheContext cctx = ctx.cacheContext(cacheId); - - if (preloadEntries != null) - marshalInfos(preloadEntries, cctx.shared(), cctx.cacheObjectContext()); - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - if (preloadEntries != null) - unmarshalInfos(preloadEntries, ctx.cacheContext(cacheId), ldr); + deployInfos(preloadEntries, cctx); + } } - /** {@inheritDoc} */ @Override public String toString() { return S.toString(GridDhtLockResponse.class, this, super.toString()); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxFinishResponse.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxFinishResponse.java index 352281f9b57c8..62c327c8d7ce5 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxFinishResponse.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxFinishResponse.java @@ -17,12 +17,9 @@ package org.apache.ignite.internal.processors.cache.distributed.dht; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.managers.communication.ErrorMessage; -import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheReturn; -import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.processors.cache.distributed.GridDistributedTxFinishResponse; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.util.typedef.internal.S; @@ -118,33 +115,6 @@ public boolean checkCommitted() { return checkCommitted; } - /** {@inheritDoc} */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - - if (retVal != null && retVal.cacheId() != 0) { - GridCacheContext cctx = ctx.cacheContext(retVal.cacheId()); - - assert cctx != null : retVal.cacheId(); - - retVal.prepareMarshal(cctx); - } - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) - throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - if (retVal != null && retVal.cacheId() != 0) { - GridCacheContext cctx = ctx.cacheContext(retVal.cacheId()); - - assert cctx != null : retVal.cacheId(); - - retVal.finishUnmarshal(cctx, ldr); - } - } - /** * @param retVal Return value. */ @@ -158,8 +128,7 @@ public void returnValue(GridCacheReturn retVal) { public GridCacheReturn returnValue() { return retVal; } - - + /** {@inheritDoc} */ @Override public String toString() { return S.toString(GridDhtTxFinishResponse.class, this, "super", super.toString()); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxLocalAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxLocalAdapter.java index 4c7e9313f5e16..74140402ca968 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxLocalAdapter.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxLocalAdapter.java @@ -496,7 +496,7 @@ private void addMapping( assert state == PREPARING : "Invalid tx state for " + "adding entry [msgId=" + msgId + ", e=" + e + ", tx=" + this + ']'; - e.unmarshal(cctx, false, cctx.deploy().globalLoader()); + e.initializeContext(cctx, topVer, false); checkInternal(e.txKey()); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareRequest.java index f8364dca6adb1..452e64978b9dc 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareRequest.java @@ -17,17 +17,16 @@ package org.apache.ignite.internal.processors.cache.distributed.dht; -import java.util.ArrayList; import java.util.BitSet; import java.util.Collection; import java.util.Collections; -import java.util.Iterator; -import java.util.List; import java.util.Map; import java.util.UUID; import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.Marshalled; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; +import org.apache.ignite.internal.processors.cache.DeployableMessage; import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.processors.cache.distributed.GridDistributedTxPrepareRequest; @@ -44,7 +43,7 @@ /** * DHT prepare request. */ -public class GridDhtTxPrepareRequest extends GridDistributedTxPrepareRequest { +public class GridDhtTxPrepareRequest extends GridDistributedTxPrepareRequest implements DeployableMessage { /** Max order. */ @Order(0) UUID nearNodeId; @@ -72,7 +71,8 @@ public class GridDhtTxPrepareRequest extends GridDistributedTxPrepareRequest { /** Owned versions by key. */ @GridToStringInclude - private Map owned; + @Marshalled(keys = "ownedKeys", values = "ownedVals") + Map owned; /** Owned keys. */ @Order(6) @@ -98,9 +98,6 @@ public class GridDhtTxPrepareRequest extends GridDistributedTxPrepareRequest { @Order(11) BitSet preloadKeys; - /** */ - private List nearWritesCacheMissed; - /** {@code True} if remote tx should skip adding itself to completed versions map on finish. */ @Order(12) boolean skipCompletedVers; @@ -187,13 +184,6 @@ public Collection updateCounters() { return updCntrs; } - /** - * @return Near cache writes for which cache was not found (possible if client near cache was closed). - */ - @Nullable public List nearWritesCacheMissed() { - return nearWritesCacheMissed; - } - /** * @return Near transaction ID. */ @@ -315,83 +305,18 @@ public boolean skipCompletedVersion() { return txLbl; } - /** - * {@inheritDoc} - * - * @param ctx - */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - + /** {@inheritDoc} */ + @Override public void deploy(GridCacheSharedContext ctx) throws IgniteCheckedException { if (owned != null && ownedKeys == null) { - ownedKeys = owned.keySet(); - - ownedVals = owned.values(); - - for (IgniteTxKey key: ownedKeys) { + for (IgniteTxKey key : owned.keySet()) { GridCacheContext cctx = ctx.cacheContext(key.cacheId()); - key.prepareMarshal(cctx); - if (addDepInfo) - prepareObject(key, cctx); + deployObject(key, cctx); } } - - if (nearWrites != null) - marshalTx(nearWrites, ctx); } - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - if (ownedKeys != null) { - assert ownedKeys.size() == ownedVals.size(); - - owned = U.newHashMap(ownedKeys.size()); - - Iterator keyIter = ownedKeys.iterator(); - - Iterator valIter = ownedVals.iterator(); - - while (keyIter.hasNext()) { - IgniteTxKey key = keyIter.next(); - - GridCacheContext cacheCtx = ctx.cacheContext(key.cacheId()); - - if (cacheCtx != null) { - key.finishUnmarshal(cacheCtx, ldr); - - owned.put(key, valIter.next()); - } - } - } - - if (nearWrites != null) { - for (Iterator it = nearWrites.iterator(); it.hasNext();) { - IgniteTxEntry e = it.next(); - - GridCacheContext cacheCtx = ctx.cacheContext(e.cacheId()); - - if (cacheCtx == null) { - it.remove(); - - if (nearWritesCacheMissed == null) - nearWritesCacheMissed = new ArrayList<>(); - - nearWritesCacheMissed.add(e.txKey()); - } - else { - e.context(cacheCtx); - - e.unmarshal(ctx, true, ldr); - } - } - } - } - - /** {@inheritDoc} */ @Override public int partition() { return U.safeAbs(version().hashCode()); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareResponse.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareResponse.java index 921f52790252b..f4ad3faa6bd50 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareResponse.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareResponse.java @@ -21,11 +21,8 @@ import java.util.Collection; import java.util.List; import java.util.Map; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.Order; -import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheEntryInfo; -import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.processors.cache.distributed.GridDistributedTxPrepareResponse; import org.apache.ignite.internal.processors.cache.transactions.IgniteTxKey; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; @@ -169,51 +166,6 @@ public void addPreloadEntry(GridCacheEntryInfo info) { preloadEntries.add(info); } - /** {@inheritDoc} */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - - if (nearEvicted != null) { - for (IgniteTxKey key : nearEvicted) { - GridCacheContext cctx = ctx.cacheContext(key.cacheId()); - - // Can be null if client near cache was removed, in this case assume do not need prepareMarshal. - if (cctx != null) - key.prepareMarshal(cctx); - } - } - - if (preloadEntries != null) { - for (GridCacheEntryInfo info : preloadEntries) { - GridCacheContext cctx = ctx.cacheContext(info.cacheId()); - - info.marshal(cctx); - } - } - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - if (nearEvicted != null) { - for (IgniteTxKey key : nearEvicted) { - GridCacheContext cctx = ctx.cacheContext(key.cacheId()); - - key.finishUnmarshal(cctx, ldr); - } - } - - if (preloadEntries != null) { - for (GridCacheEntryInfo info : preloadEntries) { - GridCacheContext cctx = ctx.cacheContext(info.cacheId()); - - info.unmarshal(cctx, ldr); - } - } - } - - /** {@inheritDoc} */ @Override public String toString() { return S.toString(GridDhtTxPrepareResponse.class, this, diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxRemote.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxRemote.java index c2ad54b41b910..de6676f8f138c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxRemote.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxRemote.java @@ -271,7 +271,7 @@ public UUID nearNodeId() { * @throws IgniteCheckedException If failed. */ public void addWrite(IgniteTxEntry entry, ClassLoader ldr) throws IgniteCheckedException { - entry.unmarshal(cctx, false, ldr); + entry.initializeContext(cctx, topVer, false); GridCacheContext cacheCtx = entry.context(); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtUnlockRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtUnlockRequest.java index 8c5fc051a69e7..609e319171a3e 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtUnlockRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtUnlockRequest.java @@ -21,7 +21,6 @@ import java.util.List; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.Order; -import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.processors.cache.distributed.GridNearUnlockRequest; import org.apache.ignite.internal.util.typedef.internal.S; @@ -70,20 +69,6 @@ public void addNearKey(KeyCacheObject key) nearKeys.add(key); } - /** {@inheritDoc} */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - - prepareMarshalCacheObjects(nearKeys, ctx.cacheContext(cacheId)); - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - finishUnmarshalCacheObjects(nearKeys, ctx.cacheContext(cacheId), ldr); - } - /** {@inheritDoc} */ @Override public String toString() { return S.toString(GridDhtUnlockRequest.class, this); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/TransactionAttributesAwareRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/TransactionAttributesAwareRequest.java index 4cc026c390cda..e24d5c0d41816 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/TransactionAttributesAwareRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/TransactionAttributesAwareRequest.java @@ -18,10 +18,8 @@ package org.apache.ignite.internal.processors.cache.distributed.dht; import java.util.Map; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.cache.GridCacheMessage; -import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.processors.cache.distributed.GridDistributedTxPrepareRequest; /** Wraps transaction prepare request with application attributes. */ @@ -57,16 +55,6 @@ public Map applicationAttributes() { return appAttrs; } - /** {@inheritDoc} */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - payload.prepareMarshal(ctx); - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - payload.finishUnmarshal(ctx, ldr); - } - /** {@inheritDoc} */ @Override public boolean addDeploymentInfo() { return false; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/AtomicApplicationAttributesAwareRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/AtomicApplicationAttributesAwareRequest.java index 7c37b474dd2b7..49bdc531a3049 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/AtomicApplicationAttributesAwareRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/AtomicApplicationAttributesAwareRequest.java @@ -18,10 +18,8 @@ package org.apache.ignite.internal.processors.cache.distributed.dht.atomic; import java.util.Map; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.cache.GridCacheIdMessage; -import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; /** Wraps atomic updates with application attributes. */ public class AtomicApplicationAttributesAwareRequest extends GridCacheIdMessage { @@ -57,16 +55,6 @@ public Map applicationAttributes() { return appAttrs; } - /** {@inheritDoc} */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - payload.prepareMarshal(ctx); - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - payload.finishUnmarshal(ctx, ldr); - } - /** {@inheritDoc} */ @Override public boolean addDeploymentInfo() { return false; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicNearResponse.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicNearResponse.java index f71e035bdac94..f7944ca52288c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicNearResponse.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicNearResponse.java @@ -18,11 +18,9 @@ package org.apache.ignite.internal.processors.cache.distributed.dht.atomic; import java.util.UUID; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.cache.GridCacheIdMessage; import org.apache.ignite.internal.processors.cache.GridCacheReturn; -import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.util.tostring.GridToStringExclude; import org.apache.ignite.internal.util.tostring.GridToStringInclude; @@ -171,22 +169,6 @@ public long futureId() { return false; } - /** {@inheritDoc} */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - - if (errs != null) - errs.prepareMarshal(this, ctx.cacheContext(cacheId)); - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - if (errs != null) - errs.finishUnmarshal(this, ctx.cacheContext(cacheId), ldr); - } - /** {@inheritDoc} */ @Override public String toString() { StringBuilder flags = new StringBuilder(); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicSingleUpdateRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicSingleUpdateRequest.java index 59988a5610ed1..667fb0dd0d752 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicSingleUpdateRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicSingleUpdateRequest.java @@ -19,13 +19,10 @@ import java.util.UUID; import javax.cache.processor.EntryProcessor; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.CacheObject; -import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheOperation; -import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.util.tostring.GridToStringInclude; @@ -314,54 +311,6 @@ private void near(boolean near) { return null; } - /** {@inheritDoc} */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - - GridCacheContext cctx = ctx.cacheContext(cacheId); - - prepareMarshalObject(key, cctx); - - prepareMarshalObject(val, cctx); - - prepareMarshalObject(prevVal, cctx); - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - GridCacheContext cctx = ctx.cacheContext(cacheId); - - finishUnmarshalObject(key, cctx, ldr); - - finishUnmarshalObject(val, cctx, ldr); - - finishUnmarshalObject(prevVal, cctx, ldr); - } - - /** - * @param obj CacheObject to marshal - * @param ctx context - * @throws IgniteCheckedException if error - */ - private void prepareMarshalObject(CacheObject obj, GridCacheContext ctx) throws IgniteCheckedException { - if (obj != null) - obj.prepareMarshal(ctx.cacheObjectContext()); - } - - /** - * @param obj CacheObject un to marshal - * @param ctx context - * @param ldr class loader - * @throws IgniteCheckedException if error - */ - private void finishUnmarshalObject(@Nullable CacheObject obj, GridCacheContext ctx, - ClassLoader ldr) throws IgniteCheckedException { - if (obj != null) - obj.finishUnmarshal(ctx.cacheObjectContext(), ldr); - } - /** * Cleanup values not needed after message was sent. */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicUpdateRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicUpdateRequest.java index 4f292290f627a..ad2e7bcc5e3a9 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicUpdateRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicUpdateRequest.java @@ -18,14 +18,15 @@ package org.apache.ignite.internal.processors.cache.distributed.dht.atomic; import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.UUID; import javax.cache.processor.EntryProcessor; import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.MarshallableMessage; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.CacheObject; +import org.apache.ignite.internal.processors.cache.DeployableMessage; import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheOperation; import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; @@ -36,13 +37,14 @@ import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.CU; import org.apache.ignite.internal.util.typedef.internal.S; +import org.apache.ignite.marshaller.Marshaller; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; /** * Lite dht cache backup update request. */ -public class GridDhtAtomicUpdateRequest extends GridDhtAtomicAbstractUpdateRequest { +public class GridDhtAtomicUpdateRequest extends GridDhtAtomicAbstractUpdateRequest implements MarshallableMessage, DeployableMessage { /** Keys to update. */ @GridToStringInclude @Order(0) @@ -465,71 +467,56 @@ else if (conflictVers != null) } /** {@inheritDoc} */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - - GridCacheContext cctx = ctx.cacheContext(cacheId); - - prepareMarshalCacheObjects(keys, cctx); - - prepareMarshalCacheObjects(vals, cctx); - - prepareMarshalCacheObjects(nearKeys, cctx); - - prepareMarshalCacheObjects(nearVals, cctx); - - prepareMarshalCacheObjects(prevVals, cctx); + @Override protected void cleanup() { + nearVals = null; + prevVals = null; + } + /** {@inheritDoc} */ + @Override public void marshal(Marshaller marsh) throws IgniteCheckedException { if (forceTransformBackups) { - // force addition of deployment info for entry processors if P2P is enabled globally. - if (!addDepInfo && ctx.deploymentEnabled()) - addDepInfo = true; - if (!F.isEmpty(invokeArgs) && invokeArgsBytes == null) - invokeArgsBytes = Arrays.asList(marshalInvokeArguments(invokeArgs, cctx)); + invokeArgsBytes = marshallInvokeArguments(invokeArgs, marsh); if (entryProcessorsBytes == null) - entryProcessorsBytes = marshalCollection(entryProcessors, cctx); + entryProcessorsBytes = marshallCollection(entryProcessors, marsh); if (nearEntryProcessorsBytes == null) - nearEntryProcessorsBytes = marshalCollection(nearEntryProcessors, cctx); + nearEntryProcessorsBytes = marshallCollection(nearEntryProcessors, marsh); } } /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - GridCacheContext cctx = ctx.cacheContext(cacheId); - - finishUnmarshalCacheObjects(keys, cctx, ldr); - - finishUnmarshalCacheObjects(vals, cctx, ldr); - - finishUnmarshalCacheObjects(nearKeys, cctx, ldr); - - finishUnmarshalCacheObjects(nearVals, cctx, ldr); - - finishUnmarshalCacheObjects(prevVals, cctx, ldr); - + @Override public void unmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { if (forceTransformBackups) { if (entryProcessors == null) - entryProcessors = unmarshalCollection(entryProcessorsBytes, ctx, ldr); + entryProcessors = unmarshalCollection(entryProcessorsBytes, marsh, clsLdr); if (invokeArgsBytes != null && invokeArgs == null) - invokeArgs = unmarshalInvokeArguments(invokeArgsBytes.toArray(new byte[invokeArgsBytes.size()][]), ctx, ldr); + invokeArgs = unmarshalInvokeArguments(invokeArgsBytes, marsh, clsLdr); if (nearEntryProcessors == null) - nearEntryProcessors = unmarshalCollection(nearEntryProcessorsBytes, ctx, ldr); + nearEntryProcessors = unmarshalCollection(nearEntryProcessorsBytes, marsh, clsLdr); } } /** {@inheritDoc} */ - @Override protected void cleanup() { - nearVals = null; - prevVals = null; - } + @Override public void deploy(GridCacheSharedContext ctx) throws IgniteCheckedException { + if (forceTransformBackups) { + GridCacheContext cctx = ctx.cacheContext(cacheId); + forceDeploymentInfo(ctx); + + if (!F.isEmpty(invokeArgs) && invokeArgsBytes == null) + deployInvokeArguments(invokeArgs, cctx); + + if (entryProcessorsBytes == null) + deployCollection(entryProcessors, cctx); + + if (nearEntryProcessorsBytes == null) + deployCollection(nearEntryProcessors, cctx); + } + } /** {@inheritDoc} */ @Override public String toString() { diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicUpdateResponse.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicUpdateResponse.java index a63354bc634fa..451a3c26ae25d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicUpdateResponse.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridDhtAtomicUpdateResponse.java @@ -22,7 +22,6 @@ import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteLogger; import org.apache.ignite.internal.Order; -import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheDeployable; import org.apache.ignite.internal.processors.cache.GridCacheIdMessage; import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; @@ -118,33 +117,6 @@ public void nearEvicted(List nearEvicted) { return partId; } - /** {@inheritDoc} */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - - GridCacheContext cctx = ctx.cacheContext(cacheId); - - // Can be null if client near cache was removed, in this case assume do not need prepareMarshal. - if (cctx != null) { - prepareMarshalCacheObjects(nearEvicted, cctx); - - if (errs != null) - errs.prepareMarshal(this, cctx); - } - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - GridCacheContext cctx = ctx.cacheContext(cacheId); - - finishUnmarshalCacheObjects(nearEvicted, cctx, ldr); - - if (errs != null) - errs.finishUnmarshal(this, cctx, ldr); - } - /** {@inheritDoc} */ @Override public boolean addDeploymentInfo() { return addDepInfo; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicAbstractUpdateFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicAbstractUpdateFuture.java index 21aa24e160865..d7638c11c8e5d 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicAbstractUpdateFuture.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicAbstractUpdateFuture.java @@ -365,7 +365,7 @@ final void completeFuture(@Nullable GridCacheReturn ret, Throwable err, @Nullabl ? null : (this.retval || op == TRANSFORM) ? cctx.unwrapBinaryIfNeeded( - ret.value(), + ret.value(cctx), keepBinary, U.deploymentClassLoader(cctx.kernalContext(), deploymentLdrId)) : ret.success(); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicFullUpdateRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicFullUpdateRequest.java index 62fcf3966d916..8e24a81240dd5 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicFullUpdateRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicFullUpdateRequest.java @@ -25,10 +25,12 @@ import javax.cache.processor.EntryProcessor; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.cache.CacheWriteSynchronizationMode; +import org.apache.ignite.internal.MarshallableMessage; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.CacheEntryPredicate; import org.apache.ignite.internal.processors.cache.CacheObject; +import org.apache.ignite.internal.processors.cache.DeployableMessage; import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheOperation; import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; @@ -41,6 +43,7 @@ import org.apache.ignite.internal.util.typedef.internal.CU; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.marshaller.Marshaller; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -51,7 +54,7 @@ /** * Lite DHT cache update request sent from near node to primary node. */ -public class GridNearAtomicFullUpdateRequest extends GridNearAtomicAbstractUpdateRequest { +public class GridNearAtomicFullUpdateRequest extends GridNearAtomicAbstractUpdateRequest implements MarshallableMessage, DeployableMessage { /** Keys to update. */ @Order(0) @GridToStringInclude @@ -328,94 +331,69 @@ else if (conflictVers != null) } /** {@inheritDoc} */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - - GridCacheContext cctx = ctx.cacheContext(cacheId); - - if (expiryPlc != null && expiryPlcBytes == null) - expiryPlcBytes = CU.marshal(cctx, new IgniteExternalizableExpiryPolicy(expiryPlc)); - - prepareMarshalCacheObjects(keys, cctx); - - if (filter != null) { - boolean hasFilter = false; + @Override public int partition() { + assert !F.isEmpty(keys); - for (CacheEntryPredicate p : filter) { - if (p != null) { - hasFilter = true; + return keys.get(0).partition(); + } - p.prepareMarshal(cctx); - } - } + /** {@inheritDoc} */ + @Override public void cleanup(boolean clearKeys) { + vals = null; + entryProcessors = null; + entryProcessorsBytes = null; + invokeArgs = null; + invokeArgsBytes = null; - if (!hasFilter) - filter = null; - } + if (clearKeys) + keys = null; + } + /** {@inheritDoc} */ + @Override public void marshal(Marshaller marsh) throws IgniteCheckedException { + if (expiryPlc != null && expiryPlcBytes == null) + expiryPlcBytes = U.marshal(marsh, new IgniteExternalizableExpiryPolicy(expiryPlc)); + if (operation() == TRANSFORM) { - // force addition of deployment info for entry processors if P2P is enabled globally. - if (!addDepInfo && ctx.deploymentEnabled()) - addDepInfo = true; - if (entryProcessorsBytes == null) - entryProcessorsBytes = marshalCollection(entryProcessors, cctx); + entryProcessorsBytes = marshallCollection(entryProcessors, marsh); if (!F.isEmpty(invokeArgs) && invokeArgsBytes == null) - invokeArgsBytes = Arrays.asList(marshalInvokeArguments(invokeArgs, cctx)); + invokeArgsBytes = marshallInvokeArguments(invokeArgs, marsh); } - else - prepareMarshalCacheObjects(vals, cctx); } /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - GridCacheContext cctx = ctx.cacheContext(cacheId); - + @Override public void unmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { if (expiryPlcBytes != null && expiryPlc == null) - expiryPlc = U.unmarshal(ctx, expiryPlcBytes, U.resolveClassLoader(ldr, ctx.gridConfig())); - - finishUnmarshalCacheObjects(keys, cctx, ldr); - - if (filter != null) { - for (CacheEntryPredicate p : filter) { - if (p != null) - p.finishUnmarshal(cctx, ldr); - } - } + expiryPlc = U.unmarshal(marsh, expiryPlcBytes, clsLdr); if (operation() == TRANSFORM) { if (entryProcessors == null) - entryProcessors = unmarshalCollection(entryProcessorsBytes, ctx, ldr); + entryProcessors = unmarshalCollection(entryProcessorsBytes, marsh, clsLdr); if (invokeArgsBytes != null && invokeArgs == null) - invokeArgs = unmarshalInvokeArguments(invokeArgsBytes.toArray(new byte[invokeArgsBytes.size()][]), ctx, ldr); + invokeArgs = unmarshalInvokeArguments(invokeArgsBytes, marsh, clsLdr); } - else - finishUnmarshalCacheObjects(vals, cctx, ldr); } /** {@inheritDoc} */ - @Override public int partition() { - assert !F.isEmpty(keys); + @Override public void deploy(GridCacheSharedContext ctx) throws IgniteCheckedException { + if (filter != null && filter.length == 0) + filter = null; - return keys.get(0).partition(); - } + if (operation() == TRANSFORM) { + GridCacheContext cctx = ctx.cacheContext(cacheId); - /** {@inheritDoc} */ - @Override public void cleanup(boolean clearKeys) { - vals = null; - entryProcessors = null; - entryProcessorsBytes = null; - invokeArgs = null; - invokeArgsBytes = null; + forceDeploymentInfo(ctx); - if (clearKeys) - keys = null; - } + if (entryProcessorsBytes == null) + deployCollection(entryProcessors, cctx); + if (!F.isEmpty(invokeArgs) && invokeArgsBytes == null) + deployInvokeArguments(invokeArgs, cctx); + } + } /** {@inheritDoc} */ @Override public String toString() { diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicSingleUpdateFilterRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicSingleUpdateFilterRequest.java index 7b072491d4f89..d5bdab4971dce 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicSingleUpdateFilterRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicSingleUpdateFilterRequest.java @@ -19,14 +19,11 @@ import java.util.Arrays; import java.util.UUID; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.cache.CacheWriteSynchronizationMode; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.CacheEntryPredicate; -import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheOperation; -import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.util.typedef.internal.S; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -91,43 +88,6 @@ public GridNearAtomicSingleUpdateFilterRequest() { return filter; } - /** {@inheritDoc} */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - - GridCacheContext cctx = ctx.cacheContext(cacheId); - - if (filter != null) { - boolean hasFilter = false; - - for (CacheEntryPredicate p : filter) { - if (p != null) { - hasFilter = true; - - p.prepareMarshal(cctx); - } - } - - if (!hasFilter) - filter = null; - } - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - if (filter != null) { - GridCacheContext cctx = ctx.cacheContext(cacheId); - - for (CacheEntryPredicate p : filter) { - if (p != null) - p.finishUnmarshal(cctx, ldr); - } - } - } - - /** {@inheritDoc} */ @Override public String toString() { return S.toString(GridNearAtomicSingleUpdateFilterRequest.class, this, "filter", Arrays.toString(filter), diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicSingleUpdateFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicSingleUpdateFuture.java index cdbb251d049af..94b8db2443068 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicSingleUpdateFuture.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicSingleUpdateFuture.java @@ -253,11 +253,11 @@ else if (res.error() != null) if (op == TRANSFORM) { if (ret != null) { - assert ret.value() == null || ret.value() instanceof Map : ret.value(); + assert ret.value(cctx) == null || ret.value(cctx) instanceof Map : ret.value(cctx); - if (ret.value() != null) { + if (ret.value(cctx) != null) { if (opRes != null) - opRes.mergeEntryProcessResults(ret); + opRes.mergeEntryProcessResults(cctx, ret); else opRes = ret; } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicSingleUpdateInvokeRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicSingleUpdateInvokeRequest.java index 2b2e44f5e7ea7..a346a140c0a1c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicSingleUpdateInvokeRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicSingleUpdateInvokeRequest.java @@ -17,25 +17,26 @@ package org.apache.ignite.internal.processors.cache.distributed.dht.atomic; -import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.UUID; import javax.cache.processor.EntryProcessor; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.cache.CacheWriteSynchronizationMode; +import org.apache.ignite.internal.MarshallableMessage; +import org.apache.ignite.internal.Marshalled; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.CacheObject; +import org.apache.ignite.internal.processors.cache.DeployableMessage; import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheOperation; import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.util.typedef.F; -import org.apache.ignite.internal.util.typedef.internal.CU; import org.apache.ignite.internal.util.typedef.internal.S; -import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.marshaller.Marshaller; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; @@ -44,7 +45,8 @@ /** * */ -public class GridNearAtomicSingleUpdateInvokeRequest extends GridNearAtomicSingleUpdateRequest { +public class GridNearAtomicSingleUpdateInvokeRequest extends GridNearAtomicSingleUpdateRequest + implements MarshallableMessage, DeployableMessage { /** Optional arguments for entry processor. */ private @Nullable Object[] invokeArgs; @@ -53,7 +55,8 @@ public class GridNearAtomicSingleUpdateInvokeRequest extends GridNearAtomicSingl @Nullable List invokeArgsBytes; /** Entry processors. */ - private @Nullable EntryProcessor entryProc; + @Marshalled("entryProcBytes") + @Nullable EntryProcessor entryProc; /** Entry processors bytes. */ @Order(1) @@ -160,44 +163,38 @@ public GridNearAtomicSingleUpdateInvokeRequest() { } /** {@inheritDoc} */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - - GridCacheContext cctx = ctx.cacheContext(cacheId); - - // force addition of deployment info for entry processors if P2P is enabled globally. - if (!addDepInfo && ctx.deploymentEnabled()) - addDepInfo = true; - - if (entryProc != null && entryProcBytes == null) { - if (addDepInfo) - prepareObject(entryProc, cctx); + @Override public void cleanup(boolean clearKey) { + super.cleanup(clearKey); - entryProcBytes = CU.marshal(cctx, entryProc); - } + entryProc = null; + } + /** {@inheritDoc} */ + @Override public void marshal(Marshaller marsh) throws IgniteCheckedException { if (!F.isEmpty(invokeArgs) && invokeArgsBytes == null) - invokeArgsBytes = Arrays.asList(marshalInvokeArguments(invokeArgs, cctx)); + invokeArgsBytes = marshallInvokeArguments(invokeArgs, marsh); } /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - if (entryProcBytes != null && entryProc == null) - entryProc = U.unmarshal(ctx, entryProcBytes, U.resolveClassLoader(ldr, ctx.gridConfig())); - + @Override public void unmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { if (invokeArgsBytes != null && invokeArgs == null) - invokeArgs = unmarshalInvokeArguments(invokeArgsBytes.toArray(new byte[invokeArgsBytes.size()][]), ctx, ldr); + invokeArgs = unmarshalInvokeArguments(invokeArgsBytes, marsh, clsLdr); } /** {@inheritDoc} */ - @Override public void cleanup(boolean clearKey) { - super.cleanup(clearKey); + @Override public void deploy(GridCacheSharedContext ctx) throws IgniteCheckedException { + GridCacheContext cctx = ctx.cacheContext(cacheId); - entryProc = null; - } + forceDeploymentInfo(ctx); + if (entryProc != null && entryProcBytes == null) { + if (addDepInfo) + deployObject(entryProc, cctx); + } + + if (!F.isEmpty(invokeArgs) && invokeArgsBytes == null) + deployInvokeArguments(invokeArgs, cctx); + } /** {@inheritDoc} */ @Override public String toString() { diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicSingleUpdateRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicSingleUpdateRequest.java index 25b31b062c7c3..80b8d0b2f0e96 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicSingleUpdateRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicSingleUpdateRequest.java @@ -22,15 +22,12 @@ import java.util.UUID; import javax.cache.expiry.ExpiryPolicy; import javax.cache.processor.EntryProcessor; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.cache.CacheWriteSynchronizationMode; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.CacheEntryPredicate; import org.apache.ignite.internal.processors.cache.CacheObject; -import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheOperation; -import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.processors.cache.GridCacheUtils; import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; @@ -216,30 +213,6 @@ public GridNearAtomicSingleUpdateRequest() { return CU.EXPIRE_TIME_CALCULATE; } - /** {@inheritDoc} */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - - GridCacheContext cctx = ctx.cacheContext(cacheId); - - prepareMarshalCacheObject(key, cctx); - - if (val != null) - prepareMarshalCacheObject(val, cctx); - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - GridCacheContext cctx = ctx.cacheContext(cacheId); - - key.finishUnmarshal(cctx.cacheObjectContext(), ldr); - - if (val != null) - val.finishUnmarshal(cctx.cacheObjectContext(), ldr); - } - /** {@inheritDoc} */ @Override public void cleanup(boolean clearKey) { val = null; @@ -247,8 +220,7 @@ public GridNearAtomicSingleUpdateRequest() { if (clearKey) key = null; } - - + /** {@inheritDoc} */ @Override public String toString() { return S.toString(GridNearAtomicSingleUpdateRequest.class, this, "parent", super.toString()); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicUpdateFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicUpdateFuture.java index a0714a324c968..94fdc0c8ec0e8 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicUpdateFuture.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicUpdateFuture.java @@ -417,11 +417,11 @@ else if (res.error() != null) if (op == TRANSFORM) { if (ret != null) { - assert ret.value() == null || ret.value() instanceof Map : ret.value(); + assert ret.value(cctx) == null || ret.value(cctx) instanceof Map : ret.value(cctx); - if (ret.value() != null) { + if (ret.value(cctx) != null) { if (opRes != null) - opRes.mergeEntryProcessResults(ret); + opRes.mergeEntryProcessResults(cctx, ret); else opRes = ret; } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicUpdateResponse.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicUpdateResponse.java index a1103fb308d55..066ba444f0fe6 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicUpdateResponse.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/GridNearAtomicUpdateResponse.java @@ -25,6 +25,7 @@ import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.CacheObject; +import org.apache.ignite.internal.processors.cache.DeployableMessage; import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheDeployable; import org.apache.ignite.internal.processors.cache.GridCacheIdMessage; @@ -39,7 +40,7 @@ /** * DHT atomic cache near update response. */ -public class GridNearAtomicUpdateResponse extends GridCacheIdMessage implements GridCacheDeployable { +public class GridNearAtomicUpdateResponse extends GridCacheIdMessage implements GridCacheDeployable, DeployableMessage { /** Cache message index. */ public static final int CACHE_MSG_IDX = nextIndexId(); @@ -337,39 +338,6 @@ synchronized void addFailedKeys(Collection keys, Throwable e) { errs.addFailedKeys(keys, e); } - /** {@inheritDoc} - * @param ctx*/ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - - GridCacheContext cctx = ctx.cacheContext(cacheId); - - if (errs != null) - errs.prepareMarshal(this, cctx); - - if (nearUpdates != null) - prepareMarshalCacheObjects(nearUpdates.nearValues(), cctx); - - if (ret != null) - ret.prepareMarshal(cctx); - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - GridCacheContext cctx = ctx.cacheContext(cacheId); - - if (errs != null) - errs.finishUnmarshal(this, cctx, ldr); - - if (nearUpdates != null) - finishUnmarshalCacheObjects(nearUpdates.nearValues(), cctx, ldr); - - if (ret != null) - ret.finishUnmarshal(cctx, ldr); - } - /** * @return Data for near cache update. */ @@ -406,6 +374,14 @@ public void partition(int partId) { return ctx.atomicMessageLogger(); } + /** {@inheritDoc} */ + @Override public void deploy(GridCacheSharedContext ctx) throws IgniteCheckedException { + if (nearUpdates != null) { + GridCacheContext cctx = ctx.cacheContext(cacheId); + + deployCacheObjects(nearUpdates.nearValues(), cctx); + } + } /** {@inheritDoc} */ @Override public String toString() { diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/UpdateErrors.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/UpdateErrors.java index 0e42f82082251..820b5d7b4d17a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/UpdateErrors.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/atomic/UpdateErrors.java @@ -23,8 +23,6 @@ import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.managers.communication.ErrorMessage; -import org.apache.ignite.internal.processors.cache.GridCacheContext; -import org.apache.ignite.internal.processors.cache.GridCacheMessage; import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.util.tostring.GridToStringInclude; import org.apache.ignite.internal.util.typedef.internal.S; @@ -115,17 +113,6 @@ void addFailedKeys(Collection keys, Throwable e) { errMsg.error().addSuppressed(e); } - /** */ - void prepareMarshal(GridCacheMessage msg, GridCacheContext cctx) throws IgniteCheckedException { - msg.prepareMarshalCacheObjects(failedKeys, cctx); - } - - /** */ - void finishUnmarshal(GridCacheMessage msg, GridCacheContext cctx, ClassLoader ldr) throws IgniteCheckedException { - msg.finishUnmarshalCacheObjects(failedKeys, cctx, ldr); - } - - /** {@inheritDoc} */ @Override public String toString() { return S.toString(UpdateErrors.class, this); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtForceKeysRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtForceKeysRequest.java index 898ad4478f086..36e74d86c20be 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtForceKeysRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtForceKeysRequest.java @@ -18,13 +18,10 @@ package org.apache.ignite.internal.processors.cache.distributed.dht.preloader; import java.util.Collection; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; -import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheDeployable; import org.apache.ignite.internal.processors.cache.GridCacheIdMessage; -import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.util.tostring.GridToStringInclude; import org.apache.ignite.internal.util.typedef.F; @@ -113,24 +110,6 @@ public Collection keys() { return topVer; } - /** {@inheritDoc} */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - - GridCacheContext cctx = ctx.cacheContext(cacheId); - - prepareMarshalCacheObjects(keys, cctx); - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - GridCacheContext cctx = ctx.cacheContext(cacheId); - - finishUnmarshalCacheObjects(keys, cctx, ldr); - } - /** {@inheritDoc} */ @Override public boolean addDeploymentInfo() { return addDepInfo; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtForceKeysResponse.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtForceKeysResponse.java index cafcb5fa3e364..09afa95023c1b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtForceKeysResponse.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtForceKeysResponse.java @@ -23,11 +23,9 @@ import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.managers.communication.ErrorMessage; -import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheDeployable; import org.apache.ignite.internal.processors.cache.GridCacheEntryInfo; import org.apache.ignite.internal.processors.cache.GridCacheIdMessage; -import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.util.tostring.GridToStringInclude; import org.apache.ignite.internal.util.typedef.F; @@ -131,42 +129,11 @@ public void addInfo(GridCacheEntryInfo info) { infos.add(info); } - /** {@inheritDoc} */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - - GridCacheContext cctx = ctx.cacheContext(cacheId); - - if (missedKeys != null) - prepareMarshalCacheObjects(missedKeys, cctx); - - if (infos != null) { - for (GridCacheEntryInfo info : infos) - info.marshal(cctx.cacheObjectContext()); - } - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - GridCacheContext cctx = ctx.cacheContext(cacheId); - - if (missedKeys != null) - finishUnmarshalCacheObjects(missedKeys, cctx, ldr); - - if (infos != null) { - for (GridCacheEntryInfo info : infos) - info.unmarshal(cctx.cacheObjectContext(), ldr); - } - } - /** {@inheritDoc} */ @Override public boolean addDeploymentInfo() { return addDepInfo; } - /** {@inheritDoc} */ @Override public String toString() { return S.toString(GridDhtForceKeysResponse.class, this, super.toString()); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionSupplyMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionSupplyMessage.java index a800ab4d1f7a8..8b85ce7913a6a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionSupplyMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionSupplyMessage.java @@ -27,7 +27,6 @@ import org.apache.ignite.internal.Order; import org.apache.ignite.internal.managers.communication.ErrorMessage; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; -import org.apache.ignite.internal.processors.cache.CacheGroupContext; import org.apache.ignite.internal.processors.cache.CacheObjectContext; import org.apache.ignite.internal.processors.cache.GridCacheDeployable; import org.apache.ignite.internal.processors.cache.GridCacheEntryInfo; @@ -215,7 +214,7 @@ void addEntry0(int p, boolean historical, GridCacheEntryInfo info, GridCacheShar assert info.value() != null || historical : info; // Need to call this method to initialize info properly. - marshalInfo(info, ctx, cacheObjCtx); + deployInfo(info, ctx, cacheObjCtx); msgSize += info.marshalledSize(cacheObjCtx); @@ -230,21 +229,6 @@ void addEntry0(int p, boolean historical, GridCacheEntryInfo info, GridCacheShar infoCol.add(info); } - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - CacheGroupContext grp = ctx.cache().cacheGroup(grpId); - - if (grp == null) - return; - - for (List entries : getInfosSafe().values()) { - for (int i = 0; i < entries.size(); i++) - entries.get(i).unmarshal(grp.cacheObjectContext(), ldr); - } - } - /** {@inheritDoc} */ @Override public boolean addDeploymentInfo() { return addDepInfo; @@ -256,8 +240,7 @@ void addEntry0(int p, boolean historical, GridCacheEntryInfo info, GridCacheShar public int size() { return getInfosSafe().size(); } - - + /** {@inheritDoc} */ @Override public String toString() { return S.toString(GridDhtPartitionSupplyMessage.class, this, diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java index e3c7b42dc7f6e..61ee42f498ce6 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsExchangeFuture.java @@ -66,6 +66,7 @@ import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException; import org.apache.ignite.internal.events.DiscoveryCustomEvent; import org.apache.ignite.internal.managers.communication.GridIoPolicy; +import org.apache.ignite.internal.managers.communication.MessageMarshalling; import org.apache.ignite.internal.managers.discovery.DiscoCache; import org.apache.ignite.internal.managers.discovery.DiscoveryCustomMessage; import org.apache.ignite.internal.pagemem.wal.record.ExchangeRecord; @@ -3876,7 +3877,9 @@ else if (exchCtx.events().hasServerLeft()) else if (forceAffReassignment) msg.idealAffinityDiff(idealAffDiff); - msg.prepareMarshal(cctx); + // Marshal eagerly: the heavy partition-map copy lands in the "Full message preparing" stage, and the + // message cached in FinishState is sent to late joiners as is (the send-path marshal-once turns no-op). + MessageMarshalling.marshal(msg, cctx.kernalContext(), null); timeBag.finishGlobalStage("Full message preparing"); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsFullMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsFullMessage.java index f8fc363a829dd..0f80b015b48ba 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsFullMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsFullMessage.java @@ -92,17 +92,13 @@ public class GridDhtPartitionsFullMessage extends GridDhtPartitionsAbstractMessa @Order(6) AffinityTopologyVersion topVer; - /** Exceptions. */ - @GridToStringInclude - private Map errs; - /** - * Used as a stub for serialization of {@link #errs}. - * All logic resides within getter and setter. + * Exceptions in wire form. The logical {@code Map} is exposed via + * {@link #getErrorsMap()} / {@link #setErrorsMap(Map)}. */ @Order(7) @Compress - @SuppressWarnings("unused") + @GridToStringInclude Map errMsgs; /** */ @@ -169,7 +165,7 @@ public GridDhtPartitionsFullMessage(@Nullable GridDhtPartitionExchangeId id, cp.partsToReload = partsToReload; cp.partsSizes = partsSizes; cp.topVer = topVer; - cp.errs = errs; + cp.errMsgs = errMsgs; cp.resTopVer = resTopVer; cp.joinedNodeAff = joinedNodeAff; cp.idealAffDiff = idealAffDiff; @@ -364,14 +360,17 @@ public Map> partitionSizes() { * @return Errors map. */ @Nullable Map getErrorsMap() { - return errs; + return errMsgs == null ? null : F.viewReadOnly(errMsgs, e -> e.error()); } /** * @param errs Errors map. */ void setErrorsMap(Map errs) { - this.errs = new HashMap<>(errs); + errMsgs = new HashMap<>(); + + for (Map.Entry e : errs.entrySet()) + errMsgs.put(e.getKey(), new ErrorMessage(e.getValue())); } /** @@ -389,11 +388,9 @@ public void rebalanced(boolean rebalanced) { } /** {@inheritDoc} */ - @Override public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { + @Override public void marshal(Marshaller marsh) throws IgniteCheckedException { if (!F.isEmpty(parts) && locParts == null) locParts = copyPartitionsMap(parts); - - errMsgs = errs == null ? null : F.viewReadOnly(errs, ErrorMessage::new); } /** @@ -411,7 +408,7 @@ public void topologyVersion(AffinityTopologyVersion topVer) { } /** {@inheritDoc} */ - @Override public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { + @Override public void unmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { if (locParts != null && parts == null) { parts = copyPartitionsMap(locParts); @@ -443,8 +440,6 @@ public void topologyVersion(AffinityTopologyVersion topVer) { if (parts == null) parts = new HashMap<>(); - - errs = errMsgs == null ? null : F.viewReadOnly(errMsgs, e -> e.error()); } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsSingleMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsSingleMessage.java index a4a28d2eed3c1..d2df0a081d076 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsSingleMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/preloader/GridDhtPartitionsSingleMessage.java @@ -23,14 +23,15 @@ import java.util.Map; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.Compress; +import org.apache.ignite.internal.MarshallableMessage; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.managers.communication.ErrorMessage; -import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.util.tostring.GridToStringInclude; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.S; +import org.apache.ignite.marshaller.Marshaller; import org.jetbrains.annotations.Nullable; /** @@ -38,7 +39,7 @@ * * Sent in response to {@link GridDhtPartitionsSingleRequest} and during processing partitions exchange future. */ -public class GridDhtPartitionsSingleMessage extends GridDhtPartitionsAbstractMessage { +public class GridDhtPartitionsSingleMessage extends GridDhtPartitionsAbstractMessage implements MarshallableMessage { /** Local partitions. */ @Order(0) @Compress @@ -291,9 +292,12 @@ public void exchangeStartTime(long exchangeStartTime) { } /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); + @Override public void marshal(Marshaller marsh) throws IgniteCheckedException { + // No-op. + } + /** {@inheritDoc} */ + @Override public void unmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { if (dupPartsData != null) { assert parts != null; @@ -315,7 +319,6 @@ public void exchangeStartTime(long exchangeStartTime) { } } - /** {@inheritDoc} */ @Override public String toString() { return S.toString(GridDhtPartitionsSingleMessage.class, this, super.toString()); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/CacheVersionedValue.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/CacheVersionedValue.java index af5d90f84d2a2..5546df99c8806 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/CacheVersionedValue.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/CacheVersionedValue.java @@ -17,20 +17,18 @@ package org.apache.ignite.internal.processors.cache.distributed.near; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.cache.CacheObject; -import org.apache.ignite.internal.processors.cache.CacheObjectContext; -import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.util.tostring.GridToStringInclude; import org.apache.ignite.internal.util.typedef.internal.S; +import org.apache.ignite.plugin.extensions.communication.CacheIdAware; import org.apache.ignite.plugin.extensions.communication.Message; /** * Cache object and version. */ -public class CacheVersionedValue implements Message { +public class CacheVersionedValue implements Message, CacheIdAware { /** Value. */ @Order(0) @GridToStringInclude @@ -40,19 +38,21 @@ public class CacheVersionedValue implements Message { @Order(1) @GridToStringInclude GridCacheVersion ver; + + /** */ + @Order(2) + int cacheId; /** */ public CacheVersionedValue() { // No-op. } - /** - * @param val Cache value. - * @param ver Cache version. - */ - public CacheVersionedValue(CacheObject val, GridCacheVersion ver) { + /** */ + public CacheVersionedValue(CacheObject val, GridCacheVersion ver, int cacheId) { this.val = val; this.ver = ver; + this.cacheId = cacheId; } /** @@ -69,34 +69,14 @@ public CacheObject value() { return val; } - /** - * This method is called before the whole message is sent - * and is responsible for pre-marshalling state. - * - * @param ctx Cache object context. - * @throws IgniteCheckedException If failed. - */ - public void prepareMarshal(CacheObjectContext ctx) throws IgniteCheckedException { - if (val != null) - val.prepareMarshal(ctx); - } - - /** - * This method is called after the whole message is received - * and is responsible for unmarshalling state. - * - * @param ctx Context. - * @param ldr Class loader. - * @throws IgniteCheckedException If failed. - */ - public void finishUnmarshal(GridCacheContext ctx, ClassLoader ldr) throws IgniteCheckedException { - if (val != null) - val.finishUnmarshal(ctx.cacheObjectContext(), ldr); - } - /** {@inheritDoc} */ @Override public String toString() { return S.toString(CacheVersionedValue.class, this); } + + /** {@inheritDoc} */ + @Override public int cacheId() { + return cacheId; + } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetFuture.java index a8df9c74253c6..75ef1509bc4af 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetFuture.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetFuture.java @@ -628,8 +628,6 @@ private Map loadEntries( for (GridCacheEntryInfo info : infos) { try { - info.unmarshalValue(cctx, cctx.deploy().globalLoader()); - // Entries available locally in DHT should not be loaded into near cache for reading. if (!cctx.affinity().keyLocalNode(info.key(), cctx.affinity().affinityTopologyVersion())) { GridNearCacheEntry entry = savedEntries.get(info.key()); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetRequest.java index 74ad48394405d..972aa6f0ebe0b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetRequest.java @@ -22,13 +22,10 @@ import java.util.LinkedHashMap; import java.util.List; import java.util.Map; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; -import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheDeployable; import org.apache.ignite.internal.processors.cache.GridCacheIdMessage; -import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.processors.cache.version.GridCacheVersionable; @@ -43,8 +40,7 @@ /** * Get request. Responsible for obtaining entry from primary node. 'Near' means 'Initiating node' here, not 'Near Cache'. */ -public class GridNearGetRequest extends GridCacheIdMessage implements GridCacheDeployable, - GridCacheVersionable { +public class GridNearGetRequest extends GridCacheIdMessage implements GridCacheDeployable, GridCacheVersionable { /** */ private static final int READ_THROUGH_FLAG_MASK = 0x01; @@ -215,6 +211,18 @@ public int taskNameHash() { * @return Keys. */ public LinkedHashMap keyMap() { + if (keyMap == null && !F.isEmpty(keys)) { + keyMap = U.newLinkedHashMap(keys.size()); + + Iterator keysIt = keys.iterator(); + + for (int i = 0; i < keys.size(); i++) { + Boolean addRdr = readersFlags != null ? readersFlags.get(i) : Boolean.FALSE; + + keyMap.put(keysIt.next(), addRdr); + } + } + return keyMap; } @@ -280,56 +288,11 @@ public long accessTtl() { return txLbl; } - /** - * @param ctx Cache context. - * @throws IgniteCheckedException If failed. - */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - - assert ctx != null; - assert !F.isEmpty(keys); - assert readersFlags == null || keys.size() == readersFlags.size(); - - GridCacheContext cctx = ctx.cacheContext(cacheId); - - prepareMarshalCacheObjects(keys, cctx); - } - - /** - * @param ctx Context. - * @param ldr Loader. - * @throws IgniteCheckedException If failed. - */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - GridCacheContext cctx = ctx.cacheContext(cacheId); - - finishUnmarshalCacheObjects(keys, cctx, ldr); - - assert !F.isEmpty(keys); - assert readersFlags == null || keys.size() == readersFlags.size(); - - if (keyMap == null) { - keyMap = U.newLinkedHashMap(keys.size()); - - Iterator keysIt = keys.iterator(); - - for (int i = 0; i < keys.size(); i++) { - Boolean addRdr = readersFlags != null ? readersFlags.get(i) : Boolean.FALSE; - - keyMap.put(keysIt.next(), addRdr); - } - } - } - /** {@inheritDoc} */ @Override public boolean addDeploymentInfo() { return addDepInfo; } - /** {@inheritDoc} */ @Override public String toString() { return S.toString(GridNearGetRequest.class, this); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetResponse.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetResponse.java index 56f0aa1ca803d..c8a8c84b6b148 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetResponse.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearGetResponse.java @@ -19,15 +19,12 @@ import java.util.Collection; import java.util.Collections; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.managers.communication.ErrorMessage; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; -import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheDeployable; import org.apache.ignite.internal.processors.cache.GridCacheEntryInfo; import org.apache.ignite.internal.processors.cache.GridCacheIdMessage; -import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.processors.cache.version.GridCacheVersionable; import org.apache.ignite.internal.util.GridLeanSet; @@ -173,31 +170,6 @@ public void error(@Nullable Throwable err) { errMsg = new ErrorMessage(err); } - /** {@inheritDoc} - * @param ctx*/ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - - GridCacheContext cctx = ctx.cacheContext(cacheId); - - if (entries != null) { - for (GridCacheEntryInfo info : entries) - info.marshal(cctx); - } - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - GridCacheContext cctx = ctx.cacheContext(cacheId()); - - if (entries != null) { - for (GridCacheEntryInfo info : entries) - info.unmarshal(cctx, ldr); - } - } - /** {@inheritDoc} */ @Override public boolean addDeploymentInfo() { return addDepInfo; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearSingleGetRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearSingleGetRequest.java index 07ca1355fc0f0..45bb7739bf4ae 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearSingleGetRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearSingleGetRequest.java @@ -17,13 +17,10 @@ package org.apache.ignite.internal.processors.cache.distributed.near; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; -import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheDeployable; import org.apache.ignite.internal.processors.cache.GridCacheIdMessage; -import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.util.typedef.internal.S; import org.jetbrains.annotations.NotNull; @@ -249,28 +246,6 @@ public boolean recovery() { return (flags & RECOVERY_FLAG_MASK) != 0; } - /** {@inheritDoc} */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - - assert key != null; - - GridCacheContext cctx = ctx.cacheContext(cacheId); - - prepareMarshalCacheObject(key, cctx); - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - assert key != null; - - GridCacheContext cctx = ctx.cacheContext(cacheId); - - key.finishUnmarshal(cctx.cacheObjectContext(), ldr); - } - /** {@inheritDoc} */ @Override public boolean addDeploymentInfo() { return addDepInfo; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearSingleGetResponse.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearSingleGetResponse.java index 73f72ec4c0247..fcccd4494aca2 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearSingleGetResponse.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearSingleGetResponse.java @@ -22,9 +22,9 @@ import org.apache.ignite.internal.managers.communication.ErrorMessage; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.CacheObject; +import org.apache.ignite.internal.processors.cache.DeployableMessage; import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheDeployable; -import org.apache.ignite.internal.processors.cache.GridCacheEntryInfo; import org.apache.ignite.internal.processors.cache.GridCacheIdMessage; import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.util.typedef.internal.S; @@ -34,7 +34,7 @@ /** * */ -public class GridNearSingleGetResponse extends GridCacheIdMessage implements GridCacheDeployable { +public class GridNearSingleGetResponse extends GridCacheIdMessage implements GridCacheDeployable, DeployableMessage { /** */ public static final int INVALID_PART_FLAG_MASK = 0x1; @@ -145,34 +145,11 @@ public long futureId() { } /** {@inheritDoc} */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - - if (res != null) { + @Override public void deploy(GridCacheSharedContext ctx) throws IgniteCheckedException { + if (res instanceof CacheObject) { GridCacheContext cctx = ctx.cacheContext(cacheId); - if (res instanceof CacheObject) - prepareMarshalCacheObject((CacheObject)res, cctx); - else if (res instanceof CacheVersionedValue) - ((CacheVersionedValue)res).prepareMarshal(cctx.cacheObjectContext()); - else if (res instanceof GridCacheEntryInfo) - ((GridCacheEntryInfo)res).marshal(cctx); - } - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - if (res != null) { - GridCacheContext cctx = ctx.cacheContext(cacheId()); - - if (res instanceof CacheObject) - ((CacheObject)res).finishUnmarshal(cctx.cacheObjectContext(), ldr); - else if (res instanceof CacheVersionedValue) - ((CacheVersionedValue)res).finishUnmarshal(cctx, ldr); - else if (res instanceof GridCacheEntryInfo) - ((GridCacheEntryInfo)res).unmarshal(cctx, ldr); + deployCacheObject((CacheObject)res, cctx); } } @@ -181,7 +158,6 @@ else if (res instanceof GridCacheEntryInfo) return addDepInfo; } - /** {@inheritDoc} */ @Override public String toString() { return S.toString(GridNearSingleGetResponse.class, this); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java index f0f4ddaaf26d1..ba60bd7ded420 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxLocal.java @@ -1809,7 +1809,7 @@ private IgniteInternalFuture removeAllAsync0( true, keepBinary, U.deploymentClassLoader(cctx.kernalContext(), deploymentLdrId), - implicitRes.value(), + implicitRes.value(cacheCtx), implicitRes.success() ); } @@ -2672,7 +2672,7 @@ private IgniteInternalFuture optimisticPutFuture( try { txFut.get(); - Object res = implicitRes.value(); + Object res = implicitRes.value(cacheCtx); if (implicitRes.invokeResult()) { assert res == null || res instanceof Map : implicitRes; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxPrepareRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxPrepareRequest.java index 05b7f6ef918a1..3860c4cd00998 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxPrepareRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxPrepareRequest.java @@ -22,6 +22,7 @@ import java.util.Collections; import java.util.Map; import java.util.UUID; +import org.apache.ignite.internal.MarshallableMessage; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.GridCacheContext; @@ -33,12 +34,13 @@ import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteUuid; +import org.apache.ignite.marshaller.Marshaller; import org.jetbrains.annotations.Nullable; /** * Near transaction prepare request to primary node. 'Near' means 'Initiating node' here, not 'Near Cache'. */ -public class GridNearTxPrepareRequest extends GridDistributedTxPrepareRequest { +public class GridNearTxPrepareRequest extends GridDistributedTxPrepareRequest implements MarshallableMessage { /** */ private static final int NEAR_FLAG_MASK = 0x01; @@ -265,11 +267,6 @@ private Collection cloneEntries(Collection c) { return cp; } - /** {@inheritDoc} */ - @Override protected boolean transferExpiryPolicy() { - return true; - } - /** * Sets flag mask. * @@ -296,6 +293,25 @@ private boolean isFlag(int mask) { return U.safeAbs(version().hashCode()); } + /** {@inheritDoc} */ + @Override public void marshal(Marshaller marsh) { + // Of all tx messages, only the near prepare request transfers entry expiry policies. + if (writes() != null) { + for (IgniteTxEntry e : writes()) + e.transferExpiryPolicy(true); + } + + if (reads() != null) { + for (IgniteTxEntry e : reads()) + e.transferExpiryPolicy(true); + } + } + + /** {@inheritDoc} */ + @Override public void unmarshal(Marshaller marsh, ClassLoader clsLdr) { + // No-op. + } + /** {@inheritDoc} */ @Override public String toString() { StringBuilder flags = new StringBuilder(); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxPrepareResponse.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxPrepareResponse.java index 646335209b86e..2642f25d1305a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxPrepareResponse.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxPrepareResponse.java @@ -20,22 +20,18 @@ import java.util.Collection; import java.util.Collections; import java.util.HashMap; -import java.util.Iterator; import java.util.Map; -import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.Marshalled; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.CacheObject; -import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheReturn; -import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.processors.cache.distributed.GridDistributedTxPrepareResponse; import org.apache.ignite.internal.processors.cache.transactions.IgniteTxKey; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.util.tostring.GridToStringInclude; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.S; -import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteUuid; import org.jetbrains.annotations.Nullable; @@ -66,7 +62,8 @@ public class GridNearTxPrepareResponse extends GridDistributedTxPrepareResponse /** Map of owned values to set on near node. */ @GridToStringInclude - private Map ownedVals; + @Marshalled(keys = "ownedValKeys", values = "ownedValVals") + Map ownedVals; /** OwnedVals' keys for marshalling. */ @Order(5) @@ -196,7 +193,7 @@ public void addOwnedValue(IgniteTxKey key, GridCacheVersion ver, CacheObject val if (ownedVals == null) ownedVals = new HashMap<>(); - CacheVersionedValue oVal = new CacheVersionedValue(val, ver); + CacheVersionedValue oVal = new CacheVersionedValue(val, ver, key.cacheId()); ownedVals.put(key, oVal); } @@ -235,97 +232,6 @@ public boolean hasOwnedValue(IgniteTxKey key) { return F.mapContainsKey(ownedVals, key); } - /** {@inheritDoc} */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - - // There are separate collections for keys and values of the 'ownedVals' map, because IgniteTxKey - // can not be inserted directly in a map as a key during invocation of MessageReader#read. - // The IgniteTxKey's hash code calculation will fail due to delegation of calculation - // to KeyCacheObjectImpl#hashCode, which in turn fails with assertion error if KeyCacheObjectImpl#val - // has not initialized yet in KeyCacheObjectImpl#finishUnmarshal. - if (ownedVals != null && ownedValKeys == null) { - ownedValKeys = ownedVals.keySet(); - - ownedValVals = ownedVals.values(); - - for (Map.Entry entry : ownedVals.entrySet()) { - GridCacheContext cacheCtx = ctx.cacheContext(entry.getKey().cacheId()); - - entry.getKey().prepareMarshal(cacheCtx); - - entry.getValue().prepareMarshal(cacheCtx.cacheObjectContext()); - } - } - - if (retVal != null && retVal.cacheId() != 0) { - GridCacheContext cctx = ctx.cacheContext(retVal.cacheId()); - - assert cctx != null : retVal.cacheId(); - - retVal.prepareMarshal(cctx); - } - - if (filterFailedKeys != null) { - for (IgniteTxKey key : filterFailedKeys) { - GridCacheContext cctx = ctx.cacheContext(key.cacheId()); - - key.prepareMarshal(cctx); - } - } - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - // There are separate collections for keys and values of the 'ownedVals' map, because IgniteTxKey - // can not be inserted directly in a map as a key during invocation of MessageReader#read. - // The IgniteTxKey's hash code calculation will fail due to delegation of calculation - // to KeyCacheObjectImpl#hashCode, which in turn fails with assertion error if KeyCacheObjectImpl#val - // has not initialized yet in KeyCacheObjectImpl#finishUnmarshal. - if (ownedValKeys != null && ownedVals == null) { - ownedVals = U.newHashMap(ownedValKeys.size()); - - assert ownedValKeys.size() == ownedValVals.size(); - - Iterator keyIter = ownedValKeys.iterator(); - - Iterator valIter = ownedValVals.iterator(); - - while (keyIter.hasNext()) { - IgniteTxKey key = keyIter.next(); - - GridCacheContext cctx = ctx.cacheContext(key.cacheId()); - - CacheVersionedValue val = valIter.next(); - - key.finishUnmarshal(cctx, ldr); - - val.finishUnmarshal(cctx, ldr); - - ownedVals.put(key, val); - } - } - - if (retVal != null && retVal.cacheId() != 0) { - GridCacheContext cctx = ctx.cacheContext(retVal.cacheId()); - - assert cctx != null : retVal.cacheId(); - - retVal.finishUnmarshal(cctx, ldr); - } - - if (filterFailedKeys != null) { - for (IgniteTxKey key : filterFailedKeys) { - GridCacheContext cctx = ctx.cacheContext(key.cacheId()); - - key.finishUnmarshal(cctx, ldr); - } - } - } - - /** {@inheritDoc} */ @Override public String toString() { return S.toString(GridNearTxPrepareResponse.class, this, "super", super.toString()); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxRemote.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxRemote.java index 936033d8b3838..6023dbd144c27 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxRemote.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxRemote.java @@ -25,6 +25,7 @@ import java.util.UUID; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; +import org.apache.ignite.internal.processors.cache.CacheInvalidStateException; import org.apache.ignite.internal.processors.cache.CacheObject; import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheEntryRemovedException; @@ -126,9 +127,14 @@ public GridNearTxRemote( if (writeEntries != null) { for (IgniteTxEntry entry : writeEntries) { - entry.unmarshal(ctx, true, ldr); + try { + entry.initializeContext(ctx, topVer, true); - addEntry(entry); + addEntry(entry); + } + catch (CacheInvalidStateException e) { + // Cache was destroyed. + } } } @@ -203,9 +209,14 @@ public Collection evicted() { */ public void addEntries(ClassLoader ldr, Iterable entries) throws IgniteCheckedException { for (IgniteTxEntry entry : entries) { - entry.unmarshal(cctx, true, ldr); + try { + entry.initializeContext(cctx, topVer, true); - addEntry(entry); + addEntry(entry); + } + catch (CacheInvalidStateException e) { + // Cache was destroyed. + } } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/IncrementalSnapshotAwareMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/IncrementalSnapshotAwareMessage.java index 5a0824c9a5d41..cfaa9eb031402 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/IncrementalSnapshotAwareMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/IncrementalSnapshotAwareMessage.java @@ -18,10 +18,8 @@ package org.apache.ignite.internal.processors.cache.persistence.snapshot; import java.util.UUID; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.cache.GridCacheMessage; -import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.jetbrains.annotations.Nullable; /** @@ -81,17 +79,6 @@ public long snapshotTopologyVersion() { return topVer; } - /** {@inheritDoc} */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - payload.prepareMarshal(ctx); - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - payload.finishUnmarshal(ctx, ldr); - } - - /** {@inheritDoc} */ @Override public boolean addDeploymentInfo() { return false; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/IncrementalSnapshotVerifyResult.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/IncrementalSnapshotVerifyResult.java index 641e123ffff69..7a1a0e75568db 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/IncrementalSnapshotVerifyResult.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/IncrementalSnapshotVerifyResult.java @@ -64,7 +64,7 @@ public IncrementalSnapshotVerifyResult() { this.txHashRes = txHashRes; this.partHashRes = partHashRes; this.partiallyCommittedTxs = partiallyCommittedTxs; - this.exceptions = exceptions == null ? null : F.viewReadOnly(exceptions, ErrorMessage::new); + this.exceptions = exceptions == null ? null : F.transform(exceptions, ErrorMessage::new); } /** */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryRequest.java index 84813c40420c9..3f21d760df663 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryRequest.java @@ -19,9 +19,10 @@ import java.util.Collection; import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.Marshalled; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; -import org.apache.ignite.internal.processors.cache.CacheObjectContext; +import org.apache.ignite.internal.processors.cache.DeployableMessage; import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheDeployable; import org.apache.ignite.internal.processors.cache.GridCacheIdMessage; @@ -29,7 +30,6 @@ import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.util.tostring.GridToStringInclude; import org.apache.ignite.internal.util.typedef.F; -import org.apache.ignite.internal.util.typedef.internal.CU; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteBiPredicate; @@ -45,7 +45,7 @@ /** * Query request. */ -public class GridCacheQueryRequest extends GridCacheIdMessage implements GridCacheDeployable { +public class GridCacheQueryRequest extends GridCacheIdMessage implements GridCacheDeployable, DeployableMessage { /** */ private static final int FLAG_DATA_PAGE_SCAN_DFLT = 0b00; @@ -76,7 +76,8 @@ public class GridCacheQueryRequest extends GridCacheIdMessage implements GridCac String clause; /** */ - private IndexQueryDesc idxQryDesc; + @Marshalled("idxQryDescBytes") + IndexQueryDesc idxQryDesc; /** */ @Order(4) @@ -91,28 +92,32 @@ public class GridCacheQueryRequest extends GridCacheIdMessage implements GridCac String clsName; /** */ - private IgniteBiPredicate keyValFilter; + @Marshalled("keyValFilterBytes") + IgniteBiPredicate keyValFilter; /** */ @Order(7) byte[] keyValFilterBytes; /** */ - private IgniteReducer rdc; + @Marshalled("rdcBytes") + IgniteReducer rdc; /** */ @Order(8) byte[] rdcBytes; /** */ - private IgniteClosure trans; + @Marshalled("transBytes") + IgniteClosure trans; /** */ @Order(9) byte[] transBytes; /** */ - private Object[] args; + @Marshalled("argsBytes") + Object[] args; /** */ @Order(10) @@ -406,86 +411,6 @@ private static byte setDataPageScanEnabled(int flags, Boolean enabled) { return topVer != null ? topVer : AffinityTopologyVersion.NONE; } - /** {@inheritDoc} */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - - GridCacheContext cctx = ctx.cacheContext(cacheId); - - if (keyValFilter != null && keyValFilterBytes == null) { - if (addDepInfo) - prepareObject(keyValFilter, cctx); - - keyValFilterBytes = CU.marshal(cctx, keyValFilter); - } - - if (rdc != null && rdcBytes == null) { - if (addDepInfo) - prepareObject(rdc, cctx); - - rdcBytes = CU.marshal(cctx, rdc); - } - - if (trans != null && transBytes == null) { - if (addDepInfo) - prepareObject(trans, cctx); - - transBytes = CU.marshal(cctx, trans); - } - - if (!F.isEmpty(args) && argsBytes == null) { - if (addDepInfo) { - for (Object arg : args) - prepareObject(arg, cctx); - } - - argsBytes = CU.marshal(cctx, args); - } - - if (idxQryDesc != null && idxQryDescBytes == null) { - if (addDepInfo) - prepareObject(idxQryDesc, cctx); - - idxQryDescBytes = CU.marshal(cctx, idxQryDesc); - } - - if (!F.isEmpty(skipKeys)) { - for (KeyCacheObject k : skipKeys) - k.prepareMarshal(cctx.cacheObjectContext()); - } - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - Marshaller mrsh = ctx.marshaller(); - - ClassLoader clsLdr = U.resolveClassLoader(ldr, ctx.gridConfig()); - - if (keyValFilterBytes != null && keyValFilter == null) - keyValFilter = U.unmarshal(mrsh, keyValFilterBytes, clsLdr); - - if (rdcBytes != null && rdc == null) - rdc = U.unmarshal(mrsh, rdcBytes, ldr); - - if (transBytes != null && trans == null) - trans = U.unmarshal(mrsh, transBytes, clsLdr); - - if (argsBytes != null && args == null) - args = U.unmarshal(mrsh, argsBytes, clsLdr); - - if (idxQryDescBytes != null && idxQryDesc == null) - idxQryDesc = U.unmarshal(mrsh, idxQryDescBytes, clsLdr); - - if (!F.isEmpty(skipKeys)) { - CacheObjectContext objCtx = ctx.cacheObjectContext(cacheId); - - for (KeyCacheObject k : skipKeys) - k.finishUnmarshal(objCtx, ldr); - } - } - /** {@inheritDoc} */ @Override public boolean addDeploymentInfo() { return addDepInfo; @@ -659,6 +584,37 @@ public Collection skipKeys() { return part; } + /** {@inheritDoc} */ + @Override public void deploy(GridCacheSharedContext ctx) throws IgniteCheckedException { + GridCacheContext cctx = ctx.cacheContext(cacheId); + + if (keyValFilter != null && keyValFilterBytes == null) { + if (addDepInfo) + deployObject(keyValFilter, cctx); + } + + if (rdc != null && rdcBytes == null) { + if (addDepInfo) + deployObject(rdc, cctx); + } + + if (trans != null && transBytes == null) { + if (addDepInfo) + deployObject(trans, cctx); + } + + if (!F.isEmpty(args) && argsBytes == null) { + if (addDepInfo) { + for (Object arg : args) + deployObject(arg, cctx); + } + } + + if (idxQryDesc != null && idxQryDescBytes == null) { + if (addDepInfo) + deployObject(idxQryDesc, cctx); + } + } /** {@inheritDoc} */ @Override public String toString() { diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryResponse.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryResponse.java index 6b295f2561182..902921726f8d6 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryResponse.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryResponse.java @@ -17,30 +17,26 @@ package org.apache.ignite.internal.processors.cache.query; -import java.util.ArrayList; import java.util.Collection; -import java.util.List; import java.util.Map; import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.Marshalled; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.cache.query.index.IndexQueryResultMeta; import org.apache.ignite.internal.managers.communication.ErrorMessage; -import org.apache.ignite.internal.processors.cache.CacheObjectContext; +import org.apache.ignite.internal.processors.cache.DeployableMessage; import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheDeployable; import org.apache.ignite.internal.processors.cache.GridCacheIdMessage; import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; -import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.S; -import org.apache.ignite.internal.util.typedef.internal.U; -import org.apache.ignite.marshaller.Marshaller; import org.jetbrains.annotations.Nullable; /** * Page of cache query response. */ -public class GridCacheQueryResponse extends GridCacheIdMessage implements GridCacheDeployable { +public class GridCacheQueryResponse extends GridCacheIdMessage implements GridCacheDeployable, DeployableMessage { /** */ @Order(0) boolean finished; @@ -66,7 +62,8 @@ public class GridCacheQueryResponse extends GridCacheIdMessage implements GridCa Collection dataBytes; /** */ - private Collection data; + @Marshalled("dataBytes") + Collection data; /** * Empty constructor. @@ -103,79 +100,6 @@ public GridCacheQueryResponse(int cacheId, long reqId, Throwable err, boolean ad finished = true; } - /** {@inheritDoc} - * @param ctx*/ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - - GridCacheContext cctx = ctx.cacheContext(cacheId); - - if (dataBytes == null && data != null) - dataBytes = marshalCollection(data, cctx); - - if (addDepInfo && !F.isEmpty(data)) { - for (Object o : data) { - if (o instanceof Map.Entry) { - Map.Entry e = (Map.Entry)o; - - prepareObject(e.getKey(), cctx); - prepareObject(e.getValue(), cctx); - } - } - } - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - if (data == null) - data = unmarshalCollection0(dataBytes, ctx, ldr); - } - - /** - * @param byteCol Collection to unmarshal. - * @param ctx Context. - * @param ldr Loader. - * @return Unmarshalled collection. - * @throws IgniteCheckedException If failed. - */ - @Nullable protected List unmarshalCollection0(@Nullable Collection byteCol, - GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - assert ldr != null; - assert ctx != null; - - if (byteCol == null) - return null; - - List col = new ArrayList<>(byteCol.size()); - - Marshaller marsh = ctx.marshaller(); - - ClassLoader ldr0 = U.resolveClassLoader(ldr, ctx.gridConfig()); - - CacheObjectContext cacheObjCtx = null; - - for (byte[] bytes : byteCol) { - Object obj = bytes == null ? null : marsh.unmarshal(bytes, ldr0); - - if (obj instanceof Map.Entry) { - Object key = ((Map.Entry)obj).getKey(); - - if (key instanceof KeyCacheObject) { - if (cacheObjCtx == null) - cacheObjCtx = ctx.cacheContext(cacheId).cacheObjectContext(); - - ((KeyCacheObject)key).finishUnmarshal(cacheObjCtx, ldr0); - } - } - - col.add((T)obj); - } - - return col; - } - /** {@inheritDoc} */ @Override public boolean addDeploymentInfo() { return addDepInfo; @@ -233,6 +157,24 @@ public boolean fields() { return fields; } + /** {@inheritDoc} */ + @Override public void deploy(GridCacheSharedContext ctx) throws IgniteCheckedException { + GridCacheContext cctx = ctx.cacheContext(cacheId); + + if (dataBytes == null && data != null) + deployCollection(data, cctx); + + if (addDepInfo && !F.isEmpty(data)) { + for (Object o : data) { + if (o instanceof Map.Entry) { + Map.Entry e = (Map.Entry)o; + + deployObject(e.getKey(), cctx); + deployObject(e.getValue(), cctx); + } + } + } + } /** {@inheritDoc} */ @Override public String toString() { diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryEntry.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryEntry.java index 130dcec622821..526261613353b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryEntry.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryEntry.java @@ -24,19 +24,19 @@ import org.apache.ignite.internal.managers.deployment.GridDeploymentInfo; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.CacheObject; -import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheDeployable; import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.util.tostring.GridToStringExclude; import org.apache.ignite.internal.util.tostring.GridToStringInclude; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.marshaller.Marshaller; +import org.apache.ignite.plugin.extensions.communication.CacheIdAware; import org.jetbrains.annotations.Nullable; /** * Continuous query entry. */ -public class CacheContinuousQueryEntry implements GridCacheDeployable, MarshallableMessage { +public class CacheContinuousQueryEntry implements GridCacheDeployable, MarshallableMessage, CacheIdAware { /** */ private static final byte BACKUP_ENTRY = 0b0001; @@ -58,25 +58,25 @@ public class CacheContinuousQueryEntry implements GridCacheDeployable, Marshalla @GridToStringInclude KeyCacheObject key; - /** */ + /** {@code null} for a filtered entry. */ @Order(2) - byte[] keyBytes; + KeyCacheObject keyWire; /** New value. */ @GridToStringInclude CacheObject newVal; - /** */ + /** {@code null} for a filtered entry. */ @Order(3) - byte[] newValBytes; + CacheObject newValWire; /** Old value. */ @GridToStringInclude CacheObject oldVal; - /** */ + /** {@code null} for a filtered entry. */ @Order(4) - byte[] oldValBytes; + CacheObject oldValWire; /** Cache name. */ @Order(5) @@ -194,10 +194,8 @@ public byte flags() { return topVer; } - /** - * @return Cache ID. - */ - int cacheId() { + /** {@inheritDoc} */ + @Override public int cacheId() { return cacheId; } @@ -295,39 +293,6 @@ boolean isKeepBinary() { return (flags & KEEP_BINARY) != 0; } - /** - * @param cctx Cache context. - * @throws IgniteCheckedException In case of error. - */ - void prepareMarshal(GridCacheContext cctx) throws IgniteCheckedException { - if (key != null) - key.prepareMarshal(cctx.cacheObjectContext()); - - if (newVal != null) - newVal.prepareMarshal(cctx.cacheObjectContext()); - - if (oldVal != null) - oldVal.prepareMarshal(cctx.cacheObjectContext()); - } - - /** - * @param cctx Cache context. - * @param ldr Class loader. - * @throws IgniteCheckedException In case of error. - */ - void unmarshal(GridCacheContext cctx, @Nullable ClassLoader ldr) throws IgniteCheckedException { - if (!isFiltered()) { - if (key != null) - key.finishUnmarshal(cctx.cacheObjectContext(), ldr); - - if (newVal != null) - newVal.finishUnmarshal(cctx.cacheObjectContext(), ldr); - - if (oldVal != null) - oldVal.finishUnmarshal(cctx.cacheObjectContext(), ldr); - } - } - /** * @return Key. */ @@ -350,7 +315,7 @@ CacheObject oldValue() { } /** {@inheritDoc} */ - @Override public void prepare(GridDeploymentInfo depInfo) { + @Override public void deploy(GridDeploymentInfo depInfo) { this.depInfo = depInfo; } @@ -359,35 +324,38 @@ CacheObject oldValue() { return depInfo; } - /** {@inheritDoc} */ - @Override public String toString() { - return S.toString(CacheContinuousQueryEntry.class, this); + @Override public void marshal(Marshaller marsh) throws IgniteCheckedException { + if (!isFiltered()) { + keyWire = key; + newValWire = newVal; + oldValWire = oldVal; + } } /** {@inheritDoc} */ - @Override public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { - if (!isFiltered()) { - if (key != null) - keyBytes = marsh.marshal(key); + @Override public void unmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { + if (keyWire != null) { + key = keyWire; + + keyWire = null; + } + + if (newValWire != null) { + newVal = newValWire; - if (newVal != null) - newValBytes = marsh.marshal(newVal); + newValWire = null; + } + + if (oldValWire != null) { + oldVal = oldValWire; - if (oldVal != null) - oldValBytes = marsh.marshal(oldVal); + oldValWire = null; } } /** {@inheritDoc} */ - @Override public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { - if (keyBytes != null) - key = marsh.unmarshal(keyBytes, clsLdr); - - if (newValBytes != null) - newVal = marsh.unmarshal(newValBytes, clsLdr); - - if (oldValBytes != null) - oldVal = marsh.unmarshal(oldValBytes, clsLdr); + @Override public String toString() { + return S.toString(CacheContinuousQueryEntry.class, this); } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryHandler.java index eca4f12544b83..30668521d71dc 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryHandler.java @@ -53,6 +53,7 @@ import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException; import org.apache.ignite.internal.managers.communication.GridIoPolicy; +import org.apache.ignite.internal.managers.communication.MessageMarshalling; import org.apache.ignite.internal.managers.deployment.GridDeploymentInfo; import org.apache.ignite.internal.managers.deployment.P2PClassLoadingIssues; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; @@ -932,13 +933,8 @@ protected CacheEntryEventFilter getEventFilter0() { */ private void prepareEntry(GridCacheContext cctx, UUID nodeId, CacheContinuousQueryEntry entry) throws IgniteCheckedException { - if (cctx.kernalContext().config().isPeerClassLoadingEnabled() && cctx.discovery().node(nodeId) != null) { - entry.prepareMarshal(cctx); - + if (cctx.kernalContext().config().isPeerClassLoadingEnabled() && cctx.discovery().node(nodeId) != null) cctx.deploy().prepare(entry); - } - else - entry.prepareMarshal(cctx); } /** @@ -1076,7 +1072,7 @@ private void notifyCallback0(UUID nodeId, } } - e.unmarshal(cctx, ldr); + MessageMarshalling.unmarshal(e, ctx, cctx.cacheObjectContext(), ldr); Collection> evts = handleEvent(ctx, e); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryManager.java index 1680b9619a2ef..b711e97cccc41 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/query/continuous/CacheContinuousQueryManager.java @@ -418,11 +418,11 @@ public void onEntryUpdated( oldVal = (CacheObject)cctx.unwrapTemporary(oldVal); if (oldVal != null) - oldVal.finishUnmarshal(cctx.cacheObjectContext(), cctx.deploy().globalLoader()); + oldVal.unmarshal(cctx.cacheObjectContext(), cctx.deploy().globalLoader()); } if (newVal != null) - newVal.finishUnmarshal(cctx.cacheObjectContext(), cctx.deploy().globalLoader()); + newVal.unmarshal(cctx.cacheObjectContext(), cctx.deploy().globalLoader()); initialized = true; } @@ -484,7 +484,7 @@ public void onEntryExpired(GridCacheEntryEx e, KeyCacheObject key, CacheObject o oldVal = (CacheObject)cctx.unwrapTemporary(oldVal); if (oldVal != null) - oldVal.finishUnmarshal(cctx.cacheObjectContext(), cctx.deploy().globalLoader()); + oldVal.unmarshal(cctx.cacheObjectContext(), cctx.deploy().globalLoader()); initialized = true; } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxEntry.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxEntry.java index 3139e9d8db007..a2d36d76d8c73 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxEntry.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxEntry.java @@ -25,13 +25,14 @@ import javax.cache.processor.EntryProcessor; import org.apache.ignite.IgniteCache; import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.MarshallableMessage; +import org.apache.ignite.internal.Marshalled; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.CacheEntryPredicate; import org.apache.ignite.internal.processors.cache.CacheInvalidStateException; import org.apache.ignite.internal.processors.cache.CacheInvokeEntry; import org.apache.ignite.internal.processors.cache.CacheObject; -import org.apache.ignite.internal.processors.cache.CacheObjectValueContext; import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheEntryEx; import org.apache.ignite.internal.processors.cache.GridCacheEntryRemovedException; @@ -47,7 +48,8 @@ import org.apache.ignite.internal.util.typedef.T2; import org.apache.ignite.internal.util.typedef.internal.CU; import org.apache.ignite.internal.util.typedef.internal.U; -import org.apache.ignite.plugin.extensions.communication.Message; +import org.apache.ignite.marshaller.Marshaller; +import org.apache.ignite.plugin.extensions.communication.CacheIdAware; import org.apache.ignite.thread.IgniteThread; import org.jetbrains.annotations.Nullable; @@ -59,7 +61,7 @@ * {@link #equals(Object)} method, as transaction entries should use referential * equality. */ -public class IgniteTxEntry implements GridPeerDeployAware, Message { +public class IgniteTxEntry implements GridPeerDeployAware, MarshallableMessage, CacheIdAware { /** */ private static final long serialVersionUID = 0L; @@ -133,7 +135,8 @@ public class IgniteTxEntry implements GridPeerDeployAware, Message { /** Transform. */ @GridToStringInclude - private Collection, Object[]>> entryProcessorsCol; + @Marshalled("transformClosBytes") + Collection, Object[]>> entryProcessorsCol; /** Transient field for calculated entry processor value. */ private T2 entryProcessorCalcVal; @@ -195,7 +198,7 @@ public class IgniteTxEntry implements GridPeerDeployAware, Message { /** Expiry policy. */ private ExpiryPolicy expiryPlc; - /** Expiry policy transfer flag. */ + /** Sender-side flag: the entry travels with its expiry policy (near prepare requests only). */ private boolean transferExpiryPlc; /** Expiry policy bytes. */ @@ -594,7 +597,7 @@ public KeyCacheObject key() { /** * @return Cache ID. */ - public int cacheId() { + @Override public int cacheId() { return cacheId; } @@ -1041,52 +1044,35 @@ public void filtersSet(boolean filtersSet) { this.filtersSet = filtersSet; } - /** - * @param ctx Context. - * @param transferExpiry {@code True} if expire policy should be marshalled. - * @throws IgniteCheckedException If failed. - */ - public void marshal(GridCacheSharedContext ctx, boolean transferExpiry) throws IgniteCheckedException { - if (filters != null) { - for (CacheEntryPredicate p : filters) { - if (p != null) - p.prepareMarshal(this.ctx); - } - } - - // Do not serialize filters if they are null. - if (transformClosBytes == null && entryProcessorsCol != null) - transformClosBytes = CU.marshal(this.ctx, entryProcessorsCol); - - if (transferExpiry) - transferExpiryPlc = expiryPlc != null && expiryPlc != this.ctx.expiry(); - - key.prepareMarshal(context().cacheObjectContext()); - - val.marshal(context()); + /** {@inheritDoc} */ + @Override public void marshal(Marshaller marsh) throws IgniteCheckedException { + boolean transfer = transferExpiryPlc && expiryPlc != null && expiryPlc != ctx.expiry(); - if (transferExpiryPlc) { + if (transfer) { if (expiryPlcBytes == null) - expiryPlcBytes = CU.marshal(this.ctx, new IgniteExternalizableExpiryPolicy(expiryPlc)); + expiryPlcBytes = U.marshal(marsh, new IgniteExternalizableExpiryPolicy(expiryPlc)); } else expiryPlcBytes = null; + } + + /** {@inheritDoc} */ + @Override public void unmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { + if (filters == null) + filters = CU.empty0(); - if (oldVal != null) - oldVal.marshal(context()); + if (expiryPlcBytes != null && expiryPlc == null) + expiryPlc = U.unmarshal(marsh, expiryPlcBytes, clsLdr); } /** - * Prepares this entry to unmarshall. In particular, this method initialize a cache context. - * * @param ctx Cache context. * @param topVer Topology version that is used to validate a cache context. * If this parameter is {@code null} then validation will be skipped. * @param near Near flag. * @throws IgniteCheckedException If un-marshalling failed. */ - public void prepareUnmarshal( - GridCacheSharedContext ctx, + public void initializeContext(GridCacheSharedContext ctx, AffinityTopologyVersion topVer, boolean near ) throws IgniteCheckedException { @@ -1106,53 +1092,6 @@ else if (!cacheCtx.isNear() && near) } } - /** - * Unmarshalls entry. - * - * @param ctx Cache context. - * @param near Near flag. - * @param clsLdr Class loader. - * @throws IgniteCheckedException If un-marshalling failed. - */ - public void unmarshal( - GridCacheSharedContext ctx, - boolean near, - ClassLoader clsLdr - ) throws IgniteCheckedException { - - if (this.ctx == null) - prepareUnmarshal(ctx, null, near); - - CacheObjectValueContext coctx = this.ctx.cacheObjectContext(); - - if (coctx == null) - throw new CacheInvalidStateException( - "Failed to perform cache operation (cache is stopped), cacheId=" + cacheId); - - // Unmarshal transform closure anyway if it exists. - if (transformClosBytes != null && entryProcessorsCol == null) - entryProcessorsCol = U.unmarshal(ctx, transformClosBytes, U.resolveClassLoader(clsLdr, ctx.gridConfig())); - - if (filters == null) - filters = CU.empty0(); - else { - for (CacheEntryPredicate p : filters) { - if (p != null) - p.finishUnmarshal(this.ctx, clsLdr); - } - } - - key.finishUnmarshal(coctx, clsLdr); - - val.unmarshal(coctx, clsLdr); - - if (expiryPlcBytes != null && expiryPlc == null) - expiryPlc = U.unmarshal(ctx, expiryPlcBytes, U.resolveClassLoader(clsLdr, ctx.gridConfig())); - - if (hasOldValue()) - oldVal.unmarshal(coctx, clsLdr); - } - /** * @param expiryPlc Expiry policy. */ @@ -1167,6 +1106,13 @@ public void expiry(@Nullable ExpiryPolicy expiryPlc) { return expiryPlc; } + /** + * @param transferExpiryPlc {@code True} if this entry travels with its expiry policy. + */ + public void transferExpiryPolicy(boolean transferExpiryPlc) { + this.transferExpiryPlc = transferExpiryPlc; + } + /** * @return Entry processor calculated value. */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxHandler.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxHandler.java index 40dae253a43f6..66a93ac57f20a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxHandler.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxHandler.java @@ -20,6 +20,7 @@ import java.util.ArrayList; import java.util.Collection; import java.util.HashSet; +import java.util.Iterator; import java.util.List; import java.util.Set; import java.util.UUID; @@ -374,14 +375,15 @@ public IgniteInternalFuture prepareColocatedTx( * @return First entry. * @throws IgniteCheckedException If failed. */ - private IgniteTxEntry unmarshal(@Nullable Collection entries) throws IgniteCheckedException { + private IgniteTxEntry initialize(@Nullable Collection entries, AffinityTopologyVersion topVer) + throws IgniteCheckedException { if (entries == null) return null; IgniteTxEntry firstEntry = null; for (IgniteTxEntry e : entries) { - e.unmarshal(ctx, false, ctx.deploy().globalLoader()); + e.initializeContext(ctx, topVer, false); if (firstEntry == null) firstEntry = e; @@ -430,12 +432,24 @@ public IgniteInternalFuture prepareNearTxLocal( IgniteTxEntry firstEntry; try { - IgniteTxEntry firstWrite = unmarshal(req.writes()); - IgniteTxEntry firstRead = unmarshal(req.reads()); + IgniteTxEntry firstWrite = initialize(req.writes(), req.topologyVersion()); + IgniteTxEntry firstRead = initialize(req.reads(), req.topologyVersion()); firstEntry = firstWrite != null ? firstWrite : firstRead; } catch (IgniteCheckedException e) { + // The failed-message response must be sent from here: the entry context binding moved from the + // message-level unmarshal into this handler, so errors like "cache recreated" surface past + // GridCacheIoManager's catch, and the near node would hang without a response (IgniteCacheRecreateTest). + try { + req.onClassError(e); + + ctx.io().processFailedMessage(nearNode.id(), req, null, req.policy()); + } + catch (IgniteCheckedException ex) { + throw new IgniteException(ex); + } + return new GridFinishedFuture<>(e); } @@ -1215,7 +1229,29 @@ private void processDhtTxPrepareRequest(final UUID nodeId, final GridDhtTxPrepar if (nearTx != null) res.nearEvicted(nearTx.evicted()); - List writesCacheMissed = req.nearWritesCacheMissed(); + List writesCacheMissed = new ArrayList<>(); + + Collection writes = req.nearWrites(); + + for (Iterator it = writes.iterator(); it.hasNext();) { + IgniteTxEntry e = it.next(); + + GridCacheContext cacheCtx = ctx.cacheContext(e.cacheId()); + + // A missing cache or one recreated after the request was sent: report the key back as evicted, + // so the near node drops its stale entry. + if (cacheCtx == null + || (req.topologyVersion() != null && req.topologyVersion().before(cacheCtx.startTopologyVersion()))) { + it.remove(); + + writesCacheMissed.add(e.txKey()); + } + else { + e.context(cacheCtx); + + e.initializeContext(ctx, req.topologyVersion(), true); + } + } if (writesCacheMissed != null) { Collection evicted0 = res.nearEvicted(); @@ -1759,6 +1795,8 @@ private void sendReply(UUID nodeId, GridDhtTxFinishRequest req, boolean committe int idx = 0; for (IgniteTxEntry entry : req.writes()) { + entry.initializeContext(ctx, req.topologyVersion(), false); + GridCacheContext cacheCtx = entry.context(); int part = cacheCtx.affinity().partition(entry.key()); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxKey.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxKey.java index b50bc340c3ba1..b428069ae4875 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxKey.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxKey.java @@ -17,19 +17,18 @@ package org.apache.ignite.internal.processors.cache.transactions; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.Order; -import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.util.tostring.GridToStringInclude; import org.apache.ignite.internal.util.typedef.internal.S; +import org.apache.ignite.plugin.extensions.communication.CacheIdAware; import org.apache.ignite.plugin.extensions.communication.Message; /** * Cache transaction key. This wrapper is needed because same keys may be enlisted in the same transaction * for multiple caches. */ -public class IgniteTxKey implements Message { +public class IgniteTxKey implements Message, CacheIdAware { /** Key. */ @Order(0) @GridToStringInclude(sensitive = true) @@ -65,29 +64,10 @@ public KeyCacheObject key() { /** * @return Cache ID. */ - public int cacheId() { + @Override public int cacheId() { return cacheId; } - /** - * @param ctx Context. - * @throws IgniteCheckedException If failed. - */ - public void prepareMarshal(GridCacheContext ctx) throws IgniteCheckedException { - key.prepareMarshal(ctx.cacheObjectContext()); - } - - /** - * @param ctx Context. - * @param ldr Class loader. - * @throws IgniteCheckedException If failed. - */ - public void finishUnmarshal(GridCacheContext ctx, ClassLoader ldr) throws IgniteCheckedException { - assert key != null; - - key.finishUnmarshal(ctx.cacheObjectContext(), ldr); - } - /** {@inheritDoc} */ @Override public boolean equals(Object o) { if (this == o) @@ -110,7 +90,6 @@ public void finishUnmarshal(GridCacheContext ctx, ClassLoader ldr) throws Ignite return res; } - /** {@inheritDoc} */ @Override public String toString() { return S.toString(IgniteTxKey.class, this); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalAdapter.java index bbc6e282fd5f0..67e72fd1fb162 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalAdapter.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxLocalAdapter.java @@ -326,7 +326,7 @@ public void implicitSingleResult(GridCacheReturn ret) { assert ret != null; if (ret.invokeResult()) - implicitRes.mergeEntryProcessResults(ret); + implicitRes.mergeEntryProcessResults(cctx.cacheContext(ret.cacheId()), ret); else implicitRes = ret; } @@ -1229,7 +1229,7 @@ protected final void postLockWrite( } else { // Revert operation to previous. (if no - NOOP, so entry will be unlocked). - txEntry.setAndMarkValid(txEntry.previousOperation(), cacheCtx.toCacheObject(ret.value())); + txEntry.setAndMarkValid(txEntry.previousOperation(), cacheCtx.toCacheObject(ret.value(cacheCtx))); txEntry.filters(CU.empty0()); txEntry.filtersSet(false); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxManager.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxManager.java index 524ea82e3ab80..c06d0c4bde39a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTxManager.java @@ -54,6 +54,7 @@ import org.apache.ignite.internal.cluster.DistributedTransactionConfiguration; import org.apache.ignite.internal.managers.communication.GridIoPolicy; import org.apache.ignite.internal.managers.communication.GridMessageListener; +import org.apache.ignite.internal.managers.communication.MessageMarshalling; import org.apache.ignite.internal.managers.discovery.DiscoCache; import org.apache.ignite.internal.managers.eventstorage.DiscoveryEventListener; import org.apache.ignite.internal.managers.eventstorage.HighPriorityListener; @@ -67,6 +68,7 @@ import org.apache.ignite.internal.processors.cache.GridCacheEntryRemovedException; import org.apache.ignite.internal.processors.cache.GridCacheMapEntry; import org.apache.ignite.internal.processors.cache.GridCacheMessage; +import org.apache.ignite.internal.processors.cache.GridCacheMessageDeployer; import org.apache.ignite.internal.processors.cache.GridCacheMvccCandidate; import org.apache.ignite.internal.processors.cache.GridCacheReturnCompletableWrapper; import org.apache.ignite.internal.processors.cache.GridCacheSharedManagerAdapter; @@ -2430,7 +2432,7 @@ void txLocksInfo(UUID nodeId, TxDeadlockFuture fut, Set txKeys) { try { if (!cctx.localNodeId().equals(nodeId)) - req.prepareMarshal(cctx); + GridCacheMessageDeployer.deploy(cctx.kernalContext().messageFactory(), req, cctx); cctx.gridIO().sendToGridTopic(node, TOPIC_TX, req, SYSTEM_POOL); } @@ -3420,7 +3422,7 @@ private class DeadlockDetectionListener implements GridMessageListener { try { if (!cctx.localNodeId().equals(nodeId)) - res.prepareMarshal(cctx); + GridCacheMessageDeployer.deploy(cctx.kernalContext().messageFactory(), res, cctx); cctx.gridIO().sendToGridTopic(nodeId, TOPIC_TX, res, SYSTEM_POOL); } @@ -3505,7 +3507,7 @@ private void unmarshall(UUID nodeId, GridCacheMessage cacheMsg) { return; try { - cacheMsg.finishUnmarshal(cctx, cctx.deploy().globalLoader()); + MessageMarshalling.unmarshal(cacheMsg, cctx.kernalContext(), null, cctx.deploy().globalLoader()); } catch (IgniteCheckedException e) { cacheMsg.onClassError(e); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TxEntryValueHolder.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TxEntryValueHolder.java index 98e5830cb3b46..425e4d88cdfeb 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TxEntryValueHolder.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TxEntryValueHolder.java @@ -17,11 +17,8 @@ package org.apache.ignite.internal.processors.cache.transactions; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.cache.CacheObject; -import org.apache.ignite.internal.processors.cache.CacheObjectValueContext; -import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheOperation; import org.apache.ignite.internal.util.tostring.GridToStringExclude; import org.apache.ignite.internal.util.tostring.GridToStringInclude; @@ -119,25 +116,6 @@ public boolean hasReadValue() { return hasReadVal; } - /** - * @param ctx Cache context. - * @throws IgniteCheckedException If marshaling failed. - */ - public void marshal(GridCacheContext ctx) throws IgniteCheckedException { - if (hasWriteVal && val != null) - val.prepareMarshal(ctx.cacheObjectContext()); - } - - /** - * @param ctx Cache context. - * @param ldr Class loader. - * @throws IgniteCheckedException If unmarshalling failed. - */ - public void unmarshal(CacheObjectValueContext ctx, ClassLoader ldr) throws IgniteCheckedException { - if (hasWriteVal && val != null) - val.finishUnmarshal(ctx, ldr); - } - /** {@inheritDoc} */ @Override public String toString() { return S.toString(TxEntryValueHolder.class, this); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TxLocksRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TxLocksRequest.java index 4db908333d72b..1f20e21d608fd 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TxLocksRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TxLocksRequest.java @@ -17,17 +17,14 @@ package org.apache.ignite.internal.processors.cache.transactions; -import java.util.Collection; import java.util.Set; -import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.Marshalled; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.cache.GridCacheMessage; -import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.util.tostring.GridToStringExclude; import org.apache.ignite.internal.util.tostring.GridToStringInclude; import org.apache.ignite.internal.util.typedef.internal.A; import org.apache.ignite.internal.util.typedef.internal.S; -import org.apache.ignite.internal.util.typedef.internal.U; /** * Transactions lock list request. @@ -39,7 +36,8 @@ public class TxLocksRequest extends GridCacheMessage { /** Tx keys. */ @GridToStringInclude - private Set txKeys; + @Marshalled("txKeysArr") + Set txKeys; /** Array of txKeys from {@link #txKeys}. Used during marshalling and unmarshalling. */ @GridToStringExclude @@ -71,10 +69,8 @@ public long futureId() { return futId; } - /** - * @return Tx keys. - */ - public Collection txKeys() { + /** */ + public Set txKeys() { return txKeys; } @@ -87,35 +83,4 @@ public Collection txKeys() { @Override public boolean addDeploymentInfo() { return addDepInfo; } - - /** {@inheritDoc} */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - - txKeysArr = new IgniteTxKey[txKeys.size()]; - - int i = 0; - - for (IgniteTxKey key : txKeys) { - key.prepareMarshal(ctx.cacheContext(key.cacheId())); - - txKeysArr[i++] = key; - } - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - super.finishUnmarshal(ctx, ldr); - - txKeys = U.newHashSet(txKeysArr.length); - - for (IgniteTxKey key : txKeysArr) { - key.finishUnmarshal(ctx.cacheContext(key.cacheId()), ldr); - - txKeys.add(key); - } - - txKeysArr = null; - } - } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TxLocksResponse.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TxLocksResponse.java index 8ebbcbddbd031..b022b0d8e7091 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TxLocksResponse.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TxLocksResponse.java @@ -23,14 +23,12 @@ import java.util.List; import java.util.Map; import java.util.Set; -import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.Marshalled; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.processors.cache.GridCacheMessage; -import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.util.tostring.GridToStringExclude; import org.apache.ignite.internal.util.tostring.GridToStringInclude; import org.apache.ignite.internal.util.typedef.internal.S; -import org.apache.ignite.internal.util.typedef.internal.U; /** * Transactions lock list response. @@ -42,11 +40,13 @@ public class TxLocksResponse extends GridCacheMessage { /** Locks for near txKeys of near transactions. */ @GridToStringInclude - private final Map> nearTxKeyLocks = new HashMap<>(); + @Marshalled(keys = "nearTxKeysArr", values = "locksArr") + final Map> nearTxKeyLocks = new HashMap<>(); /** Remote keys involved into transactions. Doesn't include near keys. */ @GridToStringInclude - private Set txKeys; + @Marshalled("txKeysArr") + Set txKeys; /** Array of txKeys from {@link #nearTxKeyLocks}. Used during marshalling and unmarshalling. */ @GridToStringExclude @@ -135,77 +135,4 @@ public void addKey(IgniteTxKey key) { @Override public String toString() { return S.toString(TxLocksResponse.class, this); } - - /** {@inheritDoc} */ - @Override public void prepareMarshal(GridCacheSharedContext ctx) throws IgniteCheckedException { - super.prepareMarshal(ctx); - - if (nearTxKeyLocks != null && !nearTxKeyLocks.isEmpty()) { - int len = nearTxKeyLocks.size(); - - nearTxKeysArr = new IgniteTxKey[len]; - locksArr = (List[])new List[len]; - - int i = 0; - - for (Map.Entry> entry : nearTxKeyLocks.entrySet()) { - IgniteTxKey key = entry.getKey(); - - key.prepareMarshal(ctx.cacheContext(key.cacheId())); - - nearTxKeysArr[i] = key; - locksArr[i] = entry.getValue(); - - i++; - } - } - - if (txKeys != null && !txKeys.isEmpty()) { - txKeysArr = new IgniteTxKey[txKeys.size()]; - - int i = 0; - - for (IgniteTxKey key : txKeys) { - key.prepareMarshal(ctx.cacheContext(key.cacheId())); - - txKeysArr[i++] = key; - } - } - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader ldr) throws IgniteCheckedException { - try { - super.finishUnmarshal(ctx, ldr); - - if (nearTxKeysArr != null) { - for (int i = 0; i < nearTxKeysArr.length; i++) { - IgniteTxKey txKey = nearTxKeysArr[i]; - - txKey.key().finishUnmarshal(ctx.cacheObjectContext(txKey.cacheId()), ldr); - - txLocks().put(txKey, locksArr[i]); - } - - nearTxKeysArr = null; - locksArr = null; - } - - if (txKeysArr != null) { - txKeys = U.newHashSet(txKeysArr.length); - - for (IgniteTxKey txKey : txKeysArr) { - txKey.key().finishUnmarshal(ctx.cacheObjectContext(txKey.cacheId()), ldr); - - txKeys.add(txKey); - } - - txKeysArr = null; - } - } - catch (Exception e) { - throw new IgniteCheckedException(e); - } - } - } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/PartitionHashRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/PartitionHashRecord.java index 06ce5642fe874..49b938754087b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/PartitionHashRecord.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/PartitionHashRecord.java @@ -18,9 +18,8 @@ import java.io.Serializable; import java.util.Objects; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.configuration.BinaryConfiguration; -import org.apache.ignite.internal.MarshallableMessage; +import org.apache.ignite.internal.Marshalled; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.binary.GridBinaryMarshaller; import org.apache.ignite.internal.management.cache.PartitionKey; @@ -28,15 +27,14 @@ import org.apache.ignite.internal.util.tostring.GridToStringExclude; import org.apache.ignite.internal.util.tostring.GridToStringInclude; import org.apache.ignite.internal.util.typedef.internal.S; -import org.apache.ignite.internal.util.typedef.internal.U; -import org.apache.ignite.marshaller.Marshaller; +import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.plugin.extensions.communication.MessageFactory; import org.jetbrains.annotations.Nullable; /** * Record containing partition checksum, primary flag and consistent ID of owner. */ -public class PartitionHashRecord implements MarshallableMessage, Serializable { +public class PartitionHashRecord implements Message, Serializable { /** */ private static final long serialVersionUID = 0L; @@ -54,6 +52,7 @@ public class PartitionHashRecord implements MarshallableMessage, Serializable { /** Consistent id. */ @GridToStringInclude + @Marshalled("consistentIdBytes") Object consistentId; /** Bytes of {@link #consistentId}. */ @@ -73,6 +72,7 @@ public class PartitionHashRecord implements MarshallableMessage, Serializable { /** Update counter's state. */ @GridToStringInclude + @Marshalled("updateCntrBytes") Object updateCntr; /** Bytes of {@link #updateCntr}. */ @@ -248,27 +248,6 @@ public void hasExpiringEntries(boolean hasExpiringEntries) { this.hasExpiringEntries = hasExpiringEntries; } - /** {@inheritDoc} */ - @Override public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { - if (consistentId != null) - consistentIdBytes = U.marshal(marsh, consistentId); - - if (updateCntr != null) - updateCntrBytes = U.marshal(marsh, updateCntr); - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { - if (consistentIdBytes != null) - consistentId = U.unmarshal(marsh, consistentIdBytes, clsLdr); - - if (updateCntrBytes != null) - updateCntr = U.unmarshal(marsh, updateCntrBytes, clsLdr); - - consistentId = null; - updateCntrBytes = null; - } - /** {@inheritDoc} */ @Override public String toString() { return size == MOVING_PARTITION_SIZE ? diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/TransactionsHashRecord.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/TransactionsHashRecord.java index 38bd085377824..1aa7a72c2e1ec 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/TransactionsHashRecord.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/verify/TransactionsHashRecord.java @@ -18,21 +18,20 @@ package org.apache.ignite.internal.processors.cache.verify; import java.io.Serializable; -import org.apache.ignite.IgniteCheckedException; -import org.apache.ignite.internal.MarshallableMessage; +import org.apache.ignite.internal.Marshalled; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.util.tostring.GridToStringInclude; import org.apache.ignite.internal.util.typedef.internal.S; -import org.apache.ignite.internal.util.typedef.internal.U; -import org.apache.ignite.marshaller.Marshaller; +import org.apache.ignite.plugin.extensions.communication.Message; /** Represents committed transactions hash for a pair of nodes. */ -public class TransactionsHashRecord implements MarshallableMessage, Serializable { +public class TransactionsHashRecord implements Message, Serializable { /** */ private static final long serialVersionUID = 0L; /** Consistent ID of local node that participated in the transaction. This node produces this record. */ @GridToStringInclude + @Marshalled("locConsistentIdBytes") Object locConsistentId; /** Bytes of {@link #locConsistentId}. */ @@ -41,6 +40,7 @@ public class TransactionsHashRecord implements MarshallableMessage, Serializable /** Consistent ID of remote node that participated in the transactions. */ @GridToStringInclude + @Marshalled("rmtConsistentIdBytes") Object rmtConsistentId; /** Bytes of {@link #rmtConsistentId}. */ @@ -64,18 +64,6 @@ public TransactionsHashRecord(Object locConsistentId, Object rmtConsistentId, in this.txHash = txHash; } - /** {@inheritDoc} */ - @Override public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { - locConsistentIdBytes = U.marshal(marsh, locConsistentId); - rmtConsistentIdBytes = U.marshal(marsh, rmtConsistentId); - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { - locConsistentId = U.unmarshal(marsh, locConsistentIdBytes, clsLdr); - rmtConsistentId = U.unmarshal(marsh, rmtConsistentIdBytes, clsLdr); - } - /** @return Committed transactions IDs hash. */ public int transactionHash() { return txHash; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/ChangeGlobalStateMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/ChangeGlobalStateMessage.java index 461d36f8bdb17..2262b2ba90cf8 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/ChangeGlobalStateMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cluster/ChangeGlobalStateMessage.java @@ -19,9 +19,8 @@ import java.util.List; import java.util.UUID; -import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.cluster.ClusterState; -import org.apache.ignite.internal.MarshallableMessage; +import org.apache.ignite.internal.Marshalled; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.managers.discovery.DiscoCache; import org.apache.ignite.internal.managers.discovery.DiscoveryCustomMessage; @@ -32,15 +31,13 @@ import org.apache.ignite.internal.processors.service.ServiceDeploymentActions; import org.apache.ignite.internal.util.tostring.GridToStringExclude; import org.apache.ignite.internal.util.typedef.internal.S; -import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteUuid; -import org.apache.ignite.marshaller.Marshaller; import org.jetbrains.annotations.Nullable; /** * Message represent request for change cluster global state. */ -public class ChangeGlobalStateMessage extends DiscoveryCustomMessage implements MarshallableMessage { +public class ChangeGlobalStateMessage extends DiscoveryCustomMessage { /** Request ID */ @Order(0) UUID reqId; @@ -58,7 +55,8 @@ public class ChangeGlobalStateMessage extends DiscoveryCustomMessage implements List storedCfgs; /** */ - @Nullable private BaselineTopology baselineTopology; + @Nullable @Marshalled("baselineTopologyBytes") + BaselineTopology baselineTopology; /** JDK Serialized version of baselineTopology. */ @Order(4) @@ -221,18 +219,6 @@ public UUID requestId() { return reqId; } - /** {@inheritDoc} */ - @Override public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { - if (baselineTopology != null) - baselineTopologyBytes = U.marshal(marsh, baselineTopology); - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { - if (baselineTopologyBytes != null) - baselineTopology = U.unmarshal(marsh, baselineTopologyBytes, clsLdr); - } - /** {@inheritDoc} */ @Override public String toString() { return S.toString(ChangeGlobalStateMessage.class, this); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/GridContinuousMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/GridContinuousMessage.java index 68ac58db08abe..8f30653a08b26 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/GridContinuousMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/GridContinuousMessage.java @@ -19,6 +19,7 @@ import java.util.Collection; import java.util.UUID; +import org.apache.ignite.internal.DeferredUnmarshalMessage; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.util.tostring.GridToStringInclude; import org.apache.ignite.internal.util.typedef.internal.S; @@ -31,7 +32,7 @@ /** * Continuous processor message. */ -public class GridContinuousMessage implements Message { +public class GridContinuousMessage implements DeferredUnmarshalMessage { /** Message type. */ @Order(0) GridContinuousMessageType type; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/GridContinuousProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/GridContinuousProcessor.java index 7291e631c2f31..efc65d8d35431 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/GridContinuousProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/GridContinuousProcessor.java @@ -975,7 +975,7 @@ private AbstractContinuousMessage createStartMessage(UUID routineId, reqData.deploymentInfo(dep); } - reqData.prepareMarshal(ctx); + reqData.marshal(ctx); if (!immutableDiscoCustomMsg) { StartRoutineDiscoveryMessage msg = new StartRoutineDiscoveryMessage(routineId, reqData, Mode.MUTABLE); @@ -1342,7 +1342,7 @@ private void processStartRequestMutable(ClusterNode node, StartRoutineDiscoveryM IgniteCheckedException err = null; try { - data.finishUnmarshal(ctx, node.id()); + data.unmarshal(ctx, node.id()); } catch (IgniteCheckedException e) { U.error(log, "Failed to unmarshal start request data [nodeId=" + node.id() + @@ -1484,7 +1484,7 @@ private void processStartRequestImmutable(final AffinityTopologyVersion topVer, Exception err = null; try { - reqData.finishUnmarshal(ctx, snd.id()); + reqData.unmarshal(ctx, snd.id()); } catch (IgniteCheckedException e) { err = e; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/StartRequestData.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/StartRequestData.java index 99c39201500af..9571c231bbf9a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/StartRequestData.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/continuous/StartRequestData.java @@ -171,7 +171,7 @@ public void autoUnsubscribe(boolean autoUnsubscribe) { } /** */ - public void prepareMarshal(GridKernalContext ctx) throws IgniteCheckedException { + public void marshal(GridKernalContext ctx) throws IgniteCheckedException { if (hnd != null) { if (ctx.config().isPeerClassLoadingEnabled()) { // Handle peer deployment for other handler-specific objects. @@ -186,7 +186,7 @@ public void prepareMarshal(GridKernalContext ctx) throws IgniteCheckedException } /** */ - public void finishUnmarshal(GridKernalContext ctx, UUID sndId) throws IgniteCheckedException { + public void unmarshal(GridKernalContext ctx, UUID sndId) throws IgniteCheckedException { if (ctx.config().isPeerClassLoadingEnabled() && clsName != null) { GridDeployment dep = ctx.deploy().getGlobalDeployment(depInfo.deployMode(), clsName, diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/datastreamer/DataStreamProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/datastreamer/DataStreamProcessor.java index 464a74d82ee25..371b0487d65cb 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/datastreamer/DataStreamProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/datastreamer/DataStreamProcessor.java @@ -27,6 +27,7 @@ import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException; import org.apache.ignite.internal.managers.communication.GridIoManager; import org.apache.ignite.internal.managers.communication.GridMessageListener; +import org.apache.ignite.internal.managers.communication.MessageMarshalling; import org.apache.ignite.internal.managers.deployment.GridDeployment; import org.apache.ignite.internal.processors.GridProcessorAdapter; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; @@ -207,6 +208,19 @@ private void processRequest(final UUID nodeId, final DataStreamerRequest req) { } } + // The generic receive pass skips this request (entries must stay serialized for the update job and its + // peer-deployment loader), so the response topic is restored here; it carries only internal classes. + try { + if (req.resTopicMsg != null) + MessageMarshalling.unmarshal(req.resTopicMsg, ctx); + } + catch (IgniteCheckedException e) { + U.error(log, "Failed to unmarshal response topic (no response will be sent) [nodeId=" + nodeId + + ", req=" + req + ']', e); + + return; + } + Object topic = req.responseTopic(); ClassLoader clsLdr; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/datastreamer/DataStreamerImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/datastreamer/DataStreamerImpl.java index 1b795b2faf84a..9a030b8e3354f 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/datastreamer/DataStreamerImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/datastreamer/DataStreamerImpl.java @@ -1931,12 +1931,12 @@ private void submit( else { try { for (DataStreamerEntry e : entries) { - e.getKey().prepareMarshal(cacheObjCtx); + e.getKey().marshal(cacheObjCtx); CacheObject val = e.getValue(); if (val != null) - val.prepareMarshal(cacheObjCtx); + val.marshal(cacheObjCtx); } if (updaterBytes == null) { @@ -2253,7 +2253,7 @@ protected static class IsolatedUpdater implements StreamReceiver { final GridCacheContext cctx = cache.context(); for (DataStreamerEntry e : col) { - e.getKey().finishUnmarshal(cctx.cacheObjectContext(), cctx.deploy().globalLoader()); + e.getKey().unmarshal(cctx.cacheObjectContext(), cctx.deploy().globalLoader()); CacheObject val = e.getValue(); if (val != null) { checkSecurityPermission(SecurityPermission.CACHE_PUT); - val.finishUnmarshal(cctx.cacheObjectContext(), cctx.deploy().globalLoader()); + val.unmarshal(cctx.cacheObjectContext(), cctx.deploy().globalLoader()); } else checkSecurityPermission(SecurityPermission.CACHE_REMOVE); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/job/GridJobProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/job/GridJobProcessor.java index 3e584ed0e4842..ec0096383bf2b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/job/GridJobProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/job/GridJobProcessor.java @@ -1250,7 +1250,7 @@ public void processJobExecuteRequest(ClusterNode node, final GridJobExecuteReque try { if (!loc) - req.finishUnmarshal(marsh, U.resolveClassLoader(dep.classLoader(), ctx.config())); + req.unmarshal(marsh, U.resolveClassLoader(dep.classLoader(), ctx.config())); // Note that we unmarshal session/job attributes here with proper class loader. GridTaskSessionImpl taskSes = ctx.session().createTaskSession( diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/metastorage/persistence/DistributedMetaStorageCasMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/metastorage/persistence/DistributedMetaStorageCasMessage.java index d40661bbadcad..95f3717fb5b63 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/metastorage/persistence/DistributedMetaStorageCasMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/metastorage/persistence/DistributedMetaStorageCasMessage.java @@ -75,16 +75,16 @@ public boolean matches() { } /** {@inheritDoc} */ - @Override public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { - super.prepareMarshal(marsh); + @Override public void marshal(Marshaller marsh) throws IgniteCheckedException { + super.marshal(marsh); if (expVal != null && expValBytes == null) expValBytes = U.marshal(marsh, expVal); } /** {@inheritDoc} */ - @Override public void finishUnmarshal(Marshaller marsh) throws IgniteCheckedException { - super.finishUnmarshal(marsh); + @Override public void unmarshal(Marshaller marsh) throws IgniteCheckedException { + super.unmarshal(marsh); if (expValBytes != null && expVal == null) expVal = U.unmarshal(marsh, expValBytes, U.gridClassLoader()); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/metastorage/persistence/DistributedMetaStorageImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/metastorage/persistence/DistributedMetaStorageImpl.java index ad9022f2e9747..990a26d9b2386 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/metastorage/persistence/DistributedMetaStorageImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/metastorage/persistence/DistributedMetaStorageImpl.java @@ -1018,7 +1018,7 @@ private GridFutureAdapter startWrite(String key, @Nullable Serializable val) DistributedMetaStorageUpdateMessage msg = new DistributedMetaStorageUpdateMessage(reqId, key, val); - msg.prepareMarshal(marshaller); + msg.marshal(marshaller); ctx.discovery().sendCustomEvent(msg); @@ -1039,7 +1039,7 @@ private GridFutureAdapter startCas(String key, @Nullable Serializable e DistributedMetaStorageCasMessage msg = new DistributedMetaStorageCasMessage(reqId, key, expVal, newVal); - msg.prepareMarshal(marshaller); + msg.marshal(marshaller); ctx.discovery().sendCustomEvent(msg); @@ -1281,7 +1281,7 @@ private void completeCas( Serializable oldVal = bridge.read(msg.key()); - msg.finishUnmarshal(marshaller); + msg.unmarshal(marshaller); if (!Objects.deepEquals(oldVal, msg.expectedValue())) { msg.setMatches(false); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/metastorage/persistence/DistributedMetaStorageUpdateMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/metastorage/persistence/DistributedMetaStorageUpdateMessage.java index b836fec1032d6..07e645795c6e7 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/metastorage/persistence/DistributedMetaStorageUpdateMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/metastorage/persistence/DistributedMetaStorageUpdateMessage.java @@ -84,13 +84,13 @@ public byte[] valueBytes() { } /** @param marsh Marshaller. */ - public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { + public void marshal(Marshaller marsh) throws IgniteCheckedException { if (val != null && valBytes == null) valBytes = U.marshal(marsh, val); } /** @param marsh Marshaller. */ - public void finishUnmarshal(Marshaller marsh) throws IgniteCheckedException { + public void unmarshal(Marshaller marsh) throws IgniteCheckedException { // No-op. } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/plugin/PluginsDataBagItem.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/plugin/PluginsDataBagItem.java index 9b70e42223788..64860f731f0d2 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/plugin/PluginsDataBagItem.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/plugin/PluginsDataBagItem.java @@ -19,17 +19,15 @@ import java.io.Serializable; import java.util.Map; -import org.apache.ignite.IgniteCheckedException; -import org.apache.ignite.internal.MarshallableMessage; +import org.apache.ignite.internal.Marshalled; import org.apache.ignite.internal.Order; -import org.apache.ignite.internal.util.typedef.F; -import org.apache.ignite.internal.util.typedef.internal.U; -import org.apache.ignite.marshaller.Marshaller; +import org.apache.ignite.plugin.extensions.communication.Message; import org.jetbrains.annotations.Nullable; /** */ -public class PluginsDataBagItem implements MarshallableMessage { +public class PluginsDataBagItem implements Message { /** Original plugins data. */ + @Marshalled("dataBytes") @Nullable Map data; /** Serialized plugins data. */ @@ -44,18 +42,6 @@ public PluginsDataBagItem(@Nullable Map data) { this.data = data; } - /** {@inheritDoc} */ - @Override public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { - if (!F.isEmpty(data)) - dataBytes = U.marshal(marsh, data); - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { - if (dataBytes != null) - data = U.unmarshal(marsh, dataBytes, clsLdr); - } - /** @return Original plugins data. */ public @Nullable Map data() { return data; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/message/QueryEntityMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/message/QueryEntityMessage.java index 8c6daf46cfd54..e66f2a17df502 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/message/QueryEntityMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/query/schema/message/QueryEntityMessage.java @@ -145,14 +145,17 @@ protected QueryEntity entityBase() { } /** {@inheritDoc} */ - @Override public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { - if (!F.isEmpty(dfltFieldValues)) + @Override public void marshal(Marshaller marsh) throws IgniteCheckedException { + if (!F.isEmpty(dfltFieldValues) && dfltFieldValuesBytes == null) dfltFieldValuesBytes = U.marshal(marsh, dfltFieldValues); } /** {@inheritDoc} */ - @Override public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { - if (!F.isEmpty(dfltFieldValuesBytes)) + @Override public void unmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { + if (!F.isEmpty(dfltFieldValuesBytes)) { dfltFieldValues = U.unmarshal(marsh, dfltFieldValuesBytes, clsLdr); + + dfltFieldValuesBytes = null; + } } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/task/GridTaskResultResponse.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/task/GridTaskResultResponse.java index ff0f3af4ffce8..32b6ef00ba5ff 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/task/GridTaskResultResponse.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/rest/handlers/task/GridTaskResultResponse.java @@ -17,18 +17,17 @@ package org.apache.ignite.internal.processors.rest.handlers.task; -import org.apache.ignite.IgniteCheckedException; -import org.apache.ignite.internal.MarshallableMessage; +import org.apache.ignite.internal.Marshalled; import org.apache.ignite.internal.Order; -import org.apache.ignite.internal.util.typedef.internal.U; -import org.apache.ignite.marshaller.Marshaller; +import org.apache.ignite.plugin.extensions.communication.Message; import org.jetbrains.annotations.Nullable; /** * Task result response. */ -public class GridTaskResultResponse implements MarshallableMessage { +public class GridTaskResultResponse implements Message { /** Result. */ + @Marshalled("resBytes") public @Nullable Object res; /** Serialized result. */ @@ -96,19 +95,4 @@ public void error(String err) { this.err = err; } - /** {@inheritDoc} */ - @Override public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { - if (res != null) - resBytes = U.marshal(marsh, res); - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { - if (resBytes != null) { - res = U.unmarshal(marsh, resBytes, clsLdr); - - // It is not required anymore. - resBytes = null; - } - } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/LazyServiceConfigurationMessage.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/LazyServiceConfigurationMessage.java index 1d003f0bc00a8..7c2fddac97143 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/LazyServiceConfigurationMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/LazyServiceConfigurationMessage.java @@ -123,13 +123,13 @@ public LazyServiceConfiguration toConfiguration() { } /** {@inheritDoc} */ - @Override public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { - if (affKey != null) + @Override public void marshal(Marshaller marsh) throws IgniteCheckedException { + if (affKey != null && affKeyBytes == null) affKeyBytes = U.marshal(marsh, affKey); } /** {@inheritDoc} */ - @Override public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { + @Override public void unmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { if (!F.isEmpty(affKeyBytes)) { affKey = U.unmarshal(marsh, affKeyBytes, clsLdr); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceSingleNodeDeploymentResult.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceSingleNodeDeploymentResult.java index 10ceefb8284aa..f2b55d3e22300 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceSingleNodeDeploymentResult.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/service/ServiceSingleNodeDeploymentResult.java @@ -77,7 +77,7 @@ public Collection errors() { */ public void errors(@Nullable Collection errors) { if (!F.isEmpty(errors)) - this.errors = F.viewReadOnly(errors, ErrorMessage::new); + this.errors = F.transform(errors, ErrorMessage::new); } /** {@inheritDoc} */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/task/GridTaskWorker.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/task/GridTaskWorker.java index d21de03723432..fe419cefaf637 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/task/GridTaskWorker.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/task/GridTaskWorker.java @@ -1416,7 +1416,7 @@ private void sendRequest(ComputeJobResult res) { if (loc) ctx.job().processJobExecuteRequest(ctx.discovery().localNode(), req); else { - req.prepareMarshal(marsh); + req.marshal(marsh); byte plc; diff --git a/modules/core/src/main/java/org/apache/ignite/plugin/extensions/communication/CacheIdAware.java b/modules/core/src/main/java/org/apache/ignite/plugin/extensions/communication/CacheIdAware.java new file mode 100644 index 0000000000000..599c1f108298a --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/plugin/extensions/communication/CacheIdAware.java @@ -0,0 +1,30 @@ +/* + * 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.plugin.extensions.communication; + +/** + * Implemented by messages that carry cache data ({@code CacheObject}) to transfer. The cache ID lets the generated + * marshaller and deployer resolve the cache object context used to (un)marshal and deploy that data. + * + * @see MessageMarshaller + * @see MessageFactory + */ +public interface CacheIdAware { + /** @return ID of the cache whose data the message transfers. */ + public int cacheId(); +} diff --git a/modules/core/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageFactoryProvider.java b/modules/core/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageFactoryProvider.java index df25d13a17bd6..2300bf5fbe334 100644 --- a/modules/core/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageFactoryProvider.java +++ b/modules/core/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageFactoryProvider.java @@ -18,6 +18,7 @@ package org.apache.ignite.plugin.extensions.communication; import org.apache.ignite.internal.CoreMessagesProvider; +import org.apache.ignite.internal.managers.communication.IgniteMessageFactory; import org.apache.ignite.plugin.Extension; /** @@ -34,5 +35,5 @@ public interface MessageFactoryProvider extends Extension { * * @param factory {@link CoreMessagesProvider} implementation. */ - public void registerAll(MessageFactory factory); + public void registerAll(IgniteMessageFactory factory); } diff --git a/modules/core/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageFormatter.java b/modules/core/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageFormatter.java index 80f41b7910c58..e4759db9f4259 100644 --- a/modules/core/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageFormatter.java +++ b/modules/core/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageFormatter.java @@ -38,7 +38,7 @@ public interface MessageFormatter extends Extension { * @return Message writer. * @throws IgniteCheckedException In case of error. */ - public MessageWriter writer(MessageFactory msgFactory) throws IgniteCheckedException; + public MessageWriter writer(MessageFactory msgFactory) throws IgniteCheckedException; /** * Creates new message reader instance. @@ -47,5 +47,5 @@ public interface MessageFormatter extends Extension { * @return Message reader. * @throws IgniteCheckedException In case of error. */ - public MessageReader reader(MessageFactory msgFactory) throws IgniteCheckedException; + public MessageReader reader(MessageFactory msgFactory) throws IgniteCheckedException; } diff --git a/modules/core/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageMarshaller.java b/modules/core/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageMarshaller.java new file mode 100644 index 0000000000000..4426ffefc6219 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageMarshaller.java @@ -0,0 +1,75 @@ +/* + * 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.plugin.extensions.communication; + +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.processors.cache.CacheObjectContext; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.jetbrains.annotations.Nullable; + +/** + * Handles {@code marshal}/{@code unmarshal} for a {@link Message} that requires custom serialization. Resolve-and-dispatch + * entry points that look the marshaller up from the message factory live in {@code MessageMarshalling}. + * + * @param Message type. + */ +public interface MessageMarshaller { + /** + * Marshals the message on the user thread before sending. + * + * @param msg Message to marshal. + * @param kctx Kernal context. + * @param cacheObjCtx Cache object context of the enclosing message, or {@code null} at the top level. + */ + public void marshal(M msg, GridKernalContext kctx, @Nullable CacheObjectContext cacheObjCtx) + throws IgniteCheckedException; + + /** + * Unmarshals the message with full cache context and class loader. + * + * @param msg Message to unmarshal. + * @param kctx Kernal context. + * @param cacheObjCtx Cache object context of the enclosing message, or {@code null} at the top level. + * @param clsLdr Class loader for unmarshalling. + */ + public void unmarshal(M msg, GridKernalContext kctx, @Nullable CacheObjectContext cacheObjCtx, ClassLoader clsLdr) + throws IgniteCheckedException; + + /** + * Unmarshals the message without a cache context, using the configuration class loader — the cache-free receive + * path (e.g. the generic {@code GridIoManager} pass). Delegates to the cache-aware overload with a {@code null} + * context, so per-message marshallers need only implement the cache-aware method. + * + * @param msg Message to unmarshal. + * @param kctx Kernal context. + */ + default void unmarshal(M msg, GridKernalContext kctx) throws IgniteCheckedException { + unmarshal(msg, kctx, null, U.resolveClassLoader(kctx.config())); + } + + /** + * Unmarshals only the {@code @NioField} fields (routing headers) on the NIO thread — unlike the {@code unmarshal} + * overloads, which restore the full payload later on a worker thread. No-op unless the message has {@code @NioField}s. + * + * @param msg Message to unmarshal. + * @param kctx Kernal context. + */ + default void unmarshalNio(M msg, GridKernalContext kctx) throws IgniteCheckedException { + } +} diff --git a/modules/core/src/main/java/org/apache/ignite/plugin/extensions/communication/NonMarshallableMessage.java b/modules/core/src/main/java/org/apache/ignite/plugin/extensions/communication/NonMarshallableMessage.java new file mode 100644 index 0000000000000..8be7c31bd8211 --- /dev/null +++ b/modules/core/src/main/java/org/apache/ignite/plugin/extensions/communication/NonMarshallableMessage.java @@ -0,0 +1,22 @@ +/* + * 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.plugin.extensions.communication; + +/** Marker interface: no {@link MessageMarshaller} is generated for implementing classes. */ +public interface NonMarshallableMessage extends Message { +} diff --git a/modules/core/src/main/java/org/apache/ignite/spi/IgniteSpiAdapter.java b/modules/core/src/main/java/org/apache/ignite/spi/IgniteSpiAdapter.java index bbf821e17d799..49ba98811b51c 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/IgniteSpiAdapter.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/IgniteSpiAdapter.java @@ -39,7 +39,10 @@ import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.IgniteNodeAttributes; import org.apache.ignite.internal.managers.communication.GridMessageListener; +import org.apache.ignite.internal.managers.communication.IgniteMessageFactory; import org.apache.ignite.internal.managers.eventstorage.GridLocalEventListener; +import org.apache.ignite.internal.processors.cache.GridCacheMessage; +import org.apache.ignite.internal.processors.cache.GridCacheMessageDeployer; import org.apache.ignite.internal.processors.timeout.GridSpiTimeoutObject; import org.apache.ignite.internal.util.IgniteExceptionRegistry; import org.apache.ignite.internal.util.typedef.internal.SB; @@ -49,6 +52,7 @@ import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.plugin.extensions.communication.MessageFactory; import org.apache.ignite.plugin.extensions.communication.MessageFormatter; +import org.apache.ignite.plugin.extensions.communication.MessageMarshaller; import org.apache.ignite.plugin.extensions.communication.MessageReader; import org.apache.ignite.plugin.extensions.communication.MessageSerializer; import org.apache.ignite.plugin.extensions.communication.MessageWriter; @@ -750,25 +754,34 @@ private class GridDummySpiContext implements IgniteSpiContext { this.locNode = locNode; this.stopping = stopping; - MessageFactory msgFactory0 = spiCtx != null ? spiCtx.messageFactory() : null; + MessageFactory msgFactory0 = spiCtx != null ? spiCtx.messageFactory() : null; MessageFormatter msgFormatter0 = spiCtx != null ? spiCtx.messageFormatter() : null; if (msgFactory0 == null) { - msgFactory0 = new MessageFactory() { - @Override public void register(short directType, Supplier supplier) throws IgniteException { + msgFactory0 = new IgniteMessageFactory<>() { + @Override public void register( + short directType, + Supplier supplier, + MessageSerializer serializer, + @Nullable MessageMarshaller marshaller, + @Nullable GridCacheMessageDeployer deployer + ) throws IgniteException { throw new IgniteException("Failed to register message, node is not started."); } - @Override public void register(short directType, Supplier supplier, - MessageSerializer serializer) throws IgniteException { + @Nullable @Override public Message create(short type) { + throw new IgniteException("Failed to read message, node is not started."); + } + + @Override public MessageSerializer serializer(short type) { throw new IgniteException("Failed to register message, node is not started."); } - @Nullable @Override public Message create(short type) { - throw new IgniteException("Failed to read message, node is not started."); + @Nullable @Override public MessageMarshaller marshaller(short type) { + throw new IgniteException("Failed to register message, node is not started."); } - @Override public MessageSerializer serializer(short type) { + @Nullable @Override public GridCacheMessageDeployer deployer(short type) { throw new IgniteException("Failed to register message, node is not started."); } }; @@ -776,11 +789,11 @@ private class GridDummySpiContext implements IgniteSpiContext { if (msgFormatter0 == null) { msgFormatter0 = new MessageFormatter() { - @Override public MessageWriter writer(MessageFactory msgFactory) { + @Override public MessageWriter writer(MessageFactory msgFactory) { throw new IgniteException("Failed to write message, node is not started."); } - @Override public MessageReader reader(MessageFactory msgFactory) { + @Override public MessageReader reader(MessageFactory msgFactory) { throw new IgniteException("Failed to read message, node is not started."); } }; diff --git a/modules/core/src/main/java/org/apache/ignite/spi/communication/tcp/internal/GridNioServerWrapper.java b/modules/core/src/main/java/org/apache/ignite/spi/communication/tcp/internal/GridNioServerWrapper.java index eb90f002a240f..76f176bcab3c0 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/communication/tcp/internal/GridNioServerWrapper.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/communication/tcp/internal/GridNioServerWrapper.java @@ -54,7 +54,10 @@ import org.apache.ignite.internal.cluster.ClusterTopologyCheckedException; import org.apache.ignite.internal.direct.DirectMessageWriter; import org.apache.ignite.internal.managers.GridManager; +import org.apache.ignite.internal.managers.communication.IgniteMessageFactory; import org.apache.ignite.internal.managers.tracing.GridTracingManager; +import org.apache.ignite.internal.processors.cache.GridCacheMessage; +import org.apache.ignite.internal.processors.cache.GridCacheMessageDeployer; import org.apache.ignite.internal.processors.metric.GridMetricManager; import org.apache.ignite.internal.processors.metric.MetricRegistryImpl; import org.apache.ignite.internal.processors.tracing.Tracing; @@ -88,6 +91,7 @@ import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.plugin.extensions.communication.MessageFactory; import org.apache.ignite.plugin.extensions.communication.MessageFormatter; +import org.apache.ignite.plugin.extensions.communication.MessageMarshaller; import org.apache.ignite.plugin.extensions.communication.MessageReader; import org.apache.ignite.plugin.extensions.communication.MessageSerializer; import org.apache.ignite.plugin.extensions.communication.MessageWriter; @@ -223,7 +227,7 @@ public class GridNioServerWrapper { private volatile boolean stopping = false; /** Channel connection index provider. */ - private ConnectionPolicy chConnPlc; + private final ConnectionPolicy chConnPlc; /** Scheduled executor service which closed the socket if handshake timeout is out. **/ private final ScheduledExecutorService handshakeTimeoutExecutorService; @@ -812,12 +816,17 @@ public GridNioServer resetNioServer() throws IgniteCheckedException { for (int port = cfg.localPort(); port <= lastPort; port++) { try { - MessageFactory msgFactory = new MessageFactory() { - private MessageFactory impl; - - @Override public void register(short directType, Supplier supplier, - MessageSerializer serializer) throws IgniteException { - get().register(directType, supplier, serializer); + MessageFactory msgFactory = new IgniteMessageFactory<>() { + private IgniteMessageFactory impl; + + @Override public void register( + short directType, + Supplier supplier, + MessageSerializer serializer, + @Nullable MessageMarshaller marshaller, + @Nullable GridCacheMessageDeployer deployer + ) throws IgniteException { + get().register(directType, supplier, serializer, marshaller, deployer); } @Nullable @Override public Message create(short type) { @@ -832,9 +841,17 @@ public GridNioServer resetNioServer() throws IgniteCheckedException { return get().serializer(type); } - private MessageFactory get() { + @Nullable @Override public MessageMarshaller marshaller(short type) { + return get().marshaller(type); + } + + @Nullable @Override public GridCacheMessageDeployer deployer(short type) { + return get().deployer(type); + } + + private IgniteMessageFactory get() { if (impl == null) { - impl = stateProvider.getSpiContext().messageFactory(); + impl = (IgniteMessageFactory)stateProvider.getSpiContext().messageFactory(); assert impl != null; } @@ -844,18 +861,18 @@ private MessageFactory get() { }; GridNioMessageReaderFactory readerFactory = new GridNioMessageReaderFactory() { - private IgniteSpiContext context; + private IgniteSpiContext spiCtx; private MessageFormatter formatter; - @Override public MessageReader reader(GridNioSession ses, MessageFactory msgFactory) + @Override public MessageReader reader(GridNioSession ses, MessageFactory msgFactory) throws IgniteCheckedException { final IgniteSpiContext ctx = stateProvider.getSpiContextWithoutInitialLatch(); - if (formatter == null || context != ctx) { - context = ctx; + if (formatter == null || this.spiCtx != ctx) { + this.spiCtx = ctx; - formatter = context.messageFormatter(); + formatter = this.spiCtx.messageFormatter(); } assert formatter != null; diff --git a/modules/core/src/main/java/org/apache/ignite/spi/communication/tcp/internal/TcpHandshakeExecutor.java b/modules/core/src/main/java/org/apache/ignite/spi/communication/tcp/internal/TcpHandshakeExecutor.java index 612ef1418f257..c08a16844e3e9 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/communication/tcp/internal/TcpHandshakeExecutor.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/communication/tcp/internal/TcpHandshakeExecutor.java @@ -26,6 +26,7 @@ import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteLogger; import org.apache.ignite.internal.CoreMessagesProvider; +import org.apache.ignite.internal.util.nio.MessageSerialization; import org.apache.ignite.internal.util.nio.ssl.BlockingSslHandler; import org.apache.ignite.internal.util.nio.ssl.GridSslMeta; import org.apache.ignite.internal.util.typedef.internal.U; @@ -36,7 +37,6 @@ import org.apache.ignite.spi.communication.tcp.messages.HandshakeMessage; import org.apache.ignite.spi.communication.tcp.messages.NodeIdMessage; import org.apache.ignite.spi.communication.tcp.messages.RecoveryLastReceivedMessage; -import org.apache.ignite.spi.communication.tcp.messages.RecoveryLastReceivedMessageSerializer; import org.jetbrains.annotations.Nullable; import static org.apache.ignite.internal.util.CommonUtils.makeMessageType; @@ -172,7 +172,7 @@ private abstract static class BlockingTransport { NodeIdMessage nodeIdMsg = new NodeIdMessage(); reader.setBuffer(buf); - msgFactory.serializer(nodeIdMsg.directType()).readFrom(nodeIdMsg, reader); + MessageSerialization.readFrom(msgFactory, nodeIdMsg, reader); reader.reset(); return nodeIdMsg.nodeId(); @@ -191,7 +191,7 @@ void sendHandshake(HandshakeMessage msg) throws IgniteCheckedException { writer.setBuffer(buf); - msgFactory.serializer(msg.directType()).writeTo(msg, writer); + MessageSerialization.writeTo(msgFactory, msg, writer); buf.flip(); @@ -210,8 +210,6 @@ long receiveAcknowledge() throws IgniteCheckedException { boolean fininshed = false; RecoveryLastReceivedMessage msg = new RecoveryLastReceivedMessage(); - RecoveryLastReceivedMessageSerializer msgSer = - (RecoveryLastReceivedMessageSerializer)msgFactory.serializer(msg.directType()); short msgType = 0; int readPos = 0; @@ -243,7 +241,7 @@ long receiveAcknowledge() throws IgniteCheckedException { reader.setBuffer(buf); - fininshed = msgSer.readFrom(msg, reader); + fininshed = MessageSerialization.readFrom(msgFactory, msg, reader); readPos = buf.position(); } diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/SerializableDataBagItemWrapper.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/SerializableDataBagItemWrapper.java index 7e3bc16ed43e1..09b2f64485b3e 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/SerializableDataBagItemWrapper.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/SerializableDataBagItemWrapper.java @@ -76,13 +76,13 @@ private T unwrap() { } /** {@inheritDoc} */ - @Override public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { + @Override public void marshal(Marshaller marsh) throws IgniteCheckedException { if (data != null) dataBytes = U.marshal(marsh, data); } /** {@inheritDoc} */ - @Override public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { + @Override public void unmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { if (dataBytes != null) { try { data = U.unmarshal(marsh, dataBytes, clsLdr); diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryIoSession.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryIoSession.java index d054080e4c648..e237db2cf3c7a 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryIoSession.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoveryIoSession.java @@ -32,10 +32,13 @@ import javax.net.ssl.SSLSocket; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteException; +import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.direct.DirectMessageReader; import org.apache.ignite.internal.direct.DirectMessageWriter; +import org.apache.ignite.internal.managers.communication.MessageMarshalling; import org.apache.ignite.internal.managers.communication.UnknownMessageException; import org.apache.ignite.internal.util.CommonUtils; +import org.apache.ignite.internal.util.nio.MessageSerialization; import org.apache.ignite.internal.util.typedef.X; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.marshaller.jdk.JdkMarshaller; @@ -144,7 +147,7 @@ void writeMessage(TcpDiscoveryAbstractMessage msg) throws IgniteCheckedException * @return Deserialized message instance. * @throws IgniteCheckedException If deserialization fails. */ - T readMessage() throws IgniteCheckedException, IOException { + T readMessage() throws IgniteCheckedException, IOException { try { byte b0 = (byte)in.read(); byte b1 = (byte)in.read(); @@ -166,8 +169,6 @@ T readMessage() throws IgniteCheckedException, IOException { msgReader.reset(); msgReader.setBuffer(msgBuf); - MessageSerializer msgSer = spi.messageFactory().serializer(msg.directType()); - boolean finished; do { @@ -180,7 +181,7 @@ T readMessage() throws IgniteCheckedException, IOException { msgBuf.limit(read); - finished = msgSer.readFrom(msg, msgReader); + finished = MessageSerialization.readFrom(spi.messageFactory(), msg, msgReader); // Server Discovery only sends next message to next Server upon receiving a receipt for the previous one. // This behaviour guarantees that we never read a next message from the buffer right after the end of @@ -196,6 +197,8 @@ T readMessage() throws IgniteCheckedException, IOException { } while (!finished); + MessageMarshalling.unmarshal(msg, ((IgniteEx)spi.ignite()).context()); + return (T)msg; } catch (Exception e) { @@ -237,8 +240,8 @@ public Socket socket() { * @param out Output stream to write serialized message. * @throws IOException If serialization fails. */ - void serializeMessage(Message m, OutputStream out) throws IOException { - MessageSerializer msgSer = spi.messageFactory().serializer(m.directType()); + void serializeMessage(Message m, OutputStream out) throws IOException, IgniteCheckedException { + MessageMarshalling.marshal(m, ((IgniteEx)spi.ignite()).context(), null); msgWriter.reset(); msgWriter.setBuffer(msgBuf); @@ -249,7 +252,7 @@ void serializeMessage(Message m, OutputStream out) throws IOException { // Should be cleared before first operation. msgBuf.clear(); - finished = msgSer.writeTo(m, msgWriter); + finished = MessageSerialization.writeTo(spi.messageFactory(), m, msgWriter); out.write(msgBuf.array(), 0, msgBuf.position()); } diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java index 5594e77395b5c..ed3db8d7b8b66 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySpi.java @@ -72,6 +72,7 @@ import org.apache.ignite.lang.IgniteProductVersion; import org.apache.ignite.lang.IgniteUuid; import org.apache.ignite.marshaller.Marshaller; +import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.plugin.extensions.communication.MessageFactory; import org.apache.ignite.resources.IgniteInstanceResource; import org.apache.ignite.resources.LoggerResource; @@ -1809,7 +1810,7 @@ protected void writeToSocket( * @throws IOException If IO failed or read timed out. * @throws IgniteCheckedException If unmarshalling failed. */ - protected T readMessage(TcpDiscoveryIoSession ses, long timeout) throws IOException, IgniteCheckedException { + protected T readMessage(TcpDiscoveryIoSession ses, long timeout) throws IOException, IgniteCheckedException { Socket sock = ses.socket(); assert sock != null; diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/TcpDiscoveryNode.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/TcpDiscoveryNode.java index 2cfc4781230b8..46f0fe8684a05 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/TcpDiscoveryNode.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/internal/TcpDiscoveryNode.java @@ -37,6 +37,7 @@ import org.apache.ignite.internal.ClusterMetricsSnapshot; import org.apache.ignite.internal.IgniteNodeAttributes; import org.apache.ignite.internal.MarshallableMessage; +import org.apache.ignite.internal.Marshalled; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.managers.discovery.IgniteClusterNode; import org.apache.ignite.internal.processors.cluster.NodeMetricsMessage; @@ -73,7 +74,8 @@ public class TcpDiscoveryNode extends GridMetadataAwareAdapter implements Ignite /** Consistent ID. */ @GridToStringInclude - private Object consistentId; + @Marshalled("consistentIdBytes") + Object consistentId; /** Serialized {@link #consistentId}. */ @Order(1) @@ -81,7 +83,8 @@ public class TcpDiscoveryNode extends GridMetadataAwareAdapter implements Ignite /** Node attributes. */ @GridToStringExclude - private Map attrs; + @Marshalled("attrsBytes") + Map attrs; /** Serialized {@link #attrs}. */ @Order(2) @@ -220,29 +223,15 @@ public TcpDiscoveryNode(UUID id, } /** {@inheritDoc} */ - @Override public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { - if (attrs != null) - attrsBytes = U.marshal(marsh, attrs); - - if (consistentId != null) - consistentIdBytes = U.marshal(marsh, consistentId); - + @Override public void marshal(Marshaller marsh) throws IgniteCheckedException { metricsMsg = new NodeMetricsMessage(metrics); } /** {@inheritDoc} */ - @Override public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { - if (attrsBytes != null) - attrs = U.unmarshal(marsh, attrsBytes, clsLdr); - - if (consistentIdBytes != null) - consistentId = U.unmarshal(marsh, consistentIdBytes, clsLdr); - + @Override public void unmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { if (metricsMsg != null) metrics = new ClusterMetricsSnapshot(metricsMsg); - attrsBytes = null; - consistentIdBytes = null; metricsMsg = null; } @@ -311,6 +300,10 @@ public void lastSuccessfulAddress(InetSocketAddress lastSuccessfulAddr) { */ public void setAttributes(Map attrs) { this.attrs = U.sealMap(attrs); + + // Invalidate the @Marshalled cache: attrs are mutated after the first marshal (auth adds the security + // subject on join), and a stale attrsBytes would propagate the pre-auth attributes. + attrsBytes = null; } /** diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryAbstractTraceableMessage.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryAbstractTraceableMessage.java index c36601a399567..239d5d4de54f6 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryAbstractTraceableMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryAbstractTraceableMessage.java @@ -83,12 +83,12 @@ public Object readResolve() { } /** {@inheritDoc} */ - @Override public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { + @Override public void marshal(Marshaller marsh) throws IgniteCheckedException { spanContainerBytes = spanContainer == null ? null : spanContainer.serializedSpanBytes(); } /** {@inheritDoc} */ - @Override public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { + @Override public void unmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { if (spanContainerBytes != null) spanContainer.serializedSpanBytes(spanContainerBytes); } diff --git a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryNodeAddFinishedMessage.java b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryNodeAddFinishedMessage.java index ff6b252c439e0..4d68ba5b492e7 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryNodeAddFinishedMessage.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/discovery/tcp/messages/TcpDiscoveryNodeAddFinishedMessage.java @@ -19,12 +19,10 @@ import java.util.Map; import java.util.UUID; -import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.Marshalled; import org.apache.ignite.internal.Order; import org.apache.ignite.internal.util.tostring.GridToStringExclude; import org.apache.ignite.internal.util.typedef.internal.S; -import org.apache.ignite.internal.util.typedef.internal.U; -import org.apache.ignite.marshaller.Marshaller; import org.apache.ignite.spi.discovery.tcp.internal.DiscoveryDataPacket; import org.jetbrains.annotations.Nullable; @@ -47,7 +45,8 @@ public class TcpDiscoveryNodeAddFinishedMessage extends TcpDiscoveryAbstractTrac /** */ @GridToStringExclude - private Map clientNodeAttrs; + @Marshalled("clientNodeAttrsBytes") + Map clientNodeAttrs; /** Serialized client node attributes. */ @Order(2) @@ -122,20 +121,6 @@ public void clientNodeAttributes(Map clientNodeAttrs) { clientNodeAttrsBytes = null; } - /** {@inheritDoc} */ - @Override public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { - if (clientNodeAttrs != null) - clientNodeAttrsBytes = U.marshal(marsh, clientNodeAttrs); - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { - if (clientNodeAttrsBytes != null) - clientNodeAttrs = U.unmarshal(marsh, clientNodeAttrsBytes, clsLdr); - - clientNodeAttrsBytes = null; - } - /** {@inheritDoc} */ @Override public String toString() { return S.toString(TcpDiscoveryNodeAddFinishedMessage.class, this, "super", super.toString()); diff --git a/modules/core/src/test/java/org/apache/ignite/cdc/CdcCacheVersionTest.java b/modules/core/src/test/java/org/apache/ignite/cdc/CdcCacheVersionTest.java index aa33d3859b330..1d42ed57ece25 100644 --- a/modules/core/src/test/java/org/apache/ignite/cdc/CdcCacheVersionTest.java +++ b/modules/core/src/test/java/org/apache/ignite/cdc/CdcCacheVersionTest.java @@ -416,7 +416,7 @@ private void addConflictData( KeyCacheObject key = new KeyCacheObjectImpl(i, null, intCache.affinity().partition(i)); CacheObject val = new CacheObjectImpl(createUser(i), null); - val.prepareMarshal(intCache.context().cacheObjectContext()); + val.marshal(intCache.context().cacheObjectContext()); drMap.put(key, new GridCacheDrInfo(val, new GridCacheVersion(1, i, 1, OTHER_CLUSTER_ID))); } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/GridAffinityNoCacheSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/GridAffinityNoCacheSelfTest.java index 5d914886a46dc..cff11ed735ec3 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/GridAffinityNoCacheSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/GridAffinityNoCacheSelfTest.java @@ -284,13 +284,13 @@ private TestCacheObject(Object val) { } /** {@inheritDoc} */ - @Override public void finishUnmarshal(CacheObjectValueContext ctx, ClassLoader ldr) + @Override public void unmarshal(CacheObjectValueContext ctx, ClassLoader ldr) throws IgniteCheckedException { throw new UnsupportedOperationException(); } /** {@inheritDoc} */ - @Override public void prepareMarshal(CacheObjectValueContext ctx) throws IgniteCheckedException { + @Override public void marshal(CacheObjectValueContext ctx) throws IgniteCheckedException { throw new UnsupportedOperationException(); } } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/codegen/MarshallerCacheFreeUnmarshalTest.java b/modules/core/src/test/java/org/apache/ignite/internal/codegen/MarshallerCacheFreeUnmarshalTest.java new file mode 100644 index 0000000000000..f9a5d29c81519 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/codegen/MarshallerCacheFreeUnmarshalTest.java @@ -0,0 +1,110 @@ +/* + * 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.codegen; + +import java.util.Collection; +import java.util.List; +import java.util.Map; +import com.tngtech.archunit.base.DescribedPredicate; +import com.tngtech.archunit.core.domain.JavaClass; +import com.tngtech.archunit.core.domain.JavaClasses; +import com.tngtech.archunit.core.domain.JavaCodeUnit; +import com.tngtech.archunit.core.domain.JavaMethodCall; +import com.tngtech.archunit.core.importer.ClassFileImporter; +import com.tngtech.archunit.core.importer.ImportOption; +import com.tngtech.archunit.lang.ArchRule; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.plugin.extensions.communication.MessageMarshaller; +import org.junit.BeforeClass; +import org.junit.Test; + +import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses; + +/** + * A message is finish-unmarshalled in two passes — cache-free (via {@code GridIoManager}) and cache-aware (via a + * subsystem) — and the mode-aware no-double-unmarshal check ({@link MessageMarshaller.Dedup}) deliberately allows + * both. So whatever the cache-free pass does must stay correct when the cache-aware pass runs it again. + * + *

The distinction is the side effect. A plain {@code @Marshalled} field unmarshals by assignment + * ({@code msg.x = ...}); assigning the same value twice is a no-op, so it is idempotent and needs no guarding. A + * {@code @Marshalled} / {@code @Marshalled} field unmarshals by mutation ({@code collection.add} / + * {@code map.put}); running that twice appends the elements twice — a doubled, corrupt collection. So a collection/map + * mutation is the one thing that must not run in both passes, and the generator keeps it in the cache-aware pass only. + * + *

That is exactly what this rule checks — purely the mutating side effect, not the fields: the cache-free + * {@code unmarshal(msg, kctx)} overload of every generated marshaller must not call {@link Collection#add} or + * {@link Map#put}. Assignments are left unchecked (they can't break); a generator regression that moved an append into + * the cache-free pass — a real double-add the runtime check can't see, since it allows both passes — fails here. + */ +public class MarshallerCacheFreeUnmarshalTest { + /** + * The two-arg, cache-free {@code unmarshal} overload. The cache-aware overload takes a cache context and a + * class loader (four args); {@code unmarshalNio} shares the two-arg shape, so the name is matched too. + */ + private static final DescribedPredicate CACHE_FREE_UNMARSHAL = + new DescribedPredicate<>("cache-free unmarshal(msg, kctx)") { + @Override public boolean test(JavaCodeUnit unit) { + List params = unit.getRawParameterTypes(); + + return "unmarshal".equals(unit.getName()) + && params.size() == 2 + && params.get(1).isEquivalentTo(GridKernalContext.class); + } + }; + + /** A {@link Collection#add} or {@link Map#put} append made from within the cache-free {@code unmarshal}. */ + private static final DescribedPredicate CACHE_FREE_UNMARSHAL_APPEND = + new DescribedPredicate<>("Collection.add / Map.put from the cache-free unmarshal pass") { + @Override public boolean test(JavaMethodCall call) { + if (!CACHE_FREE_UNMARSHAL.test(call.getOrigin())) + return false; + + JavaClass owner = call.getTarget().getOwner(); + String mtd = call.getTarget().getName(); + + return owner.isAssignableTo(Collection.class) && "add".equals(mtd) + || owner.isAssignableTo(Map.class) && "put".equals(mtd); + } + }; + + /** All production classes on the classpath (the generated marshallers among them), excluding JARs. */ + private static JavaClasses classes; + + /** */ + @BeforeClass + public static void importClasses() { + classes = new ClassFileImporter() + .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_JARS) + .importPackages("org.apache.ignite"); + } + + /** The cache-free {@code unmarshal} overload must not append to collections/maps; those are cache-pass only. */ + @Test + public void cacheFreeFinishDoesNotAppendToCollections() { + ArchRule rule = noClasses() + .that() + .areAssignableTo(MessageMarshaller.class) + .should() + .callMethodWhere(CACHE_FREE_UNMARSHAL_APPEND) + .because("@Marshalled/@Marshalled appends are non-idempotent and run only in the cache-aware " + + "unmarshal pass; an append in the cache-free pass would double-add when both passes run, which " + + "the mode-aware unmarshal-once check (MessageMarshaller.Dedup) permits and cannot catch."); + + rule.check(classes); + } +} 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 8fb559b9aac85..554b32558d1d3 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 @@ -35,6 +35,7 @@ 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.processors.cache.GridCacheIdMessage; import org.apache.ignite.internal.util.CommonUtils; import org.apache.ignite.internal.util.IgniteUtils; import org.apache.ignite.internal.util.typedef.F; @@ -50,6 +51,24 @@ /** */ public class MessageProcessorTest { + /** */ + @Test + public void testMarshalledObjectsMessage() { + Compilation compilation = compile("TestMarshalledObjectsMessage.java"); + + assertThat(compilation).succeeded(); + + assertEquals(2, compilation.generatedSourceFiles().size()); + + assertThat(compilation) + .generatedSourceFile("org.apache.ignite.internal.TestMarshalledObjectsMessageSerializer") + .hasSourceEquivalentTo(javaFile("TestMarshalledObjectsMessageSerializer.java")); + + assertThat(compilation) + .generatedSourceFile("org.apache.ignite.internal.TestMarshalledObjectsMessageMarshaller") + .hasSourceEquivalentTo(javaFile("TestMarshalledObjectsMessageMarshaller.java")); + } + /** */ @Test public void testProcessorGeneratesSerializer() { @@ -57,11 +76,15 @@ public void testProcessorGeneratesSerializer() { assertThat(compilation).succeeded(); - assertEquals(1, compilation.generatedSourceFiles().size()); + assertEquals(2, compilation.generatedSourceFiles().size()); assertThat(compilation) .generatedSourceFile("org.apache.ignite.internal.TestMessageSerializer") .hasSourceEquivalentTo(javaFile("TestMessageSerializer.java")); + + assertThat(compilation) + .generatedSourceFile("org.apache.ignite.internal.TestMessageMarshaller") + .hasSourceEquivalentTo(javaFile("TestMessageMarshaller.java")); } /** */ @@ -71,11 +94,15 @@ public void testCollectionsMessage() { assertThat(compilation).succeeded(); - assertEquals(1, compilation.generatedSourceFiles().size()); + assertEquals(2, compilation.generatedSourceFiles().size()); assertThat(compilation) .generatedSourceFile("org.apache.ignite.internal.TestCollectionsMessageSerializer") .hasSourceEquivalentTo(javaFile("TestCollectionsMessageSerializer.java")); + + assertThat(compilation) + .generatedSourceFile("org.apache.ignite.internal.TestCollectionsMessageMarshaller") + .hasSourceEquivalentTo(javaFile("TestCollectionsMessageMarshaller.java")); } /** */ @@ -85,11 +112,15 @@ public void testMapMessage() { assertThat(compilation).succeeded(); - assertEquals(1, compilation.generatedSourceFiles().size()); + assertEquals(2, compilation.generatedSourceFiles().size()); assertThat(compilation) .generatedSourceFile("org.apache.ignite.internal.TestMapMessageSerializer") .hasSourceEquivalentTo(javaFile("TestMapMessageSerializer.java")); + + assertThat(compilation) + .generatedSourceFile("org.apache.ignite.internal.TestMapMessageMarshaller") + .hasSourceEquivalentTo(javaFile("TestMapMessageMarshaller.java")); } /** */ @@ -132,6 +163,7 @@ public void testInheritedMessages() { assertThat(compilation).succeeded(); + // No marshaller: the messages have nothing to marshal, so its generation is skipped. assertEquals(1, compilation.generatedSourceFiles().size()); assertThat(compilation) @@ -146,7 +178,8 @@ public void testMultipleMessages() { assertThat(compilation).succeeded(); - assertEquals(2, compilation.generatedSourceFiles().size()); + // No ChildMessageMarshaller: the message has nothing to marshal, so its generation is skipped. + assertEquals(3, compilation.generatedSourceFiles().size()); assertThat(compilation) .generatedSourceFile("org.apache.ignite.internal.ChildMessageSerializer") @@ -155,6 +188,10 @@ public void testMultipleMessages() { assertThat(compilation) .generatedSourceFile("org.apache.ignite.internal.TestMessageSerializer") .hasSourceEquivalentTo(javaFile("TestMessageSerializer.java")); + + assertThat(compilation) + .generatedSourceFile("org.apache.ignite.internal.TestMessageMarshaller") + .hasSourceEquivalentTo(javaFile("TestMessageMarshaller.java")); } /** */ @@ -219,6 +256,9 @@ public void testDefaultMapperEnumFields() { assertThat(compilation).succeeded(); + // No marshaller: enum fields need no marshalling, so its generation is skipped. + assertEquals(1, compilation.generatedSourceFiles().size()); + assertThat(compilation) .generatedSourceFile("org.apache.ignite.internal.DefaultMapperEnumFieldsMessageSerializer") .hasSourceEquivalentTo(javaFile("DefaultMapperEnumFieldsMessageSerializer.java")); @@ -259,6 +299,9 @@ public void testCustomMapperEnumFieldsMessage() { assertThat(compilation).succeeded(); + // No marshaller: enum fields need no marshalling, so its generation is skipped. + assertEquals(1, compilation.generatedSourceFiles().size()); + assertThat(compilation) .generatedSourceFile("org.apache.ignite.internal.CustomMapperEnumFieldsMessageSerializer") .hasSourceEquivalentTo(javaFile("CustomMapperEnumFieldsMessageSerializer.java")); @@ -271,9 +314,15 @@ public void testMarshallableMessage() { assertThat(compilation).succeeded(); + assertEquals(2, compilation.generatedSourceFiles().size()); + + assertThat(compilation) + .generatedSourceFile("org.apache.ignite.internal.TestMarshallableMessageSerializer") + .hasSourceEquivalentTo(javaFile("TestMarshallableMessageSerializer.java")); + assertThat(compilation) - .generatedSourceFile("org.apache.ignite.internal.TestMarshallableMessageMarshallableSerializer") - .hasSourceEquivalentTo(javaFile("TestMarshallableMessageMarshallableSerializer.java")); + .generatedSourceFile("org.apache.ignite.internal.TestMarshallableMessageMarshaller") + .hasSourceEquivalentTo(javaFile("TestMarshallableMessageMarshaller.java")); } /** @@ -352,6 +401,136 @@ public void testCompressAnnotationFailsForUnsupportedTypes() { assertThat(compilation).hadErrorContaining("Compress annotation is used for an unsupported type: java.util.List"); } + /** Verifies that {@code @NioField} on a non-{@link Message}-typed field is a compilation error. */ + @Test + public void testNioFieldOnNonMessageTypeFails() { + Compilation compilation = compile("NioFieldOnNonMessageMessage.java"); + + assertThat(compilation).failed(); + assertThat(compilation).hadErrorContaining("@NioField has no effect on non-Message field"); + } + + /** Verifies that {@code @NioField} on a message needing a cache object context is a compilation error. */ + @Test + public void testNioFieldNeedingCacheContextFails() { + Compilation compilation = compile("NioFieldNeedsCtxMessage.java"); + + assertThat(compilation).failed(); + assertThat(compilation).hadErrorContaining("needs a cache object context to unmarshal"); + } + + /** Verifies that {@code @Marshalled} generates {@code U.unmarshal} with a blank line before the null-out. */ + @Test + public void testMarshalledMessage() { + Compilation compilation = compile("TestMarshalledMessage.java"); + + assertThat(compilation).succeeded(); + + assertEquals(2, compilation.generatedSourceFiles().size()); + + assertThat(compilation) + .generatedSourceFile("org.apache.ignite.internal.TestMarshalledMessageSerializer") + .hasSourceEquivalentTo(javaFile("TestMarshalledMessageSerializer.java")); + + assertThat(compilation) + .generatedSourceFile("org.apache.ignite.internal.TestMarshalledMessageMarshaller") + .hasSourceEquivalentTo(javaFile("TestMarshalledMessageMarshaller.java")); + } + + /** Verifies that {@code @Marshalled} generates Set reconstruction in FINISH_CACHE mode. */ + @Test + public void testMarshalledCollectionMessage() { + Compilation compilation = compile("TestMarshalledCollectionMessage.java"); + + assertThat(compilation).succeeded(); + + assertEquals(2, compilation.generatedSourceFiles().size()); + + assertThat(compilation) + .generatedSourceFile("org.apache.ignite.internal.TestMarshalledCollectionMessageSerializer") + .hasSourceEquivalentTo(javaFile("TestMarshalledCollectionMessageSerializer.java")); + + assertThat(compilation) + .generatedSourceFile("org.apache.ignite.internal.TestMarshalledCollectionMessageMarshaller") + .hasSourceEquivalentTo(javaFile("TestMarshalledCollectionMessageMarshaller.java")); + } + + /** Verifies that {@code @Marshalled} generates Map reconstruction in FINISH_CACHE mode. */ + @Test + public void testMarshalledMapMessage() { + Compilation compilation = compile("TestMarshalledMapMessage.java"); + + assertThat(compilation).succeeded(); + + assertEquals(2, compilation.generatedSourceFiles().size()); + + assertThat(compilation) + .generatedSourceFile("org.apache.ignite.internal.TestMarshalledMapMessageSerializer") + .hasSourceEquivalentTo(javaFile("TestMarshalledMapMessageSerializer.java")); + + assertThat(compilation) + .generatedSourceFile("org.apache.ignite.internal.TestMarshalledMapMessageMarshaller") + .hasSourceEquivalentTo(javaFile("TestMarshalledMapMessageMarshaller.java")); + } + + /** Verifies a deployable {@link GridCacheIdMessage} gets a generated deployer that bridges cache-object fields. */ + @Test + public void testDeployerGeneration() { + Compilation compilation = compile("TestCacheIdMessage.java"); + + assertThat(compilation).succeeded(); + + assertEquals(3, compilation.generatedSourceFiles().size()); + + assertThat(compilation) + .generatedSourceFile("org.apache.ignite.internal.TestCacheIdMessageDeployer") + .hasSourceEquivalentTo(javaFile("TestCacheIdMessageDeployer.java")); + } + + /** Verifies a {@code DeployableMessage}'s generated deployer delegates to its custom {@code deploy}. */ + @Test + public void testDeployerDelegatesToCustomDeployment() { + Compilation compilation = compile("TestDeployableMessage.java"); + + assertThat(compilation).succeeded(); + + assertThat(compilation) + .generatedSourceFile("org.apache.ignite.internal.TestDeployableMessageDeployer") + .hasSourceEquivalentTo(javaFile("TestDeployableMessageDeployer.java")); + } + + /** Verifies a nested {@link GridCacheMessage} field is deployed by delegating to the static facade entry point. */ + @Test + public void testDeployerHandlesNestedMessage() { + Compilation compilation = compile("TestNestedDeployMessage.java", "TestCacheIdMessage.java"); + + assertThat(compilation).succeeded(); + + assertThat(compilation) + .generatedSourceFile("org.apache.ignite.internal.TestNestedDeployMessageDeployer") + .hasSourceEquivalentTo(javaFile("TestNestedDeployMessageDeployer.java")); + } + + /** Verifies the generator fails fast when a deployable message cannot resolve a cache context. */ + @Test + public void testDeployerFailsWithoutCacheContext() { + Compilation compilation = compile("TestNoCacheCtxMessage.java"); + + assertThat(compilation).failed(); + assertThat(compilation).hadErrorContaining("Cannot resolve cache context"); + } + + /** Verifies the processor rejects a {@code NonMarshallableMessage} with declared marshalling logic. */ + @Test + public void testNonMarshallableWithMarshalledFieldFailed() { + Compilation compilation = compile("WrongNonMarshallableMessage.java"); + + assertThat(compilation).failed(); + + assertThat(compilation) + .hadErrorContaining("NonMarshallableMessage must not implement MarshallableMessage or declare @Marshalled fields"); + } + /** */ private Compilation compile(String... srcFiles) { return compile(new MessageProcessor(), srcFiles); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/codegen/MessageSerializationArchitectureTest.java b/modules/core/src/test/java/org/apache/ignite/internal/codegen/MessageSerializationArchitectureTest.java new file mode 100644 index 0000000000000..1bf95ef871ee0 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/codegen/MessageSerializationArchitectureTest.java @@ -0,0 +1,149 @@ +/* + * 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.codegen; + +import com.tngtech.archunit.base.DescribedPredicate; +import com.tngtech.archunit.core.domain.JavaClasses; +import com.tngtech.archunit.core.domain.JavaMethodCall; +import com.tngtech.archunit.core.domain.JavaModifier; +import com.tngtech.archunit.core.domain.properties.HasOwner; +import com.tngtech.archunit.core.importer.ClassFileImporter; +import com.tngtech.archunit.core.importer.ImportOption; +import com.tngtech.archunit.lang.ArchRule; +import org.apache.ignite.internal.managers.communication.MessageMarshalling; +import org.apache.ignite.internal.processors.cache.GridCacheMessageDeployer; +import org.apache.ignite.internal.util.nio.MessageSerialization; +import org.apache.ignite.plugin.extensions.communication.MessageMarshaller; +import org.apache.ignite.plugin.extensions.communication.MessageSerializer; +import org.junit.BeforeClass; +import org.junit.Test; + +import static com.tngtech.archunit.core.domain.JavaCall.Predicates.target; +import static com.tngtech.archunit.core.domain.JavaClass.Predicates.assignableTo; +import static com.tngtech.archunit.lang.syntax.ArchRuleDefinition.noClasses; + +/** + * Verifies that instance methods of {@link MessageSerializer}, {@link MessageMarshaller} and + * {@link GridCacheMessageDeployer} are only called from classes that implement these interfaces (i.e. generated + * serializers/marshallers/deployers and their hand-written wrappers). All other code must use the static + * convenience methods: + *

    + *
  • {@link MessageSerialization#writeTo}
  • + *
  • {@link MessageSerialization#readFrom}
  • + *
  • {@link MessageMarshalling#marshal}
  • + *
  • {@code MessageMarshalling.unmarshal}
  • + *
  • static {@code GridCacheMessageDeployer.deploy(factory, msg, ctx)}
  • + *
+ * + *

The rules key on whether the called method is {@code static}, not on its name — so any instance method added + * to these interfaces is covered automatically. + */ +public class MessageSerializationArchitectureTest { + /** Matches method calls that resolve to a non-static (instance) method. */ + private static final DescribedPredicate TO_INSTANCE_METHOD = + new DescribedPredicate<>("to instance method") { + @Override public boolean test(JavaMethodCall call) { + return call.getTarget().resolveMember() + .map(m -> !m.getModifiers().contains(JavaModifier.STATIC)) + .orElse(false); + } + }; + + /** Classes under analysis: all production + test sources on the classpath, excluding JARs. */ + private static JavaClasses classes; + + /** */ + @BeforeClass + public static void importClasses() { + classes = new ClassFileImporter() + .withImportOption(ImportOption.Predefined.DO_NOT_INCLUDE_JARS) + .importPackages("org.apache.ignite"); + } + + /** + * Instance methods of {@link MessageSerializer} ({@code writeTo}, {@code readFrom}) must only be + * called from within classes that themselves implement {@link MessageSerializer} — i.e. generated + * serializers and hand-written wrappers that delegate to the underlying serializer — or the + * {@link MessageSerialization} dispatcher that resolves and calls them. + * + * Everyone else must use the static {@link MessageSerialization} entry points. + */ + @Test + public void serializerInstanceMethodsOnlyCalledFromImplementations() { + ArchRule rule = noClasses() + .that() + // Exclude MessageSerializer implementations (generated + wrappers) and the dispatch facade. + .areNotAssignableTo(MessageSerializer.class) + .and().areNotAssignableTo(MessageSerialization.class) + .should() + .callMethodWhere(TO_INSTANCE_METHOD + .and(target(HasOwner.Predicates.With.owner(assignableTo(MessageSerializer.class)))) + ) + .because("Use static MessageSerialization.writeTo(factory, msg, writer) and " + + "MessageSerialization.readFrom(factory, msg, reader) instead of calling instance methods directly."); + + rule.check(classes); + } + + /** + * Instance methods of {@link MessageMarshaller} ({@code marshal}, {@code unmarshal}) must + * only be called from within classes that themselves implement {@link MessageMarshaller} — i.e. generated + * marshallers and hand-written wrappers that delegate to the underlying marshaller — or the + * {@link MessageMarshalling} dispatcher that resolves and calls them. + * + * Everyone else must use the static {@link MessageMarshalling} entry points. + */ + @Test + public void marshallerInstanceMethodsOnlyCalledFromImplementations() { + ArchRule rule = noClasses() + .that() + // Exclude MessageMarshaller implementations (generated + wrappers) and the MessageMarshalling dispatcher. + .areNotAssignableTo(MessageMarshaller.class) + .and().areNotAssignableTo(MessageMarshalling.class) + .should() + .callMethodWhere(TO_INSTANCE_METHOD + .and(target(HasOwner.Predicates.With.owner(assignableTo(MessageMarshaller.class)))) + ) + .because("Use the static MessageMarshalling.marshal(...) / MessageMarshalling.unmarshal(...) entry points " + + "instead of calling instance methods directly."); + + rule.check(classes); + } + + /** + * Instance method of {@link GridCacheMessageDeployer} ({@code deploy}) must only be called from + * within classes that themselves implement {@link GridCacheMessageDeployer} — i.e. generated deployers. + * + * Everyone else must use the static {@code GridCacheMessageDeployer.deploy(factory, msg, ctx)} facade. + */ + @Test + public void deployerInstanceMethodOnlyCalledFromImplementations() { + ArchRule rule = noClasses() + .that() + // Exclude GridCacheMessageDeployer itself and all its implementations (generated deployers). + .areNotAssignableTo(GridCacheMessageDeployer.class) + .should() + .callMethodWhere(TO_INSTANCE_METHOD + .and(target(HasOwner.Predicates.With.owner(assignableTo(GridCacheMessageDeployer.class)))) + ) + .because("Use static GridCacheMessageDeployer.deploy(factory, msg, ctx) instead of " + + "calling the instance method directly."); + + rule.check(classes); + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/direct/DirectMarshallingMessagesTest.java b/modules/core/src/test/java/org/apache/ignite/internal/direct/DirectMarshallingMessagesTest.java index ea37b6abe4545..b7273e53665f9 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/direct/DirectMarshallingMessagesTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/direct/DirectMarshallingMessagesTest.java @@ -22,7 +22,6 @@ import java.util.Map; import org.apache.ignite.internal.CoreMessagesProvider; import org.apache.ignite.internal.managers.communication.IgniteMessageFactoryImpl; -import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.plugin.extensions.communication.MessageFactory; import org.apache.ignite.plugin.extensions.communication.MessageFactoryProvider; @@ -46,7 +45,7 @@ public class DirectMarshallingMessagesTest extends GridCommonAbstractTest { /** Message factory. */ private final MessageFactory msgFactory = new IgniteMessageFactoryImpl(new MessageFactoryProvider[] { - new CoreMessagesProvider(jdk(), jdk(), U.gridClassLoader()), + new CoreMessagesProvider(jdk(), jdk()), factory -> factory.register( TestNestedContainersMessage.TYPE, TestNestedContainersMessage::new, diff --git a/modules/core/src/test/java/org/apache/ignite/internal/direct/stream/DirectByteBufferStreamImplByteOrderSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/direct/stream/DirectByteBufferStreamImplByteOrderSelfTest.java index 40004815c5265..5fed920d1f21f 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/direct/stream/DirectByteBufferStreamImplByteOrderSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/direct/stream/DirectByteBufferStreamImplByteOrderSelfTest.java @@ -88,13 +88,9 @@ public void setUp() throws Exception { * @return Stream. */ private static DirectByteBufferStream createStream(ByteBuffer buff) { - DirectByteBufferStream stream = new DirectByteBufferStream(new MessageFactory() { - @Override public void register(short directType, Supplier supplier) throws IgniteException { - throw new UnsupportedOperationException(); - } - + DirectByteBufferStream stream = new DirectByteBufferStream(new MessageFactory<>() { @Override public void register(short directType, Supplier supplier, - MessageSerializer serializer) throws IgniteException { + MessageSerializer serializer) throws IgniteException { throw new UnsupportedOperationException(); } @@ -102,7 +98,7 @@ private static DirectByteBufferStream createStream(ByteBuffer buff) { return null; } - @Override public MessageSerializer serializer(short type) { + @Override public MessageSerializer serializer(short type) { return null; } }); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/managers/AbstractMessageSerializationTest.java b/modules/core/src/test/java/org/apache/ignite/internal/managers/AbstractMessageSerializationTest.java index 4f76c87312f6c..eaa1081abf1f3 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/managers/AbstractMessageSerializationTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/managers/AbstractMessageSerializationTest.java @@ -31,6 +31,7 @@ import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.util.GridLongList; +import org.apache.ignite.internal.util.nio.MessageSerialization; import org.apache.ignite.lang.IgniteProductVersion; import org.apache.ignite.lang.IgniteUuid; import org.apache.ignite.plugin.extensions.communication.Message; @@ -104,13 +105,13 @@ private void checkSerializationAndDeserializationConsistency( initializeMessage(msg); - while (!msgFactory.serializer(msgType).writeTo(msg, writer)) { + while (!MessageSerialization.writeTo(msgFactory, msg, writer)) { // No-op. } msg = msgFactory.create(msgType); - while (!msgFactory.serializer(msgType).readFrom(msg, reader)) { + while (!MessageSerialization.readFrom(msgFactory, msg, reader)) { // No-op. } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/managers/IgniteCoreMessagesSerializationTest.java b/modules/core/src/test/java/org/apache/ignite/internal/managers/IgniteCoreMessagesSerializationTest.java index 21f22330814af..2eb6c7e640b2c 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/managers/IgniteCoreMessagesSerializationTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/managers/IgniteCoreMessagesSerializationTest.java @@ -21,7 +21,6 @@ import org.apache.commons.lang3.reflect.FieldUtils; import org.apache.ignite.internal.CoreMessagesProvider; import org.apache.ignite.internal.processors.cache.distributed.dht.PartitionUpdateCountersMessage; -import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteUuid; import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.plugin.extensions.communication.MessageFactoryProvider; @@ -34,7 +33,7 @@ public class IgniteCoreMessagesSerializationTest extends AbstractMessageSerializationTest { /** {@inheritDoc} */ @Override protected MessageFactoryProvider messageFactory() { - return new CoreMessagesProvider(jdk(), jdk(), U.gridClassLoader()); + return new CoreMessagesProvider(jdk(), jdk()); } /** {@inheritDoc} */ diff --git a/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/CompressedMessageTest.java b/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/CompressedMessageTest.java index 98f1478c2b3a4..e42db5f9639e9 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/CompressedMessageTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/CompressedMessageTest.java @@ -34,6 +34,7 @@ import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GridDhtPartitionsFullMessage; import org.apache.ignite.internal.processors.cache.distributed.dht.preloader.GroupPartitionIdPair; +import org.apache.ignite.internal.util.nio.MessageSerialization; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.plugin.extensions.communication.MessageFactory; @@ -49,7 +50,7 @@ public class CompressedMessageTest { /** */ private static final MessageFactory MSG_FACTORY = new IgniteMessageFactoryImpl(new MessageFactoryProvider[]{ - new CoreMessagesProvider(jdk(), jdk(), U.gridClassLoader())}); + new CoreMessagesProvider(jdk(), jdk())}); /** */ @Test @@ -133,7 +134,7 @@ public void testReadFailsOnNullChunk() { reader.setBuffer(buf); GridTestUtils.assertThrows(null, - () -> new CompressedMessageSerializer().readFrom(new CompressedMessage(), reader), + () -> MessageSerialization.readFrom(MSG_FACTORY, new CompressedMessage(), reader), IgniteException.class, "unexpected null chunk"); } @@ -156,7 +157,7 @@ public void testReadFailsOnNegativeDataSize() { reader.setBuffer(buf); GridTestUtils.assertThrows(null, - () -> new CompressedMessageSerializer().readFrom(new CompressedMessage(), reader), + () -> MessageSerialization.readFrom(MSG_FACTORY, new CompressedMessage(), reader), IgniteException.class, "Invalid compressed message data size"); } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/ErrorMessageSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/ErrorMessageSelfTest.java index b3ff36de94b8a..72ed44eacb6a2 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/ErrorMessageSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/ErrorMessageSelfTest.java @@ -40,7 +40,7 @@ public void testDirectAndInsverseConversion() throws IgniteCheckedException { assertSame(e, msg0.error()); - msg0.prepareMarshal(jdk()); + msg0.marshal(jdk()); byte[] errBytes = msg0.errBytes; @@ -49,7 +49,7 @@ public void testDirectAndInsverseConversion() throws IgniteCheckedException { ErrorMessage msg1 = new ErrorMessage(); msg1.errBytes = errBytes; - msg1.finishUnmarshal(jdk(), U.gridClassLoader()); + msg1.unmarshal(jdk(), U.gridClassLoader()); Throwable t = msg1.error(); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/GridCommunicationSendMessageSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/GridCommunicationSendMessageSelfTest.java index 90d9027ad7b67..a2b656f117a9d 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/GridCommunicationSendMessageSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/GridCommunicationSendMessageSelfTest.java @@ -24,7 +24,6 @@ import org.apache.ignite.plugin.ExtensionRegistry; import org.apache.ignite.plugin.PluginContext; import org.apache.ignite.plugin.extensions.communication.Message; -import org.apache.ignite.plugin.extensions.communication.MessageFactory; import org.apache.ignite.plugin.extensions.communication.MessageFactoryProvider; import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; @@ -150,7 +149,7 @@ public static class TestPluginProvider extends AbstractTestPluginProvider { /** {@inheritDoc} */ @Override public void initExtensions(PluginContext ctx, ExtensionRegistry registry) { registry.registerExtension(MessageFactoryProvider.class, new MessageFactoryProvider() { - @Override public void registerAll(MessageFactory factory) { + @Override public void registerAll(IgniteMessageFactory factory) { factory.register(DIRECT_TYPE, TestValidByteIdMessage::new, new TestValidByteIdMessageSerializer()); factory.register(DIRECT_TYPE_OVER_BYTE, TestOverByteIdMessage::new, new TestOverByteIdMessageSerializer()); } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/GridIoManagerOrderedPoisonMessageTest.java b/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/GridIoManagerOrderedPoisonMessageTest.java new file mode 100644 index 0000000000000..3ab2ebbf83835 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/GridIoManagerOrderedPoisonMessageTest.java @@ -0,0 +1,247 @@ +/* + * 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.managers.communication; + +import java.util.Map; +import java.util.Queue; +import java.util.UUID; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.TimeUnit; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.internal.CoreMessagesProvider; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.processors.cache.CacheObjectContext; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.plugin.AbstractTestPluginProvider; +import org.apache.ignite.plugin.ExtensionRegistry; +import org.apache.ignite.plugin.PluginContext; +import org.apache.ignite.plugin.extensions.communication.Message; +import org.apache.ignite.plugin.extensions.communication.MessageFactoryProvider; +import org.apache.ignite.plugin.extensions.communication.MessageMarshaller; +import org.apache.ignite.plugin.extensions.communication.MessageReader; +import org.apache.ignite.plugin.extensions.communication.MessageSerializer; +import org.apache.ignite.plugin.extensions.communication.MessageWriter; +import org.apache.ignite.testframework.GridTestUtils; +import org.apache.ignite.testframework.ListeningTestLogger; +import org.apache.ignite.testframework.LogListener; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; +import org.jetbrains.annotations.Nullable; +import org.junit.Test; + +import static org.apache.ignite.internal.managers.communication.GridIoPolicy.PUBLIC_POOL; + +/** + * An ordered message whose payload fails to unmarshal must be skipped with an error logged, not abandon the rest of + * the accumulated set: the tail would otherwise stay unprocessed until the next message arrives on the topic. + */ +public class GridIoManagerOrderedPoisonMessageTest extends GridCommonAbstractTest { + /** Direct type for the test message, past the core range. */ + private static final short TYPE = (short)(CoreMessagesProvider.MAX_MESSAGE_ID + 10); + + /** Ordered topic under test. */ + private static final String TOPIC = "poison-test-topic"; + + /** Listener log of the receiver. */ + private ListeningTestLogger lsnrLog; + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { + IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); + + if (getTestIgniteInstanceIndex(igniteInstanceName) == 1) + cfg.setGridLogger(lsnrLog); + + cfg.setPluginProviders(new AbstractTestPluginProvider() { + @Override public String name() { + return "ordered-poison-test"; + } + + @Override public void initExtensions(PluginContext ctx, ExtensionRegistry registry) { + registry.registerExtension(MessageFactoryProvider.class, factory -> + factory.register(TYPE, PoisonableMessage::new, new Serializer(), new PoisoningMarshaller())); + } + }); + + return cfg; + } + + /** {@inheritDoc} */ + @Override protected void afterTest() throws Exception { + stopAllGrids(); + + super.afterTest(); + } + + /** A poisoned message between two valid ones must not prevent the delivery of the one behind it. */ + @Test + public void testPoisonedMessageSkippedTailDelivered() throws Exception { + lsnrLog = new ListeningTestLogger(log); + + LogListener skipLsnr = LogListener.matches("Failed to unmarshal ordered message (will skip)").build(); + + lsnrLog.registerListener(skipLsnr); + + IgniteEx snd = startGrid(0); + IgniteEx rcv = startGrid(1); + + Queue delivered = new ConcurrentLinkedQueue<>(); + CountDownLatch firstReceived = new CountDownLatch(1); + CountDownLatch proceed = new CountDownLatch(1); + CountDownLatch tailReceived = new CountDownLatch(1); + + rcv.context().io().addMessageListener(TOPIC, (nodeId, msg, plc) -> { + PoisonableMessage m = (PoisonableMessage)msg; + + delivered.add(m.seq); + + if (m.seq == 1) { + firstReceived.countDown(); + + U.awaitQuiet(proceed); + } + else + tailReceived.countDown(); + }); + + GridIoManager sndIo = snd.context().io(); + + // First message occupies the striped worker in the listener above. + sndIo.sendOrderedMessage(rcv.localNode(), TOPIC, new PoisonableMessage(1, false), PUBLIC_POOL, 30_000, false); + + assertTrue("First message must be delivered", firstReceived.await(10, TimeUnit.SECONDS)); + + // While the worker is blocked, the poisoned message and the one behind it accumulate in the same set. + sndIo.sendOrderedMessage(rcv.localNode(), TOPIC, new PoisonableMessage(2, true), PUBLIC_POOL, 30_000, false); + sndIo.sendOrderedMessage(rcv.localNode(), TOPIC, new PoisonableMessage(3, false), PUBLIC_POOL, 30_000, false); + + assertTrue("Both messages must reach the receiver's ordered set before the worker resumes", + GridTestUtils.waitForCondition(() -> pendingOrderedMessages(rcv) == 2, 10_000)); + + proceed.countDown(); + + assertTrue("The message behind the poisoned one must still be delivered", tailReceived.await(10, TimeUnit.SECONDS)); + + assertEquals("[1, 3]", delivered.toString()); + assertTrue("Skip must be logged", skipLsnr.check(10_000)); + } + + /** @return Number of messages pending in the receiver's ordered set of {@link #TOPIC}. */ + private static int pendingOrderedMessages(IgniteEx rcv) { + Map> setMap = GridTestUtils.getFieldValue(rcv.context().io(), "msgSetMap"); + + Map byNode = setMap.get(TOPIC); + + if (byNode == null || byNode.isEmpty()) + return 0; + + Queue msgs = GridTestUtils.getFieldValue(byNode.values().iterator().next(), "msgs"); + + return msgs.size(); + } + + /** Message with a sequence number and a poison flag making its payload unmarshal fail on the receiver. */ + private static class PoisonableMessage implements Message { + /** */ + int seq; + + /** */ + boolean poison; + + /** */ + PoisonableMessage() { + // No-op. + } + + /** */ + PoisonableMessage(int seq, boolean poison) { + this.seq = seq; + this.poison = poison; + } + } + + /** Writes the two fields behind the header. */ + private static class Serializer implements MessageSerializer { + /** {@inheritDoc} */ + @Override public boolean writeTo(PoisonableMessage msg, MessageWriter writer) { + if (!writer.isHeaderWritten()) { + if (!writer.writeHeader(msg.directType())) + return false; + + writer.onHeaderWritten(); + } + + switch (writer.state()) { + case 0: + if (!writer.writeInt(msg.seq)) + return false; + + writer.incrementState(); + + case 1: + if (!writer.writeBoolean(msg.poison)) + return false; + + writer.incrementState(); + } + + return true; + } + + /** {@inheritDoc} */ + @Override public boolean readFrom(PoisonableMessage msg, MessageReader reader) { + switch (reader.state()) { + case 0: + msg.seq = reader.readInt(); + + if (!reader.isLastRead()) + return false; + + reader.incrementState(); + + case 1: + msg.poison = reader.readBoolean(); + + if (!reader.isLastRead()) + return false; + + reader.incrementState(); + } + + return true; + } + } + + /** Fails the finish-unmarshal of poisoned messages. */ + private static class PoisoningMarshaller implements MessageMarshaller { + /** {@inheritDoc} */ + @Override public void marshal(PoisonableMessage msg, GridKernalContext kctx, + @Nullable CacheObjectContext cacheObjCtx) { + // No-op. + } + + /** {@inheritDoc} */ + @Override public void unmarshal(PoisonableMessage msg, GridKernalContext kctx, + @Nullable CacheObjectContext cacheObjCtx, ClassLoader clsLdr) throws IgniteCheckedException { + if (msg.poison) + throw new IgniteCheckedException("Poisoned payload"); + } + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/IgniteMessageFactoryImplTest.java b/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/IgniteMessageFactoryImplTest.java index 838474c82c7d1..1e0e47760bede 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/IgniteMessageFactoryImplTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/IgniteMessageFactoryImplTest.java @@ -106,7 +106,7 @@ public void testRegisterTheSameType() { */ private static class TestMessageFactoryPovider implements MessageFactoryProvider { /** {@inheritDoc} */ - @Override public void registerAll(MessageFactory factory) { + @Override public void registerAll(IgniteMessageFactory factory) { factory.register(TEST_MSG_1_TYPE, TestMessage1::new, new TestMessage1Serializer()); factory.register(TEST_MSG_42_TYPE, TestMessage42::new, new TestMessage42Serializer()); } @@ -117,7 +117,7 @@ private static class TestMessageFactoryPovider implements MessageFactoryProvider */ private static class TestMessageFactoryPoviderWithTheSameDirectType implements MessageFactoryProvider { /** {@inheritDoc} */ - @Override public void registerAll(MessageFactory factory) { + @Override public void registerAll(IgniteMessageFactory factory) { factory.register(TEST_MSG_1_TYPE, TestMessage1::new, new TestMessage1Serializer()); } } @@ -127,7 +127,7 @@ private static class TestMessageFactoryPoviderWithTheSameDirectType implements M */ private static class TestMessageFactory implements MessageFactoryProvider { /** {@inheritDoc} */ - @Override public void registerAll(MessageFactory factory) { + @Override public void registerAll(IgniteMessageFactory factory) { factory.register(TEST_MSG_2_TYPE, TestMessage2::new, new TestMessage2Serializer()); } } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/MessageDirectTypeIdConflictTest.java b/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/MessageDirectTypeIdConflictTest.java index f540a08293d02..14dec7e5035a9 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/MessageDirectTypeIdConflictTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/MessageDirectTypeIdConflictTest.java @@ -23,7 +23,6 @@ import org.apache.ignite.plugin.AbstractTestPluginProvider; import org.apache.ignite.plugin.ExtensionRegistry; import org.apache.ignite.plugin.PluginContext; -import org.apache.ignite.plugin.extensions.communication.MessageFactory; import org.apache.ignite.plugin.extensions.communication.MessageFactoryProvider; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; import org.junit.Test; @@ -80,7 +79,7 @@ public static class TestPluginProvider extends AbstractTestPluginProvider { /** {@inheritDoc} */ @Override public void initExtensions(PluginContext ctx, ExtensionRegistry registry) { registry.registerExtension(MessageFactoryProvider.class, new MessageFactoryProvider() { - @Override public void registerAll(MessageFactory factory) { + @Override public void registerAll(IgniteMessageFactory factory) { factory.register(DIRECT_TYPE, DuplicateDirectTypeIdMessage::new, new DuplicateDirectTypeIdMessageSerializer()); } }); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/MessageFactoryMarshallerInitializationTest.java b/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/MessageFactoryMarshallerInitializationTest.java index c35ff721f67f7..f6fcc89dad513 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/MessageFactoryMarshallerInitializationTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/managers/communication/MessageFactoryMarshallerInitializationTest.java @@ -26,7 +26,6 @@ import org.apache.ignite.plugin.AbstractTestPluginProvider; import org.apache.ignite.plugin.ExtensionRegistry; import org.apache.ignite.plugin.PluginContext; -import org.apache.ignite.plugin.extensions.communication.MessageFactory; import org.apache.ignite.plugin.extensions.communication.MessageFactoryProvider; import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; @@ -97,13 +96,13 @@ private void checkInits(IgniteConfiguration cfg, int exp) throws Exception { /** Message factory provider, which counts initializations. */ private static class TestMessageFactoryProvider extends AbstractMarshallableMessageFactoryProvider { /** {@inheritDoc} */ - @Override public void registerAll(MessageFactory factory) { + @Override public void registerAll(IgniteMessageFactory factory) { // No-op. } /** {@inheritDoc} */ - @Override public void init(Marshaller dfltMarsh, Marshaller schemaAwareMarsh, ClassLoader resolvedClsLdr) { - super.init(dfltMarsh, schemaAwareMarsh, resolvedClsLdr); + @Override public void init(Marshaller dfltMarsh, Marshaller schemaAwareMarsh) { + super.init(dfltMarsh, schemaAwareMarsh); initCnt.incrementAndGet(); } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheMetricsCacheSizeTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheMetricsCacheSizeTest.java index 77616ae9e8d2b..9aed75febee59 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheMetricsCacheSizeTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/CacheMetricsCacheSizeTest.java @@ -33,8 +33,8 @@ import org.apache.ignite.internal.direct.DirectMessageReader; import org.apache.ignite.internal.direct.DirectMessageWriter; import org.apache.ignite.internal.processors.cluster.CacheMetricsMessage; +import org.apache.ignite.internal.util.nio.MessageSerialization; import org.apache.ignite.plugin.extensions.communication.MessageFactory; -import org.apache.ignite.plugin.extensions.communication.MessageSerializer; import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi; import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryMetricsUpdateMessage; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; @@ -106,7 +106,6 @@ public void testCacheSize() throws Exception { msg.addServerCacheMetrics(srvrId, cacheMetrics); MessageFactory msgFactory = ((TcpDiscoverySpi)grid(0).context().discovery().getInjectedDiscoverySpi()).messageFactory(); - MessageSerializer msgSerializer = msgFactory.serializer(msg.directType()); // First time we write initial message type which is not read by the reader because the message type is known. // We have to skip this header at the further message reading. @@ -123,7 +122,7 @@ public void testCacheSize() throws Exception { // 2kb should be enough for an empty message even if it is a relatively large metrics message. msgWritter.setBuffer(ByteBuffer.allocate(2048)); - assertTrue(msgSerializer.writeTo(msg, msgWritter)); + assertTrue(MessageSerialization.writeTo(msgFactory, msg, msgWritter)); assertTrue(msgWritter.getBuffer().hasRemaining()); @@ -135,7 +134,7 @@ public void testCacheSize() throws Exception { TcpDiscoveryMetricsUpdateMessage msg2 = new TcpDiscoveryMetricsUpdateMessage(); - assertTrue(msgSerializer.readFrom(msg2, msgReader)); + assertTrue(MessageSerialization.readFrom(msgFactory, msg2, msgReader)); Map cacheMetrics2 = msg2.serversFullMetricsMessages().values().iterator().next() .cachesMetricsMessages(); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ClientSlowDiscoveryAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ClientSlowDiscoveryAbstractTest.java index fd6c6f9e4befd..4cb06c7fb441a 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ClientSlowDiscoveryAbstractTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/ClientSlowDiscoveryAbstractTest.java @@ -93,7 +93,7 @@ static class CustomMessageInterceptingDiscoverySpi extends TcpDiscoverySpi { TcpDiscoveryCustomEventMessage cm = (TcpDiscoveryCustomEventMessage)msg; try { - cm.finishUnmarshal(marshaller(), U.resolveClassLoader(ignite().configuration())); + cm.unmarshal(marshaller(), U.resolveClassLoader(ignite().configuration())); assertNotNull(cm.message()); } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheIoManagerRetryTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheIoManagerRetryTest.java index 0ab5cd5382219..92eeceadd055f 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheIoManagerRetryTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/GridCacheIoManagerRetryTest.java @@ -26,8 +26,9 @@ import org.apache.ignite.IgniteException; import org.apache.ignite.cluster.ClusterNode; import org.apache.ignite.internal.GridKernalContext; -import org.apache.ignite.internal.GridTopic; +import org.apache.ignite.internal.IgniteKernal; import org.apache.ignite.internal.managers.communication.GridIoManager; +import org.apache.ignite.internal.managers.communication.GridIoMessage; import org.apache.ignite.internal.managers.deployment.GridDeploymentManager; import org.apache.ignite.internal.managers.discovery.GridDiscoveryManager; import org.apache.ignite.internal.managers.systemview.GridSystemViewManager; @@ -36,7 +37,6 @@ import org.apache.ignite.internal.processors.pool.PoolProcessor; import org.apache.ignite.internal.util.lang.RunnableX; import org.apache.ignite.internal.util.typedef.X; -import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi; import org.apache.ignite.spi.deployment.local.LocalDeploymentSpi; import org.apache.ignite.spi.discovery.tcp.TcpDiscoverySpi; @@ -128,6 +128,8 @@ private void doTest(Function action) throws Except cacheIoMgr.start(cctx); + ((IgniteKernal)cacheIoMgr.context().kernalContext().grid()).initMessageFactoryForTest(); + return cacheIoMgr; } @@ -190,15 +192,7 @@ private GridKernalContext kernalContext(int retryCnt, AtomicInteger sendCnt) thr */ private void configureGridIoManager(GridTestKernalContext ctx, AtomicInteger sendCnt) { ctx.add(new GridIoManager(ctx) { - @Override public void sendToGridTopic(ClusterNode node, GridTopic topic, Message msg, byte plc) - throws IgniteCheckedException { - sendCnt.incrementAndGet(); - - throw new IgniteCheckedException("Test cause"); - } - - @Override public void sendOrderedMessage(ClusterNode node, Object topic, Message msg, byte plc, - long timeout, boolean skipOnTimeout) throws IgniteCheckedException { + @Override public void sendPrepared(ClusterNode node, GridIoMessage ioMsg) throws IgniteCheckedException { sendCnt.incrementAndGet(); throw new IgniteCheckedException("Test cause"); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteIncompleteCacheObjectSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteIncompleteCacheObjectSelfTest.java index 0e8f4676f0c73..f280524648a01 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteIncompleteCacheObjectSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteIncompleteCacheObjectSelfTest.java @@ -149,13 +149,13 @@ private TestCacheObject(final byte type) { } /** {@inheritDoc} */ - @Override public void finishUnmarshal(final CacheObjectValueContext ctx, final ClassLoader ldr) + @Override public void unmarshal(final CacheObjectValueContext ctx, final ClassLoader ldr) throws IgniteCheckedException { // No-op } /** {@inheritDoc} */ - @Override public void prepareMarshal(final CacheObjectValueContext ctx) throws IgniteCheckedException { + @Override public void marshal(final CacheObjectValueContext ctx) throws IgniteCheckedException { // No-op } } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteMarshallerCacheClientRequestsMappingTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteMarshallerCacheClientRequestsMappingTest.java index fe4a0eeb70809..03cfabc9729d6 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteMarshallerCacheClientRequestsMappingTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/IgniteMarshallerCacheClientRequestsMappingTest.java @@ -163,7 +163,7 @@ private void doTestMarshallingBinaryMappingsLoadedFromClient(boolean receiveMeta try { TcpDiscoveryCustomEventMessage evtMsg = (TcpDiscoveryCustomEventMessage)msg; - evtMsg.finishUnmarshal(marshaller(), U.gridClassLoader()); + evtMsg.unmarshal(marshaller(), U.gridClassLoader()); DiscoveryCustomMessage delegate = U.unwrapCustomMessage(evtMsg.message()); @@ -239,7 +239,7 @@ public void testBinaryMetaDelayedForComputeJobResult() throws Exception { try { TcpDiscoveryCustomEventMessage evtMsg = (TcpDiscoveryCustomEventMessage)msg; - evtMsg.finishUnmarshal(marshaller(), U.gridClassLoader()); + evtMsg.unmarshal(marshaller(), U.gridClassLoader()); DiscoveryCustomMessage delegate = U.unwrapCustomMessage(evtMsg.message()); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxRecreateEvictionTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxRecreateEvictionTest.java new file mode 100644 index 0000000000000..2e061b796dcaa --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxRecreateEvictionTest.java @@ -0,0 +1,136 @@ +/* + * 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.processors.cache.distributed.near; + +import java.util.ArrayList; +import java.util.List; +import org.apache.ignite.IgniteCache; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.configuration.NearCacheConfiguration; +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.IgniteInternalFuture; +import org.apache.ignite.internal.TestRecordingCommunicationSpi; +import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTxPrepareRequest; +import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTxPrepareResponse; +import org.apache.ignite.internal.util.typedef.F; +import org.apache.ignite.testframework.GridTestUtils; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; +import org.apache.ignite.transactions.Transaction; +import org.junit.Test; + +import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL; +import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC; +import static org.apache.ignite.transactions.TransactionConcurrency.OPTIMISTIC; +import static org.apache.ignite.transactions.TransactionIsolation.READ_COMMITTED; + +/** + * Checks that a near-write {@link GridDhtTxPrepareRequest} targeting a cache incarnation older than the receiver's + * current one is answered with the key in {@code nearEvicted}, so the reader is dropped instead of keeping a stale + * near entry. + */ +public class GridNearTxRecreateEvictionTest extends GridCommonAbstractTest { + /** */ + private static final String CACHE_NAME = "recreate-near-cache"; + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { + IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); + + cfg.setCommunicationSpi(new TestRecordingCommunicationSpi()); + + cfg.setCacheConfiguration(cacheConfiguration()); + + return cfg; + } + + /** */ + private CacheConfiguration cacheConfiguration() { + return new CacheConfiguration(CACHE_NAME) + .setAtomicityMode(TRANSACTIONAL) + .setWriteSynchronizationMode(FULL_SYNC) + .setNearConfiguration(new NearCacheConfiguration<>()); + } + + /** {@inheritDoc} */ + @Override protected void afterTest() throws Exception { + stopAllGrids(); + + super.afterTest(); + } + + /** @throws Exception If failed. */ + @Test + public void testStaleNearWriteReportedEvictedAfterRecreate() throws Exception { + IgniteEx prim = startGrid(0); + IgniteEx reader = startGrid(1); + + awaitPartitionMapExchange(); + + IgniteCache cache = prim.cache(CACHE_NAME); + + Integer key = primaryKey(cache); + + cache.put(key, 1); + + // The get makes the second node a near reader, so a write below sends it a near-write prepare. + assertEquals((Integer)1, reader.cache(CACHE_NAME).get(key)); + + TestRecordingCommunicationSpi primSpi = TestRecordingCommunicationSpi.spi(prim); + TestRecordingCommunicationSpi readerSpi = TestRecordingCommunicationSpi.spi(reader); + + primSpi.blockMessages((node, msg) -> msg instanceof GridDhtTxPrepareRequest); + + // A bounded timeout rolls the transaction back and releases partitions, so the destroy below can proceed + // while the captured prepare stays queued. + IgniteInternalFuture txFut = GridTestUtils.runAsync(() -> { + try (Transaction tx = prim.transactions().txStart(OPTIMISTIC, READ_COMMITTED, 3000, 0)) { + cache.put(key, 2); + + tx.commit(); + } + catch (Exception ignored) { + // Rolled back on timeout while the prepare is blocked. + } + }); + + primSpi.waitForBlocked(); + + txFut.get(getTestTimeout()); + + prim.destroyCache(CACHE_NAME); + + prim.getOrCreateCache(cacheConfiguration()); + + awaitPartitionMapExchange(); + + readerSpi.record(GridDhtTxPrepareResponse.class); + + // Deliver the prepare of the destroyed incarnation to the reader. + primSpi.stopBlock(); + + List resps = new ArrayList<>(); + + assertTrue("Stale near write of the previous cache incarnation must be reported back as evicted.", + GridTestUtils.waitForCondition(() -> { + resps.addAll(readerSpi.recordedMessages(false)); + + return resps.stream().anyMatch(msg -> !F.isEmpty(((GridDhtTxPrepareResponse)msg).nearEvicted())); + }, 10_000)); + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/IgniteSequentialNodeCrashRecoveryTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/IgniteSequentialNodeCrashRecoveryTest.java index e404873a8ccad..57139ce4c5bc5 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/IgniteSequentialNodeCrashRecoveryTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/db/IgniteSequentialNodeCrashRecoveryTest.java @@ -357,7 +357,7 @@ private DiscoveryCustomMessage extractCustomMessage(TcpDiscoveryCustomEventMessa DiscoveryCustomMessage msgObj = null; try { - msg.finishUnmarshal(marshaller(), U.gridClassLoader()); + msg.unmarshal(marshaller(), U.gridClassLoader()); msgObj = (DiscoveryCustomMessage)msg.message(); } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/IncrementalSnapshotTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/IncrementalSnapshotTest.java index 6224135de075f..36bbaee3883a6 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/IncrementalSnapshotTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/IncrementalSnapshotTest.java @@ -23,6 +23,7 @@ import java.util.concurrent.atomic.AtomicReference; import java.util.function.UnaryOperator; import org.apache.ignite.IgniteCache; +import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteException; import org.apache.ignite.cache.QueryEntity; import org.apache.ignite.cluster.ClusterState; @@ -51,6 +52,7 @@ import static org.apache.ignite.internal.util.distributed.DistributedProcess.DistributedProcessType.RESTORE_CACHE_GROUP_SNAPSHOT_PREPARE; import static org.apache.ignite.internal.util.distributed.DistributedProcess.DistributedProcessType.RESTORE_CACHE_GROUP_SNAPSHOT_START; import static org.apache.ignite.internal.util.distributed.DistributedProcess.DistributedProcessType.RESTORE_INCREMENTAL_SNAPSHOT_START; +import static org.apache.ignite.marshaller.Marshallers.jdk; import static org.apache.ignite.testframework.GridTestUtils.assertThrows; import static org.apache.ignite.testframework.GridTestUtils.assertThrowsWithCause; import static org.apache.ignite.testframework.GridTestUtils.waitForCondition; @@ -426,8 +428,18 @@ public void testStagesFail() throws Exception { DistributedProcess.DistributedProcessType stage = failStage.get(); - if (stage != null && stage.ordinal() == singleMsg.type()) - GridTestUtils.setFieldValue(singleMsg, "errMsg", new ErrorMessage(new IgniteException("Test exception."))); + if (stage != null && stage.ordinal() == singleMsg.type()) { + ErrorMessage em = new ErrorMessage(new IgniteException("Test exception.")); + + try { + em.marshal(jdk()); + } + catch (IgniteCheckedException e) { + throw new RuntimeException(e); + } + + GridTestUtils.setFieldValue(singleMsg, "errMsg", em); + } } return false; diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/IgniteCacheDumpSelf2Test.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/IgniteCacheDumpSelf2Test.java index 782b67148becc..d025cbb48f195 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/IgniteCacheDumpSelf2Test.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/dump/IgniteCacheDumpSelf2Test.java @@ -1031,7 +1031,7 @@ public void testDumpEntryConflictVersion() throws Exception { KeyCacheObject key = new KeyCacheObjectImpl(i, null, intCache.affinity().partition(i)); CacheObject val = new CacheObjectImpl(i, null); - val.prepareMarshal(intCache.context().cacheObjectContext()); + val.marshal(intCache.context().cacheObjectContext()); drMap.put(key, new GridCacheDrInfo(val, new GridCacheVersion(topVer, i, nodeOrder, dataCenterId))); } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/incremental/IncrementalSnapshotJoiningClientTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/incremental/IncrementalSnapshotJoiningClientTest.java index d40a168677626..dece733bc8bf6 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/incremental/IncrementalSnapshotJoiningClientTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/persistence/snapshot/incremental/IncrementalSnapshotJoiningClientTest.java @@ -247,7 +247,7 @@ private static class CoordinatorBlockingDiscoverySpi extends TcpDiscoverySpi { TcpDiscoveryCustomEventMessage m = (TcpDiscoveryCustomEventMessage)msg; try { - m.finishUnmarshal(marshaller(), U.resolveClassLoader(ignite().configuration())); + m.unmarshal(marshaller(), U.resolveClassLoader(ignite().configuration())); if (U.unwrapCustomMessage(m.message()) instanceof InitMessage) rcvStartSnpReq.countDown(); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryResponseUnmarshalTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryResponseUnmarshalTest.java new file mode 100644 index 0000000000000..f88d183c22f53 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/GridCacheQueryResponseUnmarshalTest.java @@ -0,0 +1,85 @@ +/* + * 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.processors.cache.query; + +import java.util.List; +import java.util.Map; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.managers.communication.MessageMarshalling; +import org.apache.ignite.internal.processors.cache.CacheObjectNotResolvedException; +import org.apache.ignite.internal.processors.cache.GridCacheContext; +import org.apache.ignite.internal.processors.cache.KeyCacheObject; +import org.apache.ignite.internal.processors.cache.KeyCacheObjectImpl; +import org.apache.ignite.internal.util.typedef.T2; +import org.apache.ignite.testframework.GridTestUtils; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; +import org.junit.Test; + +/** + * Verifies that a query result row key arrives resolved from {@code GridCacheQueryResponse} unmarshalling: a + * {@code KeyCacheObject} travels bytes-only and forbids lazy resolution (see {@code @Marshalled}). + */ +public class GridCacheQueryResponseUnmarshalTest extends GridCommonAbstractTest { + /** An unresolved key (only its bytes present) must fail fast rather than resolve lazily. */ + @Test + public void testUnresolvedKeyThrows() { + KeyCacheObject unresolved = new KeyCacheObjectImpl(null, new byte[] {1, 2, 3}, -1); + + GridTestUtils.assertThrows(log, unresolved::hashCode, CacheObjectNotResolvedException.class, null); + } + + /** {@inheritDoc} */ + @Override protected void afterTest() throws Exception { + super.afterTest(); + + stopAllGrids(); + } + + /** */ + @Test + public void testRowKeyResolved() throws Exception { + startGrid(0); + + grid(0).getOrCreateCache(DEFAULT_CACHE_NAME); + + GridCacheContext cctx = grid(0).cachex(DEFAULT_CACHE_NAME).context(); + GridKernalContext kctx = grid(0).context(); + + KeyCacheObject key = cctx.toCacheKeyObject(42); + + key.marshal(cctx.cacheObjectContext()); + + GridCacheQueryResponse res = new GridCacheQueryResponse(cctx.cacheId(), 0, true, false); + + res.data(List.of(new T2<>(key, "row"))); + + MessageMarshalling.marshal(res, kctx, null); + + GridCacheQueryResponse rcvd = new GridCacheQueryResponse(cctx.cacheId(), 0, true, false); + + rcvd.dataBytes = res.dataBytes; + + MessageMarshalling.unmarshal(rcvd, kctx, null, getClass().getClassLoader()); + + Map.Entry row = (Map.Entry)rcvd.data().iterator().next(); + + // The row key resolved during unmarshalling: hashCode() returns instead of throwing + // CacheObjectNotResolvedException (see testUnresolvedKeyThrows), and matches the original. + assertEquals(key.hashCode(), row.getKey().hashCode()); + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/IgniteCacheContinuousQueryImmutableEntryTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/IgniteCacheContinuousQueryImmutableEntryTest.java index a41490c0e405f..ebed66410dd35 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/IgniteCacheContinuousQueryImmutableEntryTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/query/continuous/IgniteCacheContinuousQueryImmutableEntryTest.java @@ -37,6 +37,7 @@ import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.processors.cache.CacheObjectImpl; import org.apache.ignite.internal.processors.cache.KeyCacheObjectImpl; +import org.apache.ignite.internal.util.nio.MessageSerialization; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.plugin.extensions.communication.MessageFactoryProvider; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; @@ -134,7 +135,7 @@ public void testEventAvailabilityScope() throws Exception { * */ @Test - public void testCacheContinuousQueryEntrySerialization() { + public void testCacheContinuousQueryEntrySerialization() throws Exception { CacheContinuousQueryEntry e0 = new CacheContinuousQueryEntry( 1, EventType.UPDATED, @@ -150,19 +151,22 @@ public void testCacheContinuousQueryEntrySerialization() { e0.markFiltered(); IgniteMessageFactoryImpl msgFactory = - new IgniteMessageFactoryImpl(new MessageFactoryProvider[]{new CoreMessagesProvider(jdk(), jdk(), U.gridClassLoader())}); + new IgniteMessageFactoryImpl(new MessageFactoryProvider[]{new CoreMessagesProvider(jdk(), jdk())}); ByteBuffer buf = ByteBuffer.allocate(4096); DirectMessageWriter writer = new DirectMessageWriter(msgFactory); - var serializer = msgFactory.serializer(e0.directType()); - assertNotNull("Serializer not found for message type " + e0.directType(), serializer); + assertNotNull("Serializer not found for message type " + e0.directType(), msgFactory.serializer(e0.directType())); writer.setBuffer(buf); + // The marshal phase run by the send path before serialization: must not touch the wire fields of + // a filtered entry. + e0.marshal(jdk()); + // Skip write class header. writer.onHeaderWritten(); - serializer.writeTo(e0, writer); + MessageSerialization.writeTo(msgFactory, e0, writer); CacheContinuousQueryEntry e1 = new CacheContinuousQueryEntry(); @@ -170,7 +174,9 @@ public void testCacheContinuousQueryEntrySerialization() { reader.setBuffer(ByteBuffer.wrap(buf.array())); - serializer.readFrom(e1, reader); + MessageSerialization.readFrom(msgFactory, e1, reader); + + e1.unmarshal(jdk(), U.gridClassLoader()); assertEquals(e0.cacheId(), e1.cacheId()); assertEquals(e0.eventType(), e1.eventType()); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxDeadlockDetectionMessageMarshallingTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxDeadlockDetectionMessageMarshallingTest.java index a6d6375c1ed87..793d95f01598d 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxDeadlockDetectionMessageMarshallingTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxDeadlockDetectionMessageMarshallingTest.java @@ -27,7 +27,9 @@ import org.apache.ignite.internal.IgniteKernal; import org.apache.ignite.internal.managers.communication.GridIoPolicy; import org.apache.ignite.internal.managers.communication.GridMessageListener; +import org.apache.ignite.internal.managers.communication.MessageMarshalling; import org.apache.ignite.internal.processors.cache.GridCacheContext; +import org.apache.ignite.internal.processors.cache.GridCacheMessageDeployer; import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.processors.cache.IgniteCacheProxy; import org.apache.ignite.internal.processors.cache.KeyCacheObject; @@ -65,7 +67,8 @@ public void testMessageUnmarshallWithoutCacheContext() throws Exception { @Override public void onMessage(UUID nodeId, Object msg, byte plc) { if (msg instanceof TxLocksResponse) { try { - ((TxLocksResponse)msg).finishUnmarshal(clientCtx, clientCtx.deploy().globalLoader()); + MessageMarshalling.unmarshal((TxLocksResponse)msg, + clientCtx.kernalContext(), null, clientCtx.deploy().globalLoader()); res.set(true); } @@ -86,7 +89,7 @@ public void testMessageUnmarshallWithoutCacheContext() throws Exception { TxLocksResponse msg = new TxLocksResponse(); msg.addKey(cctx.txKey(key)); - msg.prepareMarshal(cctx.shared()); + GridCacheMessageDeployer.deploy(cctx.kernalContext().messageFactory(), msg, cctx.shared()); ((IgniteKernal)ignite).context().cache().context().gridIO().sendToCustomTopic( ((IgniteKernal)client).localNode(), TOPIC, msg, GridIoPolicy.PUBLIC_POOL); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/database/CacheFreeListSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/database/CacheFreeListSelfTest.java index 8817a3ba49ebc..3b317c5db3836 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/database/CacheFreeListSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/database/CacheFreeListSelfTest.java @@ -725,13 +725,13 @@ private TestCacheObject(int size) { } /** {@inheritDoc} */ - @Override public void finishUnmarshal(CacheObjectValueContext ctx, ClassLoader ldr) + @Override public void unmarshal(CacheObjectValueContext ctx, ClassLoader ldr) throws IgniteCheckedException { assert false; } /** {@inheritDoc} */ - @Override public void prepareMarshal(CacheObjectValueContext ctx) throws IgniteCheckedException { + @Override public void marshal(CacheObjectValueContext ctx) throws IgniteCheckedException { assert false; } } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/datastreamer/DataStreamerImplSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/datastreamer/DataStreamerImplSelfTest.java index 625f290d1c6fc..1a494d68f9093 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/datastreamer/DataStreamerImplSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/datastreamer/DataStreamerImplSelfTest.java @@ -32,6 +32,7 @@ import javax.cache.CacheException; import org.apache.ignite.Ignite; import org.apache.ignite.IgniteCache; +import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteDataStreamer; import org.apache.ignite.IgniteException; import org.apache.ignite.IgniteLogger; @@ -43,6 +44,7 @@ import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.managers.communication.GridIoMessage; +import org.apache.ignite.internal.managers.communication.MessageMarshalling; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.G; @@ -713,6 +715,13 @@ private static class StaleTopologyCommunicationSpi extends TcpCommunicationSpi { ioMsg.skipOnTimeout() ); + try { + MessageMarshalling.marshal(msg, ((IgniteEx)ignite).context(), null); + } + catch (IgniteCheckedException e) { + throw new RuntimeException(e); + } + needStaleTop = false; } } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/query/schema/IndexWithSameNameTestBase.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/query/schema/IndexWithSameNameTestBase.java index e37cee61fc560..efaaae6793ba2 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/query/schema/IndexWithSameNameTestBase.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/query/schema/IndexWithSameNameTestBase.java @@ -313,7 +313,7 @@ public static class SchemaFinishListeningTcpDiscoverySpi extends TcpDiscoverySpi try { TcpDiscoveryCustomEventMessage evtMsg = (TcpDiscoveryCustomEventMessage)msg; - evtMsg.finishUnmarshal(marshaller(), U.gridClassLoader()); + evtMsg.unmarshal(marshaller(), U.gridClassLoader()); DiscoveryCustomMessage discoCustomMsg = U.unwrapCustomMessage(evtMsg.message()); diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/query/schema/message/QueryEntityMessageSerializationTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/query/schema/message/QueryEntityMessageSerializationTest.java index 4de9416c1ff05..76b340a3eaeb6 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/query/schema/message/QueryEntityMessageSerializationTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/query/schema/message/QueryEntityMessageSerializationTest.java @@ -27,6 +27,7 @@ import java.util.List; import java.util.Map; import java.util.Set; +import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.cache.QueryEntity; import org.apache.ignite.cache.QueryIndex; import org.apache.ignite.cache.QueryIndexType; @@ -34,13 +35,16 @@ import org.apache.ignite.internal.direct.DirectMessageReader; import org.apache.ignite.internal.direct.DirectMessageWriter; import org.apache.ignite.internal.managers.communication.IgniteMessageFactoryImpl; +import org.apache.ignite.internal.managers.communication.MessageMarshalling; import org.apache.ignite.internal.processors.query.QueryEntityEx; +import org.apache.ignite.internal.util.nio.MessageSerialization; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.marshaller.Marshaller; import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.plugin.extensions.communication.MessageFactory; import org.apache.ignite.plugin.extensions.communication.MessageFactoryProvider; -import org.apache.ignite.plugin.extensions.communication.MessageSerializer; +import org.apache.ignite.testframework.GridTestUtils; +import org.apache.ignite.testframework.junits.GridTestKernalContext; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; import org.junit.Test; @@ -58,7 +62,7 @@ public class QueryEntityMessageSerializationTest extends GridCommonAbstractTest /** */ private final MessageFactory msgFactory = new IgniteMessageFactoryImpl( - new MessageFactoryProvider[] {new CoreMessagesProvider(marsh, marsh, U.gridClassLoader())}); + new MessageFactoryProvider[] {new CoreMessagesProvider(marsh, marsh)}); /** */ @Test @@ -91,7 +95,7 @@ public void testQueryEntityEx() throws Exception { * * @return Entity read during a full serde round-trip. */ - private QueryEntity serializeAndDeserialize(QueryEntity src, long expReadsWritesCnt) { + private QueryEntity serializeAndDeserialize(QueryEntity src, long expReadsWritesCnt) throws IgniteCheckedException { QueryEntityMessage msg = src instanceof QueryEntityEx ? new QueryEntityExMessage((QueryEntityEx)src) : new QueryEntityMessage(src); @@ -120,15 +124,19 @@ private long serializableFieldsCount(Class cls) { * * @return Restored message. */ - private T writeAndReadBack(T msg, long expReadsWritesCnt) { - ByteBuffer buf = ByteBuffer.allocate(64 * 1024); + private T writeAndReadBack(T msg, long expReadsWritesCnt) throws IgniteCheckedException { + GridTestKernalContext kctx = newContext(); + + GridTestUtils.setFieldValue(kctx.grid(), "msgFactory", msgFactory); - MessageSerializer serde = (MessageSerializer)msgFactory.serializer(msg.directType()); + MessageMarshalling.marshal(msg, kctx, null); + + ByteBuffer buf = ByteBuffer.allocate(64 * 1024); DirectMessageWriter writer = new DirectMessageWriter(msgFactory); writer.setBuffer(buf); - assertTrue(serde.writeTo(msg, writer)); + assertTrue(MessageSerialization.writeTo(msgFactory, msg, writer)); assertEquals("Writes" + ERROR_SUFFIX, expReadsWritesCnt, writer.state()); @@ -139,10 +147,12 @@ private T writeAndReadBack(T msg, long expReadsWritesCnt) { T res = (T)msgFactory.create(makeMessageType(buf.get(), buf.get())); - assertTrue(serde.readFrom(res, reader)); + assertTrue(MessageSerialization.readFrom(msgFactory, res, reader)); assertEquals("Reads" + ERROR_SUFFIX, expReadsWritesCnt, reader.state()); + MessageMarshalling.unmarshal(res, kctx, null, U.gridClassLoader()); + return res; } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/service/LazyServiceConfigurationMessageSerializationTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/LazyServiceConfigurationMessageSerializationTest.java index 2039f60e763ed..e35fd1dec5778 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/service/LazyServiceConfigurationMessageSerializationTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/service/LazyServiceConfigurationMessageSerializationTest.java @@ -22,18 +22,23 @@ import java.lang.reflect.Modifier; import java.nio.ByteBuffer; import java.util.Arrays; +import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.CoreMessagesProvider; import org.apache.ignite.internal.direct.DirectMessageReader; import org.apache.ignite.internal.direct.DirectMessageWriter; import org.apache.ignite.internal.managers.communication.IgniteMessageFactoryImpl; +import org.apache.ignite.internal.managers.communication.MessageMarshalling; +import org.apache.ignite.internal.util.nio.MessageSerialization; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.marshaller.Marshaller; import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.plugin.extensions.communication.MessageFactory; import org.apache.ignite.plugin.extensions.communication.MessageFactoryProvider; -import org.apache.ignite.plugin.extensions.communication.MessageSerializer; +import org.apache.ignite.testframework.GridTestUtils; +import org.apache.ignite.testframework.junits.GridTestKernalContext; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; import org.junit.Test; -import static org.apache.ignite.internal.util.CommonUtils.gridClassLoader; import static org.apache.ignite.internal.util.CommonUtils.makeMessageType; import static org.apache.ignite.marshaller.Marshallers.jdk; import static org.junit.Assert.assertArrayEquals; @@ -44,9 +49,12 @@ public class LazyServiceConfigurationMessageSerializationTest extends GridCommon public static final String ERROR_SUFFIX = " count is not equal to the expected fields count. " + "Has the number of fields in the `LazyServiceConfiguration` class changed?"; + /** */ + private final Marshaller marsh = jdk(); + /** */ private final MessageFactory msgFactory = new IgniteMessageFactoryImpl( - new MessageFactoryProvider[] {new CoreMessagesProvider(jdk(), jdk(), gridClassLoader())}); + new MessageFactoryProvider[] {new CoreMessagesProvider(marsh, marsh)}); /** * ServiceConfiguration declares {@code svc}, {@code nodeFilter}, {@code interceptors} as non-transient, @@ -57,7 +65,7 @@ public class LazyServiceConfigurationMessageSerializationTest extends GridCommon /** */ @Test - public void testLazyServiceConfiguration() { + public void testLazyServiceConfiguration() throws Exception { LazyServiceConfiguration cfg = lazyServiceConfiguration(); assertEquals(cfg, serializeAndDeserialize(cfg)); @@ -65,7 +73,7 @@ public void testLazyServiceConfiguration() { /** */ @Test - public void testLazyServiceConfigurationWithBytes() { + public void testLazyServiceConfigurationWithBytes() throws Exception { LazyServiceConfiguration cfg = lazyServiceConfigurationWithBytes(); LazyServiceConfiguration res = serializeAndDeserialize(cfg); @@ -86,7 +94,7 @@ public void testLazyServiceConfigurationWithBytes() { * * @return Configuration read during a full serde round-trip. */ - private LazyServiceConfiguration serializeAndDeserialize(LazyServiceConfiguration src) { + private LazyServiceConfiguration serializeAndDeserialize(LazyServiceConfiguration src) throws IgniteCheckedException { long expReadsWritesCnt = serializableFieldsCount(LazyServiceConfiguration.class) - SHADOWED_FIELD_COUNT; return writeAndReadBack(new LazyServiceConfigurationMessage(src), expReadsWritesCnt).toConfiguration(); @@ -112,15 +120,19 @@ private long serializableFieldsCount(Class cls) { * * @return Restored message. */ - private T writeAndReadBack(T msg, long expReadsWritesCnt) { - ByteBuffer buf = ByteBuffer.allocate(64 * 1024); + private T writeAndReadBack(T msg, long expReadsWritesCnt) throws IgniteCheckedException { + GridTestKernalContext kctx = newContext(); + + GridTestUtils.setFieldValue(kctx.grid(), "msgFactory", msgFactory); - MessageSerializer serde = (MessageSerializer)msgFactory.serializer(msg.directType()); + MessageMarshalling.marshal(msg, kctx, null); + + ByteBuffer buf = ByteBuffer.allocate(64 * 1024); DirectMessageWriter writer = new DirectMessageWriter(msgFactory); writer.setBuffer(buf); - assertTrue(serde.writeTo(msg, writer)); + assertTrue(MessageSerialization.writeTo(msgFactory, msg, writer)); assertEquals("Writes" + ERROR_SUFFIX, expReadsWritesCnt, writer.state()); buf.flip(); @@ -130,9 +142,11 @@ private T writeAndReadBack(T msg, long expReadsWritesCnt) { T res = (T)msgFactory.create(makeMessageType(buf.get(), buf.get())); - assertTrue(serde.readFrom(res, reader)); + assertTrue(MessageSerialization.readFrom(msgFactory, res, reader)); assertEquals("Reads" + ERROR_SUFFIX, expReadsWritesCnt, reader.state()); + MessageMarshalling.unmarshal(res, kctx, null, U.gridClassLoader()); + return res; } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/util/nio/IgniteExceptionInNioWorkerSelfTest.java b/modules/core/src/test/java/org/apache/ignite/internal/util/nio/IgniteExceptionInNioWorkerSelfTest.java index bceb60e4f6375..ce3f9fbeca5f0 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/util/nio/IgniteExceptionInNioWorkerSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/util/nio/IgniteExceptionInNioWorkerSelfTest.java @@ -18,11 +18,19 @@ package org.apache.ignite.internal.util.nio; import java.util.UUID; +import org.apache.ignite.IgniteException; import org.apache.ignite.configuration.CacheConfiguration; import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.internal.GridTopic; import org.apache.ignite.internal.IgniteDiagnosticRequest; import org.apache.ignite.internal.IgniteKernal; +import org.apache.ignite.plugin.AbstractTestPluginProvider; +import org.apache.ignite.plugin.ExtensionRegistry; +import org.apache.ignite.plugin.PluginContext; +import org.apache.ignite.plugin.extensions.communication.MessageFactoryProvider; +import org.apache.ignite.plugin.extensions.communication.MessageReader; +import org.apache.ignite.plugin.extensions.communication.MessageSerializer; +import org.apache.ignite.plugin.extensions.communication.MessageWriter; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; import org.junit.Test; @@ -43,6 +51,8 @@ public class IgniteExceptionInNioWorkerSelfTest extends GridCommonAbstractTest { cfg.setCacheConfiguration(ccfg); + cfg.setPluginProviders(new BrokenMessageProvider()); + return cfg; } @@ -73,19 +83,50 @@ public void testBrokenMessage() throws Exception { * */ private static class BrokenMessage extends IgniteDiagnosticRequest { + // No-op. + } + + /** Serializer that throws on the first {@code writeTo} call to simulate a broken message. */ + private static class BrokenMessageSerializer implements MessageSerializer { /** */ private boolean fail = true; /** {@inheritDoc} */ - @Override public short directType() { + @Override public boolean writeTo(BrokenMessage msg, MessageWriter writer) { + if (!writer.isHeaderWritten()) { + if (!writer.writeHeader(msg.directType())) + return false; + + writer.onHeaderWritten(); + } + if (fail) { fail = false; - return (byte)242; + throw new IgniteException("Broken message"); } - // IgniteDiagnosticRequest as an example. - return 13003; + return true; + } + + /** {@inheritDoc} */ + @Override public boolean readFrom(BrokenMessage msg, MessageReader reader) { + return true; + } + } + + /** Plugin provider that registers {@link BrokenMessageSerializer} for {@link BrokenMessage}. */ + public static class BrokenMessageProvider extends AbstractTestPluginProvider { + /** {@inheritDoc} */ + @Override public String name() { + return getClass().getName(); + } + + /** {@inheritDoc} */ + @Override public void initExtensions(PluginContext ctx, ExtensionRegistry registry) { + registry.registerExtension(MessageFactoryProvider.class, (factory) -> + factory.register(-42, BrokenMessage::new, new BrokenMessageSerializer()) + ); } } } diff --git a/modules/core/src/test/java/org/apache/ignite/internal/util/nio/TcpCommunicationSpiSslVolatilePayloadTest.java b/modules/core/src/test/java/org/apache/ignite/internal/util/nio/TcpCommunicationSpiSslVolatilePayloadTest.java index 9be2ee3156092..45c0d0ea029d6 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/util/nio/TcpCommunicationSpiSslVolatilePayloadTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/util/nio/TcpCommunicationSpiSslVolatilePayloadTest.java @@ -96,7 +96,8 @@ public class TcpCommunicationSpiSslVolatilePayloadTest extends GridAbstractCommu /** {@inheritDoc} */ @Override protected MessageFactoryProvider customMessageFactory() { return f -> f.register( - TestVolatilePayloadMessage.DIRECT_TYPE, TestVolatilePayloadMessage::new, new TestVolatilePayloadMessageSerializer() + TestVolatilePayloadMessage.DIRECT_TYPE, + TestVolatilePayloadMessage::new, new TestVolatilePayloadMessageSerializer() ); } diff --git a/modules/core/src/test/java/org/apache/ignite/p2p/ClassLoadingProblemExceptionTest.java b/modules/core/src/test/java/org/apache/ignite/p2p/ClassLoadingProblemExceptionTest.java index 44a39859e05b7..1af74a63c3340 100644 --- a/modules/core/src/test/java/org/apache/ignite/p2p/ClassLoadingProblemExceptionTest.java +++ b/modules/core/src/test/java/org/apache/ignite/p2p/ClassLoadingProblemExceptionTest.java @@ -197,8 +197,7 @@ private class TestCommunicationSpi extends TcpCommunicationSpi { GridCacheQueryRequest qryReq = (GridCacheQueryRequest)m; if (qryReq.deployInfo() != null) { - qryReq.prepare( - new GridDeploymentInfoBean( + qryReq.deploy(new GridDeploymentInfoBean( IgniteUuid.fromUuid(UUID.randomUUID()), qryReq.deployInfo().userVersion(), qryReq.deployInfo().deployMode(), diff --git a/modules/core/src/test/java/org/apache/ignite/plugin/extensions/communication/MessageMarshalOnceTest.java b/modules/core/src/test/java/org/apache/ignite/plugin/extensions/communication/MessageMarshalOnceTest.java new file mode 100644 index 0000000000000..46ca7dc60251a --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/plugin/extensions/communication/MessageMarshalOnceTest.java @@ -0,0 +1,256 @@ +/* + * 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.plugin.extensions.communication; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; +import org.apache.ignite.IgniteException; +import org.apache.ignite.cluster.ClusterNode; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.internal.CoreMessagesProvider; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.GridTopic; +import org.apache.ignite.internal.TestRecordingCommunicationSpi; +import org.apache.ignite.internal.managers.communication.GridIoMessage; +import org.apache.ignite.internal.managers.communication.GridIoPolicy; +import org.apache.ignite.internal.processors.cache.CacheObjectContext; +import org.apache.ignite.internal.processors.cache.GridCacheMessage; +import org.apache.ignite.lang.IgniteInClosure; +import org.apache.ignite.plugin.AbstractTestPluginProvider; +import org.apache.ignite.plugin.ExtensionRegistry; +import org.apache.ignite.plugin.PluginContext; +import org.apache.ignite.spi.IgniteSpiException; +import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi; +import org.apache.ignite.testframework.GridTestUtils; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; +import org.junit.Test; + +/** + * Verifies the marshal-once-before-fan-out contract of the collection {@code send}: a message broadcast to N remote + * nodes is marshalled exactly once (prepared before the fan-out and reused for every destination), not once per + * destination. A counting marshaller is registered for a test message; broadcasting it to {@link #RMT_CNT} remote nodes + * must produce {@code RMT_CNT} sends but a single {@code marshal}. Counting the sends keeps the check honest (a + * lone send would also marshal once). The unmarshal-once counterpart lives in {@link MessageUnmarshalOnceTest}. + * + *

The second scenario covers the send-retry path: a cache message whose first send attempt fails is retried, + * and the retry must not re-marshal the payload (it is prepared once by {@code GridCacheIoManager} before the + * retry loop, while {@code GridIoManager} marshals only the wrapper). + */ +public class MessageMarshalOnceTest extends GridCommonAbstractTest { + /** Direct type for the test message, past the core range. */ + private static final short TYPE = (short)(CoreMessagesProvider.MAX_MESSAGE_ID + 1); + + /** Direct type for the retry-check cache message. */ + private static final short RETRY_TYPE = (short)(CoreMessagesProvider.MAX_MESSAGE_ID + 2); + + /** Number of remote destinations to broadcast to (a single marshal must serve all of them). */ + private static final int RMT_CNT = 4; + + /** Counts {@code marshal} invocations of {@link MarshalOnceCheckMessage} across the JVM. */ + private static final AtomicInteger MARSHAL_CNT = new AtomicInteger(); + + /** Counts {@code marshal} invocations of {@link RetryCheckMessage} across the JVM. */ + private static final AtomicInteger RETRY_MARSHAL_CNT = new AtomicInteger(); + + /** When {@code true}, nodes are configured with the SPI failing the first send of {@link RetryCheckMessage}. */ + private boolean failFirstSend; + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { + IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); + + cfg.setCommunicationSpi(failFirstSend ? new FailFirstSendSpi() : new TestRecordingCommunicationSpi()); + + cfg.setPluginProviders(new AbstractTestPluginProvider() { + @Override public String name() { + return "marshal-once-test"; + } + + @Override public void initExtensions(PluginContext ctx, ExtensionRegistry registry) { + registry.registerExtension(MessageFactoryProvider.class, factory -> { + factory.register(TYPE, MarshalOnceCheckMessage::new, new Serializer(), new CountingMarshaller()); + factory.register(RETRY_TYPE, RetryCheckMessage::new, new RetrySerializer(), new RetryCountingMarshaller()); + }); + } + }); + + return cfg; + } + + /** {@inheritDoc} */ + @Override protected void afterTest() throws Exception { + stopAllGrids(); + + super.afterTest(); + } + + /** @throws Exception If failed. */ + @Test + public void testBroadcastMarshalsExactlyOnce() throws Exception { + startGrids(RMT_CNT + 1); + + TestRecordingCommunicationSpi commSpi = TestRecordingCommunicationSpi.spi(grid(0)); + + commSpi.record(MarshalOnceCheckMessage.class); + + List rmts = new ArrayList<>(RMT_CNT); + + for (int i = 1; i <= RMT_CNT; i++) + rmts.add(grid(i).localNode()); + + MARSHAL_CNT.set(0); + + grid(0).context().io().sendToGridTopic(rmts, GridTopic.TOPIC_IO_TEST, new MarshalOnceCheckMessage(), + GridIoPolicy.PUBLIC_POOL); + + assertEquals("Broadcast must be sent to all " + RMT_CNT + " nodes", RMT_CNT, commSpi.recordedMessages(true).size()); + + assertEquals("A message broadcast to " + RMT_CNT + " nodes must be marshalled exactly once, not per destination", + 1, MARSHAL_CNT.get()); + } + + /** @throws Exception If failed. */ + @Test + public void testRetryMarshalsExactlyOnce() throws Exception { + failFirstSend = true; + + startGrids(2); + + RETRY_MARSHAL_CNT.set(0); + + ClusterNode rmt = grid(0).cluster().node(grid(1).localNode().id()); + + grid(0).context().cache().context().io().send(rmt, new RetryCheckMessage(), GridIoPolicy.PUBLIC_POOL); + + FailFirstSendSpi spi = (FailFirstSendSpi)grid(0).configuration().getCommunicationSpi(); + + assertTrue("The first send attempt must have failed to exercise the retry path", spi.failed.get()); + + assertEquals("A message sent with a retry must be marshalled exactly once, not per attempt", + 1, RETRY_MARSHAL_CNT.get()); + } + + /** Fieldless message; only the registered marshaller's invocation count matters. */ + private static class MarshalOnceCheckMessage implements Message { + // No fields. + } + + /** Header-only serializer for the fieldless {@link MarshalOnceCheckMessage}. */ + private static class Serializer implements MessageSerializer { + /** {@inheritDoc} */ + @Override public boolean writeTo(MarshalOnceCheckMessage msg, MessageWriter writer) { + if (!writer.isHeaderWritten()) { + if (!writer.writeHeader(msg.directType())) + return false; + + writer.onHeaderWritten(); + } + + return true; + } + + /** {@inheritDoc} */ + @Override public boolean readFrom(MarshalOnceCheckMessage msg, MessageReader reader) { + return true; + } + } + + /** Marshaller that only counts {@code marshal} calls — no idempotency guard, so it counts raw invocations. */ + private static class CountingMarshaller implements MessageMarshaller { + /** {@inheritDoc} */ + @Override public void marshal(MarshalOnceCheckMessage msg, GridKernalContext kctx, CacheObjectContext nested) { + MARSHAL_CNT.incrementAndGet(); + } + + /** {@inheritDoc} */ + @Override public void unmarshal(MarshalOnceCheckMessage msg, GridKernalContext kctx, CacheObjectContext nested, + ClassLoader clsLdr) { + // No-op. + } + + /** {@inheritDoc} */ + @Override public void unmarshal(MarshalOnceCheckMessage msg, GridKernalContext kctx) { + // No-op. + } + } + + /** Fieldless cache message: takes the {@code GridCacheIoManager} send path with its retry loop. */ + private static class RetryCheckMessage extends GridCacheMessage { + /** {@inheritDoc} */ + @Override public boolean addDeploymentInfo() { + return false; + } + } + + /** Header-only serializer for the fieldless {@link RetryCheckMessage}. */ + private static class RetrySerializer implements MessageSerializer { + /** {@inheritDoc} */ + @Override public boolean writeTo(RetryCheckMessage msg, MessageWriter writer) { + if (!writer.isHeaderWritten()) { + if (!writer.writeHeader(msg.directType())) + return false; + + writer.onHeaderWritten(); + } + + return true; + } + + /** {@inheritDoc} */ + @Override public boolean readFrom(RetryCheckMessage msg, MessageReader reader) { + return true; + } + } + + /** Marshaller that only counts {@code marshal} calls of {@link RetryCheckMessage}. */ + private static class RetryCountingMarshaller implements MessageMarshaller { + /** {@inheritDoc} */ + @Override public void marshal(RetryCheckMessage msg, GridKernalContext kctx, CacheObjectContext nested) { + RETRY_MARSHAL_CNT.incrementAndGet(); + } + + /** {@inheritDoc} */ + @Override public void unmarshal(RetryCheckMessage msg, GridKernalContext kctx, CacheObjectContext nested, + ClassLoader clsLdr) { + // No-op. + } + + /** {@inheritDoc} */ + @Override public void unmarshal(RetryCheckMessage msg, GridKernalContext kctx) { + // No-op. + } + } + + /** SPI failing the first send of a {@link RetryCheckMessage} to force one retry iteration. */ + private static class FailFirstSendSpi extends TcpCommunicationSpi { + /** Set once the single simulated failure has been thrown. */ + private final AtomicBoolean failed = new AtomicBoolean(); + + /** {@inheritDoc} */ + @Override public void sendMessage(ClusterNode node, Message msg, IgniteInClosure ackC) + throws IgniteSpiException { + if (msg instanceof GridIoMessage && GridTestUtils.getFieldValue(msg, "msg") instanceof RetryCheckMessage + && failed.compareAndSet(false, true)) + throw new IgniteSpiException("Simulated transient send failure"); + + super.sendMessage(node, msg, ackC); + } + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/plugin/extensions/communication/MessageUnmarshalOnceTest.java b/modules/core/src/test/java/org/apache/ignite/plugin/extensions/communication/MessageUnmarshalOnceTest.java new file mode 100644 index 0000000000000..d02fdb9434129 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/plugin/extensions/communication/MessageUnmarshalOnceTest.java @@ -0,0 +1,74 @@ +/* + * 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.plugin.extensions.communication; + +import org.apache.ignite.internal.MarshallableMessage; +import org.apache.ignite.internal.managers.communication.MessageUnmarshalOnceCheck; +import org.apache.ignite.marshaller.Marshaller; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; +import org.junit.Test; + +/** + * Verifies the no-double-unmarshal check itself, not its coverage: {@link MessageUnmarshalOnceCheck#firstUnmarshal} must + * detect a second finish-unmarshal of the same instance within one pass, while allowing the two legitimate passes + * (cache-free and cache-aware), and the check must be enabled for every test — otherwise the suite-wide guard would + * silently turn off and pass every test vacuously. The actual coverage (no real receive path unmarshals an instance + * twice in the same pass) comes from running the check across the whole suite via {@code GridAbstractTest}. + */ +public class MessageUnmarshalOnceTest extends GridCommonAbstractTest { + /** The suite-wide guard must be on, so a silently-disabled check cannot pass every test without verifying anything. */ + @Override protected void beforeTestsStarted() throws Exception { + super.beforeTestsStarted(); + + assertTrue("IGNITE_MESSAGE_UNMARSHAL_ONCE_CHECK must be set for every test by GridAbstractTest", + MessageUnmarshalOnceCheck.ENABLED); + } + + /** A second finish-unmarshal of the same instance within one pass must be detected; the first must be allowed. */ + @Test + public void testSecondUnmarshalDetected() { + MarshallableMessage msg = new NoopMarshallableMessage(); + + assertTrue("First finish-unmarshal must be allowed", MessageUnmarshalOnceCheck.firstUnmarshal(msg, false)); + assertFalse("Second finish-unmarshal of the same instance in the same pass must be detected", + MessageUnmarshalOnceCheck.firstUnmarshal(msg, false)); + } + + /** The two legitimate passes (cache-free and cache-aware) over one instance must both be allowed. */ + @Test + public void testBothPassesAllowed() { + MarshallableMessage msg = new NoopMarshallableMessage(); + + assertTrue("Cache-free pass must be allowed", MessageUnmarshalOnceCheck.firstUnmarshal(msg, false)); + assertTrue("Cache-aware pass over the same instance must also be allowed", + MessageUnmarshalOnceCheck.firstUnmarshal(msg, true)); + } + + /** Minimal {@link MarshallableMessage}; only its identity matters to the check. */ + private static class NoopMarshallableMessage implements MarshallableMessage { + /** {@inheritDoc} */ + @Override public void marshal(Marshaller marsh) { + // No-op. + } + + /** {@inheritDoc} */ + @Override public void unmarshal(Marshaller marsh, ClassLoader clsLdr) { + // No-op. + } + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/spi/MessagesPluginProvider.java b/modules/core/src/test/java/org/apache/ignite/spi/MessagesPluginProvider.java index 865d9ba164444..8a8bb39bf9115 100644 --- a/modules/core/src/test/java/org/apache/ignite/spi/MessagesPluginProvider.java +++ b/modules/core/src/test/java/org/apache/ignite/spi/MessagesPluginProvider.java @@ -53,7 +53,7 @@ public MessagesPluginProvider(Class... msgs) { } }; - f.register(directType, msgSupp, loadSerializer(msg, null, null)); + f.register(directType, msgSupp, loadSerializer(msg)); directType++; } @@ -76,6 +76,6 @@ public MessagesPluginProvider(Class... msgs) { // Register messages into the discovery protocol. TestTcpDiscoverySpi discoSpi = (TestTcpDiscoverySpi)ctx.igniteConfiguration().getDiscoverySpi(); - discoSpi.messageFactory(msgFactoryProvider, ctx.igniteConfiguration()); + discoSpi.messageFactory(msgFactoryProvider); } } diff --git a/modules/core/src/test/java/org/apache/ignite/spi/communication/GridAbstractCommunicationSelfTest.java b/modules/core/src/test/java/org/apache/ignite/spi/communication/GridAbstractCommunicationSelfTest.java index 1ca7217b67dca..d15252f771b60 100644 --- a/modules/core/src/test/java/org/apache/ignite/spi/communication/GridAbstractCommunicationSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/spi/communication/GridAbstractCommunicationSelfTest.java @@ -154,7 +154,7 @@ private void startSpis() throws Exception { GridSpiTestContext ctx = initSpiContext(); ctx.messageFactory(new IgniteMessageFactoryImpl(new MessageFactoryProvider[] { - new CoreMessagesProvider(jdk(), jdk(), U.gridClassLoader()), customMessageFactory()})); + new CoreMessagesProvider(jdk(), jdk()), customMessageFactory()})); ctx.setLocalNode(node); diff --git a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/GridTcpCommunicationSpiConcurrentConnectSelfTest.java b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/GridTcpCommunicationSpiConcurrentConnectSelfTest.java index 997d5b59fd4e6..0c02503cc9c7d 100644 --- a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/GridTcpCommunicationSpiConcurrentConnectSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/GridTcpCommunicationSpiConcurrentConnectSelfTest.java @@ -434,7 +434,7 @@ private void startSpis(MessageListener lsnr) throws Exception { GridSpiTestContext ctx = initSpiContext(); ctx.messageFactory(new IgniteMessageFactoryImpl( - new MessageFactoryProvider[] {new CoreMessagesProvider(jdk(), jdk(), U.gridClassLoader()), GRID_TEST_MESSAGE_FACTORY}) + new MessageFactoryProvider[] {new CoreMessagesProvider(jdk(), jdk()), GRID_TEST_MESSAGE_FACTORY}) ); ctx.setLocalNode(node); diff --git a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/GridTcpCommunicationSpiConfigSelfTest.java b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/GridTcpCommunicationSpiConfigSelfTest.java index 3f2d90924bf28..ad5805e0bb423 100644 --- a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/GridTcpCommunicationSpiConfigSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/GridTcpCommunicationSpiConfigSelfTest.java @@ -252,7 +252,7 @@ private TcpCommunicationSpi initializeSpi(GridSpiTestContext ctx, node.setId(rsrcs.getNodeId()); ctx.messageFactory(new IgniteMessageFactoryImpl(new MessageFactoryProvider[]{ - new CoreMessagesProvider(jdk(), jdk(), U.gridClassLoader()), GRID_TEST_MESSAGE_FACTORY})); + new CoreMessagesProvider(jdk(), jdk()), GRID_TEST_MESSAGE_FACTORY})); ctx.setLocalNode(node); diff --git a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/GridTcpCommunicationSpiMultithreadedSelfTest.java b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/GridTcpCommunicationSpiMultithreadedSelfTest.java index c043c068fc434..2d1f084daf988 100644 --- a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/GridTcpCommunicationSpiMultithreadedSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/GridTcpCommunicationSpiMultithreadedSelfTest.java @@ -468,7 +468,7 @@ private int getSpiCount() { GridSpiTestContext ctx = initSpiContext(); ctx.messageFactory(new IgniteMessageFactoryImpl( - new MessageFactoryProvider[] {new CoreMessagesProvider(jdk(), jdk(), U.gridClassLoader()), GRID_TEST_MESSAGE_FACTORY}) + new MessageFactoryProvider[] {new CoreMessagesProvider(jdk(), jdk()), GRID_TEST_MESSAGE_FACTORY}) ); ctx.timeoutProcessor(timeoutProcessor); diff --git a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/GridTcpCommunicationSpiRecoveryAckSelfTest.java b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/GridTcpCommunicationSpiRecoveryAckSelfTest.java index 56c6daceca5d2..a56a636b49be0 100644 --- a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/GridTcpCommunicationSpiRecoveryAckSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/GridTcpCommunicationSpiRecoveryAckSelfTest.java @@ -400,7 +400,7 @@ private void startSpis(int ackCnt, int idleTimeout, int queueLimit) throws Excep GridSpiTestContext ctx = initSpiContext(); ctx.messageFactory(new IgniteMessageFactoryImpl( - new MessageFactoryProvider[] {new CoreMessagesProvider(jdk(), jdk(), U.gridClassLoader()), GRID_TEST_MESSAGE_FACTORY}) + new MessageFactoryProvider[] {new CoreMessagesProvider(jdk(), jdk()), GRID_TEST_MESSAGE_FACTORY}) ); ctx.setLocalNode(node); diff --git a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/GridTcpCommunicationSpiRecoverySelfTest.java b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/GridTcpCommunicationSpiRecoverySelfTest.java index d4f00e425a428..e3ef6213d111f 100644 --- a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/GridTcpCommunicationSpiRecoverySelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/GridTcpCommunicationSpiRecoverySelfTest.java @@ -729,7 +729,7 @@ private void startSpis() throws Exception { GridSpiTestContext ctx = initSpiContext(); ctx.messageFactory(new IgniteMessageFactoryImpl( - new MessageFactoryProvider[] {new CoreMessagesProvider(jdk(), jdk(), U.gridClassLoader()), GRID_TEST_MESSAGE_FACTORY}) + new MessageFactoryProvider[] {new CoreMessagesProvider(jdk(), jdk()), GRID_TEST_MESSAGE_FACTORY}) ); ctx.setLocalNode(node); diff --git a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/IgniteTcpCommunicationRecoveryAckClosureSelfTest.java b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/IgniteTcpCommunicationRecoveryAckClosureSelfTest.java index 58a321e21c8a9..28420e04479ba 100644 --- a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/IgniteTcpCommunicationRecoveryAckClosureSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/IgniteTcpCommunicationRecoveryAckClosureSelfTest.java @@ -453,7 +453,7 @@ private void startSpis(int ackCnt, int idleTimeout, int queueLimit) throws Excep GridSpiTestContext ctx = initSpiContext(); ctx.messageFactory(new IgniteMessageFactoryImpl( - new MessageFactoryProvider[] {new CoreMessagesProvider(jdk(), jdk(), U.gridClassLoader()), GRID_TEST_MESSAGE_FACTORY}) + new MessageFactoryProvider[] {new CoreMessagesProvider(jdk(), jdk()), GRID_TEST_MESSAGE_FACTORY}) ); ctx.setLocalNode(node); diff --git a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/TcpCommunicationSpiSkipMessageSendTest.java b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/TcpCommunicationSpiSkipMessageSendTest.java index aeba1e4d7c136..a9ea6d824db20 100644 --- a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/TcpCommunicationSpiSkipMessageSendTest.java +++ b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/TcpCommunicationSpiSkipMessageSendTest.java @@ -278,7 +278,7 @@ class CustomDiscoverySpi extends TcpDiscoverySpi { private final CountDownLatch netDisabledLatch = new CountDownLatch(1); /** {@inheritDoc} */ - @Override protected T readMessage(TcpDiscoveryIoSession ses, + @Override protected T readMessage(TcpDiscoveryIoSession ses, long timeout) throws IOException, IgniteCheckedException { if (netDisabled) { U.sleep(timeout); diff --git a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/TestDelayMessage.java b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/TestDelayMessage.java index 4ed72c9905f40..70c8f724b60a7 100644 --- a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/TestDelayMessage.java +++ b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/TestDelayMessage.java @@ -17,21 +17,12 @@ package org.apache.ignite.spi.communication.tcp; -import org.apache.ignite.IgniteCheckedException; -import org.apache.ignite.internal.IgniteInterruptedCheckedException; -import org.apache.ignite.internal.MarshallableMessage; -import org.apache.ignite.internal.Order; -import org.apache.ignite.internal.util.typedef.internal.U; -import org.apache.ignite.marshaller.Marshaller; +import org.apache.ignite.plugin.extensions.communication.Message; /** Test message. */ -public class TestDelayMessage implements MarshallableMessage { +public class TestDelayMessage implements Message { /** */ - @Order(0) - int val; - - /** */ - private final int writeDelay; + final int writeDelay; /** */ public TestDelayMessage(int writeDelay) { @@ -42,21 +33,4 @@ public TestDelayMessage(int writeDelay) { public TestDelayMessage() { this(0); } - - /** {@inheritDoc} */ - @Override public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { - if (writeDelay > 0) { - try { - U.sleep(writeDelay); - } - catch (IgniteInterruptedCheckedException ignored) { - // No-op. - } - } - } - - /** {@inheritDoc} */ - @Override public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { - // No-op. - } } diff --git a/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/TestDelayMessageSerializer.java b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/TestDelayMessageSerializer.java new file mode 100644 index 0000000000000..f1e69422a9337 --- /dev/null +++ b/modules/core/src/test/java/org/apache/ignite/spi/communication/tcp/TestDelayMessageSerializer.java @@ -0,0 +1,53 @@ +/* + * 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.spi.communication.tcp; + +import org.apache.ignite.internal.IgniteInterruptedCheckedException; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.plugin.extensions.communication.MessageReader; +import org.apache.ignite.plugin.extensions.communication.MessageSerializer; +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 { + /** {@inheritDoc} */ + @Override public boolean writeTo(TestDelayMessage msg, MessageWriter writer) { + if (!writer.isHeaderWritten()) { + if (!writer.writeHeader(msg.directType())) + return false; + + writer.onHeaderWritten(); + } + + if (msg.writeDelay > 0) { + try { + U.sleep(msg.writeDelay); + } + catch (IgniteInterruptedCheckedException ignored) { + // No-op. + } + } + + return true; + } + + /** {@inheritDoc} */ + @Override public boolean readFrom(TestDelayMessage msg, MessageReader reader) { + return true; + } +} diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/BlockTcpDiscoverySpi.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/BlockTcpDiscoverySpi.java index 00ed5f205abd4..3c0445f0f94a8 100644 --- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/BlockTcpDiscoverySpi.java +++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/BlockTcpDiscoverySpi.java @@ -54,7 +54,7 @@ private synchronized void apply(ClusterNode addr, TcpDiscoveryAbstractMessage ms TcpDiscoveryCustomEventMessage cm = (TcpDiscoveryCustomEventMessage)msg; try { - cm.finishUnmarshal(marshaller(), U.gridClassLoader()); + cm.unmarshal(marshaller(), U.gridClassLoader()); assertNotNull(cm.message()); } diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/DiscoveryUnmarshalVulnerabilityTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/DiscoveryUnmarshalVulnerabilityTest.java index 830e9aa27e4c5..62d194d297050 100644 --- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/DiscoveryUnmarshalVulnerabilityTest.java +++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/DiscoveryUnmarshalVulnerabilityTest.java @@ -26,15 +26,21 @@ import java.net.Socket; import java.nio.ByteBuffer; import java.util.concurrent.atomic.AtomicBoolean; +import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.internal.CoreMessagesProvider; +import org.apache.ignite.internal.GridKernalContext; import org.apache.ignite.internal.direct.DirectMessageWriter; +import org.apache.ignite.internal.managers.communication.IgniteMessageFactory; +import org.apache.ignite.internal.managers.communication.MessageMarshalling; import org.apache.ignite.internal.plugin.AbstractMarshallableMessageFactoryProvider; +import org.apache.ignite.internal.processors.cache.CacheObjectContext; import org.apache.ignite.internal.util.IgniteUtils; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.marshaller.Marshallers; import org.apache.ignite.plugin.extensions.communication.MessageFactory; import org.apache.ignite.plugin.extensions.communication.MessageFactoryProvider; +import org.apache.ignite.plugin.extensions.communication.MessageMarshaller; import org.apache.ignite.plugin.extensions.communication.MessageReader; import org.apache.ignite.plugin.extensions.communication.MessageSerializer; import org.apache.ignite.plugin.extensions.communication.MessageWriter; @@ -48,6 +54,7 @@ import static org.apache.ignite.IgniteSystemProperties.IGNITE_ENABLE_OBJECT_INPUT_FILTER_AUTOCONFIGURATION; import static org.apache.ignite.IgniteSystemProperties.IGNITE_MARSHALLER_BLACKLIST; import static org.apache.ignite.IgniteSystemProperties.IGNITE_MARSHALLER_WHITELIST; +import static org.apache.ignite.testframework.GridTestUtils.loadMarshaller; import static org.apache.ignite.testframework.GridTestUtils.loadSerializer; /** @@ -81,18 +88,19 @@ public class DiscoveryUnmarshalVulnerabilityTest extends GridCommonAbstractTest /** {@inheritDoc} */ @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { MessageFactoryProvider msgFactoryProvider = new AbstractMarshallableMessageFactoryProvider() { - @Override public void registerAll(MessageFactory factory) { + @Override public void registerAll(IgniteMessageFactory factory) { factory.register( - CoreMessagesProvider.MAX_MESSAGE_ID + 1, + (short)(CoreMessagesProvider.MAX_MESSAGE_ID + 1), ExploitMessage::new, - new MessageSerializerWrapper(this)); + new MessageSerializerWrapper(), + new MessageMarshallerWrapper(this)); } }; IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); TestTcpDiscoverySpi discoSpi = new TestTcpDiscoverySpi(); - discoSpi.messageFactory(msgFactoryProvider, cfg); + discoSpi.messageFactory(msgFactoryProvider); lsnr = LogListener.matches("Invalid message type").build(); @@ -214,7 +222,7 @@ private void attack(byte[] data) throws IOException { } /** */ - private byte[] serializedMessage() { + private byte[] serializedMessage() throws IgniteCheckedException { ByteBuffer buf = ByteBuffer.allocate(4096); MessageFactory msgFactory = ((TcpDiscoverySpi)grid().configuration().getDiscoverySpi()).messageFactory(); @@ -222,7 +230,11 @@ private byte[] serializedMessage() { DirectMessageWriter writer = new DirectMessageWriter(msgFactory); writer.setBuffer(buf); - writer.writeMessage(new ExploitMessage(new Exploit())); + ExploitMessage msg = new ExploitMessage(new Exploit()); + + MessageMarshalling.marshal(msg, grid().context(), null); + + writer.writeMessage(msg); return buf.flip().compact().array(); } @@ -239,6 +251,35 @@ private void readObject(ObjectInputStream is) throws ClassNotFoundException, IOE /** */ private static class MessageSerializerWrapper implements MessageSerializer { + /** */ + private final AtomicBoolean init = new AtomicBoolean(true); + + /** */ + private MessageSerializer serde; + + /** {@inheritDoc} */ + @Override public boolean writeTo(ExploitMessage msg, MessageWriter writer) { + initIfNecessary(); + + return serde.writeTo(msg, writer); + } + + /** {@inheritDoc} */ + @Override public boolean readFrom(ExploitMessage msg, MessageReader reader) { + initIfNecessary(); + + return serde.readFrom(msg, reader); + } + + /** */ + private void initIfNecessary() { + if (init.get() && init.compareAndSet(true, false)) + serde = loadSerializer(ExploitMessage.class); + } + } + + /** Lazily-initialized {@link MessageMarshaller} wrapper resolved from the plugin provider. */ + private static class MessageMarshallerWrapper implements MessageMarshaller { /** */ private final AbstractMarshallableMessageFactoryProvider provider; @@ -246,33 +287,40 @@ private static class MessageSerializerWrapper implements MessageSerializer serde; + private MessageMarshaller marsh; /** */ - private MessageSerializerWrapper(AbstractMarshallableMessageFactoryProvider provider) { + private MessageMarshallerWrapper(AbstractMarshallableMessageFactoryProvider provider) { this.provider = provider; } /** {@inheritDoc} */ - @Override public boolean writeTo(ExploitMessage msg, MessageWriter writer) { + @Override public void marshal(ExploitMessage msg, GridKernalContext kctx, CacheObjectContext nested) + throws IgniteCheckedException { initIfNecessary(); - return serde.writeTo(msg, writer); + marsh.marshal(msg, kctx, nested); } /** {@inheritDoc} */ - @Override public boolean readFrom(ExploitMessage msg, MessageReader reader) { + @Override public void unmarshal(ExploitMessage msg, GridKernalContext kctx, CacheObjectContext nested, ClassLoader clsLdr) + throws IgniteCheckedException { initIfNecessary(); - return serde.readFrom(msg, reader); + marsh.unmarshal(msg, kctx, nested, clsLdr); + } + + /** {@inheritDoc} */ + @Override public void unmarshal(ExploitMessage msg, GridKernalContext kctx) throws IgniteCheckedException { + initIfNecessary(); + + marsh.unmarshal(msg, kctx); } /** */ private void initIfNecessary() { if (init.get() && init.compareAndSet(true, false)) - serde = loadSerializer(ExploitMessage.class, - U.field(provider, "dfltMarsh"), - U.field(provider, "resolvedClsLdr")); + marsh = loadMarshaller(ExploitMessage.class, U.field(provider, "dfltMarsh")); } } } diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/ExploitMessage.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/ExploitMessage.java index 182f91f826289..136f1946230ce 100644 --- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/ExploitMessage.java +++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/ExploitMessage.java @@ -41,12 +41,12 @@ public ExploitMessage(Exploit exploit) { } /** {@inheritDoc} */ - @Override public void prepareMarshal(Marshaller marsh) throws IgniteCheckedException { + @Override public void marshal(Marshaller marsh) throws IgniteCheckedException { exploitBytes = marsh.marshal(exploit); } /** {@inheritDoc} */ - @Override public void finishUnmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { + @Override public void unmarshal(Marshaller marsh, ClassLoader clsLdr) throws IgniteCheckedException { exploit = marsh.unmarshal(exploitBytes, clsLdr); } } diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpClientDiscoverySpiFailureTimeoutSelfTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpClientDiscoverySpiFailureTimeoutSelfTest.java index 10645f5fc25d6..49ba4f269821d 100644 --- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpClientDiscoverySpiFailureTimeoutSelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpClientDiscoverySpiFailureTimeoutSelfTest.java @@ -36,6 +36,7 @@ import org.apache.ignite.internal.util.typedef.X; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgnitePredicate; +import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoveryNode; import org.apache.ignite.spi.discovery.tcp.ipfinder.vm.TcpDiscoveryVmIpFinder; import org.apache.ignite.spi.discovery.tcp.messages.TcpDiscoveryAbstractMessage; @@ -516,7 +517,7 @@ private static class TestTcpDiscoverySpi2 extends TcpDiscoverySpi { } /** {@inheritDoc} */ - @Override protected T readMessage(TcpDiscoveryIoSession ses, long timeout) + @Override protected T readMessage(TcpDiscoveryIoSession ses, long timeout) throws IOException, IgniteCheckedException { long currTimeout = getLocalNode().isClient() ? clientFailureDetectionTimeout() : failureDetectionTimeout(); diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySelfTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySelfTest.java index 4920d029538a6..ac7901471fcba 100644 --- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySelfTest.java +++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySelfTest.java @@ -2647,7 +2647,7 @@ private static class TestCustomerEventAckSpi extends TcpDiscoverySpi { try { TcpDiscoveryCustomEventMessage evtMsg = (TcpDiscoveryCustomEventMessage)msg; - evtMsg.finishUnmarshal(marshaller(), U.gridClassLoader()); + evtMsg.unmarshal(marshaller(), U.gridClassLoader()); DiscoveryCustomMessage custMsg = U.unwrapCustomMessage(evtMsg.message()); diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySslSecuredUnsecuredTest.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySslSecuredUnsecuredTest.java index dcf9931ef9236..79b6962db51e6 100644 --- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySslSecuredUnsecuredTest.java +++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TcpDiscoverySslSecuredUnsecuredTest.java @@ -23,6 +23,7 @@ import javax.net.ssl.SSLException; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.spi.discovery.tcp.ipfinder.TcpDiscoveryIpFinder; import org.apache.ignite.testframework.GridTestUtils; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; @@ -174,7 +175,7 @@ private FailDiscoverySpi(final boolean plain) { } /** {@inheritDoc} */ - @Override protected T readMessage(final TcpDiscoveryIoSession ses, + @Override protected T readMessage(final TcpDiscoveryIoSession ses, final long timeout) throws IOException, IgniteCheckedException { if (cnt-- > 0) { if (plain) diff --git a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TestTcpDiscoverySpi.java b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TestTcpDiscoverySpi.java index cf6affb8b35b6..33a8af3ce29d9 100644 --- a/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TestTcpDiscoverySpi.java +++ b/modules/core/src/test/java/org/apache/ignite/spi/discovery/tcp/TestTcpDiscoverySpi.java @@ -20,11 +20,9 @@ import java.io.IOException; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.IgniteException; -import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.internal.CoreMessagesProvider; import org.apache.ignite.internal.managers.communication.IgniteMessageFactoryImpl; import org.apache.ignite.internal.managers.discovery.IgniteDiscoverySpiInternalListener; -import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.plugin.extensions.communication.MessageFactory; import org.apache.ignite.plugin.extensions.communication.MessageFactoryProvider; import org.apache.ignite.spi.discovery.DiscoverySpiCustomMessage; @@ -120,14 +118,13 @@ public void discoveryHook(DiscoveryHook discoHook) { * Otherwise, this method call will take no effect. * * @param msgFactoryProvider Discovery messages factory provider. - * @param cfg Ignite configuration. */ - public void messageFactory(MessageFactoryProvider msgFactoryProvider, IgniteConfiguration cfg) { + public void messageFactory(MessageFactoryProvider msgFactoryProvider) { provider = msgFactoryProvider; assert !started(); msgFactory = new IgniteMessageFactoryImpl(new MessageFactoryProvider[] { - new CoreMessagesProvider(jdk(), jdk(), U.resolveClassLoader(cfg)), + new CoreMessagesProvider(jdk(), jdk()), msgFactoryProvider }); } diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/GridSpiTestContext.java b/modules/core/src/test/java/org/apache/ignite/testframework/GridSpiTestContext.java index 8d55fa55bc669..db82f7095ab21 100644 --- a/modules/core/src/test/java/org/apache/ignite/testframework/GridSpiTestContext.java +++ b/modules/core/src/test/java/org/apache/ignite/testframework/GridSpiTestContext.java @@ -52,7 +52,6 @@ import org.apache.ignite.internal.processors.timeout.GridTimeoutProcessor; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.S; -import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteBiPredicate; import org.apache.ignite.lang.IgniteUuid; import org.apache.ignite.logger.NullLogger; @@ -554,8 +553,7 @@ public void triggerEvent(Event evt) { /** {@inheritDoc} */ @Override public MessageFactory messageFactory() { if (factory == null) - factory = new IgniteMessageFactoryImpl(new MessageFactoryProvider[]{new CoreMessagesProvider(jdk(), jdk(), - U.gridClassLoader())}); + factory = new IgniteMessageFactoryImpl(new MessageFactoryProvider[]{new CoreMessagesProvider(jdk(), jdk())}); return factory; } diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java b/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java index 01380265c96d7..66682fb1bd271 100644 --- a/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java +++ b/modules/core/src/test/java/org/apache/ignite/testframework/GridTestUtils.java @@ -131,6 +131,7 @@ import org.apache.ignite.lang.IgnitePredicate; import org.apache.ignite.marshaller.Marshaller; import org.apache.ignite.plugin.extensions.communication.Message; +import org.apache.ignite.plugin.extensions.communication.MessageMarshaller; import org.apache.ignite.plugin.extensions.communication.MessageSerializer; import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi; import org.apache.ignite.spi.communication.tcp.internal.GridNioServerWrapper; @@ -2704,28 +2705,36 @@ public static void skipCommNioServerRead(IgniteEx ignite, boolean skip) { } /** */ - public static MessageSerializer loadSerializer(Class msgCls, - @Nullable Marshaller dfltMarsh, @Nullable ClassLoader dfltClsLdr) { + public static MessageSerializer loadSerializer(Class msgCls) { try { - boolean isMarshallable = MarshallableMessage.class.isAssignableFrom(msgCls); + Class serCls = U.gridClassLoader() + .loadClass(msgCls.getPackage().getName() + "." + msgCls.getSimpleName() + "Serializer"); - String clsPref = msgCls.getSimpleName() + (isMarshallable ? "Marshallable" : ""); + return (MessageSerializer)U.newInstance(serCls); + } + catch (Exception e) { + throw new RuntimeException("Unable to find serializer for message: " + msgCls, e); + } + } - Class serCls = U.gridClassLoader() - .loadClass(msgCls.getPackage().getName() + "." + clsPref + "Serializer"); + /** Loads the generated {@code *Marshaller} class for {@code msgCls} and instantiates it with {@code dfltMarsh}. */ + public static MessageMarshaller loadMarshaller(Class msgCls, + @Nullable Marshaller dfltMarsh) { + try { + Class marshallerCls = U.gridClassLoader() + .loadClass(msgCls.getPackage().getName() + "." + msgCls.getSimpleName() + "Marshaller"); - Marshaller marsh = dfltMarsh != null ? dfltMarsh : jdk(); - ClassLoader cldLdr = dfltClsLdr != null ? dfltClsLdr : U.gridClassLoader(); + boolean isMarshallable = MarshallableMessage.class.isAssignableFrom(msgCls); - Object msgSer = isMarshallable ? - serCls.getConstructor(Marshaller.class, ClassLoader.class) - .newInstance(marsh, cldLdr) : - U.newInstance(serCls); + if (isMarshallable) { + Marshaller marsh = dfltMarsh != null ? dfltMarsh : jdk(); + return (MessageMarshaller)marshallerCls.getConstructor(Marshaller.class).newInstance(marsh); + } - return (MessageSerializer)msgSer; + return (MessageMarshaller)U.newInstance(marshallerCls); } catch (Exception e) { - throw new RuntimeException("Unable to find serializer for message: " + msgCls, e); + throw new RuntimeException("Unable to find marshaller for message: " + msgCls, e); } } diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java index 5029cb64a8953..c214494931ab7 100755 --- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java +++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridAbstractTest.java @@ -159,6 +159,7 @@ import static org.apache.ignite.IgniteSystemProperties.IGNITE_CLIENT_CACHE_CHANGE_MESSAGE_TIMEOUT; import static org.apache.ignite.IgniteSystemProperties.IGNITE_DISCO_FAILED_CLIENT_RECONNECT_DELAY; import static org.apache.ignite.IgniteSystemProperties.IGNITE_LOG_CLASSPATH_CONTENT_ON_STARTUP; +import static org.apache.ignite.IgniteSystemProperties.IGNITE_MESSAGE_UNMARSHAL_ONCE_CHECK; import static org.apache.ignite.IgniteSystemProperties.IGNITE_TEST_ENV; import static org.apache.ignite.IgniteSystemProperties.IGNITE_TO_STRING_INCLUDE_SENSITIVE; import static org.apache.ignite.IgniteSystemProperties.IGNITE_UPDATE_NOTIFIER; @@ -291,6 +292,7 @@ public String getName() { System.setProperty(IGNITE_CLIENT_CACHE_CHANGE_MESSAGE_TIMEOUT, "1000"); System.setProperty(IGNITE_LOG_CLASSPATH_CONTENT_ON_STARTUP, "false"); System.setProperty(IGNITE_TEST_ENV, "true"); + System.setProperty(IGNITE_MESSAGE_UNMARSHAL_ONCE_CHECK, "true"); S.setIncludeSensitiveSupplier(() -> getBoolean(IGNITE_TO_STRING_INCLUDE_SENSITIVE, true)); diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridTestKernalContext.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridTestKernalContext.java index 337dd99ed4f95..4edca1efe3b65 100644 --- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridTestKernalContext.java +++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/GridTestKernalContext.java @@ -34,6 +34,7 @@ import org.apache.ignite.internal.processors.plugin.IgnitePluginProcessor; import org.apache.ignite.internal.processors.resource.GridResourceProcessor; import org.apache.ignite.internal.processors.subscription.GridInternalSubscriptionProcessor; +import org.apache.ignite.internal.thread.context.OperationContextDispatcher; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.plugin.PluginProvider; @@ -79,6 +80,7 @@ public GridTestKernalContext(IgniteLogger log, IgniteConfiguration cfg) { GridTestUtils.setFieldValue(grid(), "cfg", config()); GridTestUtils.setFieldValue(grid(), "ctx", this); + GridTestUtils.setFieldValue(grid(), "operationCtxDispatcher", new OperationContextDispatcher()); config().setGridLogger(log); diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/IgniteMock.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/IgniteMock.java index a37e758c414ee..c419cf9bcbb1a 100644 --- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/IgniteMock.java +++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/IgniteMock.java @@ -152,10 +152,8 @@ public IgniteMock(String name, String locHost, UUID nodeId, Marshaller marshalle this.name = name; this.staticCfg = staticCfg; - ClassLoader lrd = staticCfg == null ? U.gridClassLoader() : U.resolveClassLoader(staticCfg); - msgFactory = new IgniteMessageFactoryImpl(new MessageFactoryProvider[] { - new CoreMessagesProvider(marshaller, marshaller, lrd)}); + new CoreMessagesProvider(marshaller, marshaller)}); try { kernalCtx = new StandaloneGridKernalContext(new GridTestLog4jLogger(), null) { diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java index a36175a09ebac..9d9455d00e862 100644 --- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java +++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteBasicTestSuite.java @@ -36,10 +36,13 @@ import org.apache.ignite.internal.IgniteSlowClientDetectionSelfTest; import org.apache.ignite.internal.TransactionsMXBeanImplTest; import org.apache.ignite.internal.codegen.IgniteDataTransferObjectProcessorTest; +import org.apache.ignite.internal.codegen.MarshallerCacheFreeUnmarshalTest; import org.apache.ignite.internal.codegen.MessageProcessorTest; +import org.apache.ignite.internal.codegen.MessageSerializationArchitectureTest; import org.apache.ignite.internal.managers.communication.CompressedMessageTest; import org.apache.ignite.internal.managers.communication.DefaultEnumMapperTest; import org.apache.ignite.internal.managers.communication.ErrorMessageSelfTest; +import org.apache.ignite.internal.managers.communication.GridIoManagerOrderedPoisonMessageTest; import org.apache.ignite.internal.managers.communication.MessageFactoryMarshallerInitializationTest; import org.apache.ignite.internal.processors.affinity.GridAffinityAssignmentV2Test; import org.apache.ignite.internal.processors.affinity.GridAffinityAssignmentV2TestNoOptimizations; @@ -52,6 +55,7 @@ import org.apache.ignite.internal.processors.cache.distributed.dht.topology.EvictPartitionInLogTest; import org.apache.ignite.internal.processors.cache.distributed.dht.topology.LogEvictionResultsTest; import org.apache.ignite.internal.processors.cache.distributed.dht.topology.PartitionEvictionOrderTest; +import org.apache.ignite.internal.processors.cache.query.GridCacheQueryResponseUnmarshalTest; import org.apache.ignite.internal.processors.cache.query.continuous.DiscoveryDataDeserializationFailureHanderTest; import org.apache.ignite.internal.processors.closure.GridClosureProcessorRemoteTest; import org.apache.ignite.internal.processors.closure.GridClosureProcessorSelfTest; @@ -72,6 +76,8 @@ import org.apache.ignite.messaging.GridMessagingSelfTest; import org.apache.ignite.messaging.IgniteMessagingSendAsyncTest; import org.apache.ignite.messaging.IgniteMessagingWithClientTest; +import org.apache.ignite.plugin.extensions.communication.MessageMarshalOnceTest; +import org.apache.ignite.plugin.extensions.communication.MessageUnmarshalOnceTest; import org.apache.ignite.spi.GridSpiLocalHostInjectionTest; import org.apache.ignite.testframework.junits.common.GridCommonAbstractTestSelfTest; import org.apache.ignite.testframework.junits.multijvm.JavaVersionCommandParserTest; @@ -153,6 +159,12 @@ ClientSessionOutboundQueueLimitTest.class, MessageProcessorTest.class, + MessageMarshalOnceTest.class, + GridIoManagerOrderedPoisonMessageTest.class, + MessageUnmarshalOnceTest.class, + GridCacheQueryResponseUnmarshalTest.class, + MarshallerCacheFreeUnmarshalTest.class, + MessageSerializationArchitectureTest.class, ErrorMessageSelfTest.class, DefaultEnumMapperTest.class, IgniteDataTransferObjectProcessorTest.class, diff --git a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite2.java b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite2.java index 6b6dd442dad8f..4a432501f3598 100644 --- a/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite2.java +++ b/modules/core/src/test/java/org/apache/ignite/testsuites/IgniteCacheTestSuite2.java @@ -85,6 +85,7 @@ import org.apache.ignite.internal.processors.cache.distributed.near.GridCachePartitionedTxSingleThreadedSelfTest; import org.apache.ignite.internal.processors.cache.distributed.near.GridCachePartitionedTxTimeoutSelfTest; import org.apache.ignite.internal.processors.cache.distributed.near.GridNearCacheStoreUpdateTest; +import org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxRecreateEvictionTest; import org.apache.ignite.internal.processors.cache.distributed.near.GridPartitionedBackupLoadSelfTest; import org.apache.ignite.internal.processors.cache.distributed.near.IgniteCacheContainsKeyNearSelfTest; import org.apache.ignite.internal.processors.cache.distributed.near.IgniteCacheNearTxRollbackTest; @@ -127,6 +128,7 @@ public static List> suite(Collection ignoredTests) { GridTestUtils.addTestIfNeeded(suite, GridCacheAtomicNearMultiNodeSelfTest.class, ignoredTests); GridTestUtils.addTestIfNeeded(suite, GridCacheNearReadersSelfTest.class, ignoredTests); GridTestUtils.addTestIfNeeded(suite, GridCacheAtomicNearReadersSelfTest.class, ignoredTests); + GridTestUtils.addTestIfNeeded(suite, GridNearTxRecreateEvictionTest.class, ignoredTests); GridTestUtils.addTestIfNeeded(suite, GridCachePartitionedGetAndTransformStoreSelfTest.class, ignoredTests); GridTestUtils.addTestIfNeeded(suite, GridNearCacheStoreUpdateTest.class, ignoredTests); GridTestUtils.addTestIfNeeded(suite, GridCachePartitionedBasicStoreMultiNodeSelfTest.class, ignoredTests); diff --git a/modules/core/src/test/resources/codegen/CustomMapperEnumFieldsMessageSerializer.java b/modules/core/src/test/resources/codegen/CustomMapperEnumFieldsMessageSerializer.java index db939d0825792..90c17f72b0306 100644 --- a/modules/core/src/test/resources/codegen/CustomMapperEnumFieldsMessageSerializer.java +++ b/modules/core/src/test/resources/codegen/CustomMapperEnumFieldsMessageSerializer.java @@ -68,4 +68,4 @@ public class CustomMapperEnumFieldsMessageSerializer implements MessageSerialize return true; } -} \ No newline at end of file +} diff --git a/modules/core/src/test/resources/codegen/NioFieldNeedsCtxMessage.java b/modules/core/src/test/resources/codegen/NioFieldNeedsCtxMessage.java new file mode 100644 index 0000000000000..829a1028fca9f --- /dev/null +++ b/modules/core/src/test/resources/codegen/NioFieldNeedsCtxMessage.java @@ -0,0 +1,40 @@ +/* + * 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.processors.cache.CacheObject; +import org.apache.ignite.plugin.extensions.communication.Message; + +public class NioFieldNeedsCtxMessage implements Message { + @NioField + @Order(0) + NestedCacheMessage nested; + + public short directType() { + return 0; + } + + public static class NestedCacheMessage implements Message { + @Order(0) + CacheObject val; + + public short directType() { + return 1; + } + } +} diff --git a/modules/core/src/test/resources/codegen/NioFieldOnNonMessageMessage.java b/modules/core/src/test/resources/codegen/NioFieldOnNonMessageMessage.java new file mode 100644 index 0000000000000..a8ac50154d9df --- /dev/null +++ b/modules/core/src/test/resources/codegen/NioFieldOnNonMessageMessage.java @@ -0,0 +1,30 @@ +/* + * 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.plugin.extensions.communication.Message; + +public class NioFieldOnNonMessageMessage implements Message { + @NioField + @Order(0) + int id; + + public short directType() { + return 0; + } +} diff --git a/modules/core/src/test/resources/codegen/TestCacheIdMessage.java b/modules/core/src/test/resources/codegen/TestCacheIdMessage.java new file mode 100644 index 0000000000000..749e5fd007b60 --- /dev/null +++ b/modules/core/src/test/resources/codegen/TestCacheIdMessage.java @@ -0,0 +1,47 @@ +/* + * 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 java.util.Collection; +import java.util.List; +import org.apache.ignite.internal.processors.cache.CacheObject; +import org.apache.ignite.internal.processors.cache.GridCacheIdMessage; +import org.apache.ignite.internal.processors.cache.KeyCacheObject; +import org.apache.ignite.internal.processors.cache.transactions.IgniteTxEntry; + +public class TestCacheIdMessage extends GridCacheIdMessage { + @Order(0) + KeyCacheObject key; + + @Order(1) + CacheObject val; + + @Order(2) + List keys; + + @Order(3) + Collection writes; + + public short directType() { + return 0; + } + + @Override public boolean addDeploymentInfo() { + return true; + } +} diff --git a/modules/core/src/test/resources/codegen/TestCacheIdMessageDeployer.java b/modules/core/src/test/resources/codegen/TestCacheIdMessageDeployer.java new file mode 100644 index 0000000000000..00200f0d59c18 --- /dev/null +++ b/modules/core/src/test/resources/codegen/TestCacheIdMessageDeployer.java @@ -0,0 +1,44 @@ +/* + * 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.IgniteCheckedException; +import org.apache.ignite.internal.TestCacheIdMessage; +import org.apache.ignite.internal.processors.cache.GridCacheContext; +import org.apache.ignite.internal.processors.cache.GridCacheMessageDeployer; +import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; + +/** + * This class is generated automatically. + * + * @see org.apache.ignite.internal.MessageProcessor + */ +public class TestCacheIdMessageDeployer implements GridCacheMessageDeployer { + /** */ + @Override public void deploy(TestCacheIdMessage msg, GridCacheSharedContext ctx) throws IgniteCheckedException { + GridCacheContext cctx = ctx.cacheContext(msg.cacheId()); + + msg.deployCacheObject(msg.key, cctx); + + msg.deployCacheObject(msg.val, cctx); + + msg.deployCacheObjects(msg.keys, cctx); + + msg.deployTx(msg.writes, ctx); + } +} \ No newline at end of file diff --git a/modules/core/src/test/resources/codegen/TestCollectionsMessage.java b/modules/core/src/test/resources/codegen/TestCollectionsMessage.java index 312d5e91f8122..16d384b8e6a22 100644 --- a/modules/core/src/test/resources/codegen/TestCollectionsMessage.java +++ b/modules/core/src/test/resources/codegen/TestCollectionsMessage.java @@ -22,6 +22,7 @@ import java.util.Set; import java.util.UUID; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; +import org.apache.ignite.internal.processors.cache.CacheObject; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.util.GridLongList; import org.apache.ignite.lang.IgniteUuid; @@ -103,6 +104,9 @@ public class TestCollectionsMessage implements Message { @Order(24) Set bitSetSet; + @Order(25) + Set cacheObjectSet; + public short directType() { return 0; } diff --git a/modules/core/src/test/resources/codegen/TestCollectionsMessageMarshaller.java b/modules/core/src/test/resources/codegen/TestCollectionsMessageMarshaller.java new file mode 100644 index 0000000000000..65756b4e70f3d --- /dev/null +++ b/modules/core/src/test/resources/codegen/TestCollectionsMessageMarshaller.java @@ -0,0 +1,57 @@ +/* + * 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 java.util.Collection; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.TestCollectionsMessage; +import org.apache.ignite.internal.processors.cache.CacheObject; +import org.apache.ignite.internal.processors.cache.CacheObjectContext; +import org.apache.ignite.plugin.extensions.communication.MessageMarshaller; + +/** + * This class is generated automatically. + * + * @see org.apache.ignite.internal.MessageProcessor + */ +public class TestCollectionsMessageMarshaller implements MessageMarshaller { + /** */ + @Override public void marshal(TestCollectionsMessage msg, GridKernalContext kctx, CacheObjectContext cacheObjCtx) throws IgniteCheckedException { + CacheObjectContext ctx = cacheObjCtx; + + if (msg.cacheObjectSet != null) { + for (CacheObject e : (Collection)msg.cacheObjectSet) { + if (e != null && ctx != null) + e.marshal(ctx); + } + } + } + + /** */ + @Override public void unmarshal(TestCollectionsMessage msg, GridKernalContext kctx, CacheObjectContext cacheObjCtx, ClassLoader clsLdr) throws IgniteCheckedException { + CacheObjectContext ctx = cacheObjCtx; + + if (msg.cacheObjectSet != null) { + for (CacheObject e : (Collection)msg.cacheObjectSet) { + if (e != null && ctx != null) + e.unmarshal(ctx, clsLdr); + } + } + } +} \ No newline at end of file diff --git a/modules/core/src/test/resources/codegen/TestCollectionsMessageSerializer.java b/modules/core/src/test/resources/codegen/TestCollectionsMessageSerializer.java index 28444ed73f487..bfd66a60f532a 100644 --- a/modules/core/src/test/resources/codegen/TestCollectionsMessageSerializer.java +++ b/modules/core/src/test/resources/codegen/TestCollectionsMessageSerializer.java @@ -32,55 +32,57 @@ */ public class TestCollectionsMessageSerializer implements MessageSerializer { /** */ - private final static MessageCollectionType affTopVersionListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.AFFINITY_TOPOLOGY_VERSION), false); + private static final MessageCollectionType affTopVersionListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.AFFINITY_TOPOLOGY_VERSION), false); /** */ - private final static MessageCollectionType bitSetListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.BIT_SET), false); + private static final MessageCollectionType bitSetListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.BIT_SET), false); /** */ - private final static MessageCollectionType bitSetSetCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.BIT_SET), true); + private static final MessageCollectionType bitSetSetCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.BIT_SET), true); /** */ - private final static MessageCollectionType booleanArrayListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.BOOLEAN_ARR), false); + private static final MessageCollectionType booleanArrayListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.BOOLEAN_ARR), false); /** */ - private final static MessageCollectionType boxedBooleanListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.BOOLEAN), false); + private static final MessageCollectionType boxedBooleanListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.BOOLEAN), false); /** */ - private final static MessageCollectionType boxedByteListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.BYTE), false); + private static final MessageCollectionType boxedByteListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.BYTE), false); /** */ - private final static MessageCollectionType boxedCharListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.CHAR), false); + private static final MessageCollectionType boxedCharListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.CHAR), false); /** */ - private final static MessageCollectionType boxedDoubleListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.DOUBLE), false); + private static final MessageCollectionType boxedDoubleListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.DOUBLE), false); /** */ - private final static MessageCollectionType boxedFloatListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.FLOAT), false); + private static final MessageCollectionType boxedFloatListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.FLOAT), false); /** */ - private final static MessageCollectionType boxedIntListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.INT), false); + private static final MessageCollectionType boxedIntListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.INT), false); /** */ - private final static MessageCollectionType boxedIntegerSetCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.INT), true); + private static final MessageCollectionType boxedIntegerSetCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.INT), true); /** */ - private final static MessageCollectionType boxedLongListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.LONG), false); + private static final MessageCollectionType boxedLongListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.LONG), false); /** */ - private final static MessageCollectionType boxedShortListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.SHORT), false); + private static final MessageCollectionType boxedShortListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.SHORT), false); /** */ - private final static MessageCollectionType byteArrayListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.BYTE_ARR), false); + private static final MessageCollectionType byteArrayListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.BYTE_ARR), false); /** */ - private final static MessageCollectionType charArrayListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.CHAR_ARR), false); + private static final MessageCollectionType cacheObjectSetCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.CACHE_OBJECT), true); /** */ - private final static MessageCollectionType doubleArrayListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.DOUBLE_ARR), false); + private static final MessageCollectionType charArrayListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.CHAR_ARR), false); /** */ - private final static MessageCollectionType floatArrayListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.FLOAT_ARR), false); + private static final MessageCollectionType doubleArrayListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.DOUBLE_ARR), false); /** */ - private final static MessageCollectionType gridLongListListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.GRID_LONG_LIST), false); + private static final MessageCollectionType floatArrayListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.FLOAT_ARR), false); /** */ - private final static MessageCollectionType igniteUuidListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.IGNITE_UUID), false); + private static final MessageCollectionType gridLongListListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.GRID_LONG_LIST), false); /** */ - private final static MessageCollectionType intArrayListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.INT_ARR), false); + private static final MessageCollectionType igniteUuidListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.IGNITE_UUID), false); /** */ - private final static MessageCollectionType longArrayListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.LONG_ARR), false); + private static final MessageCollectionType intArrayListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.INT_ARR), false); /** */ - private final static MessageCollectionType messageListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.GRID_CACHE_VERSION), false); + private static final MessageCollectionType longArrayListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.LONG_ARR), false); /** */ - private final static MessageCollectionType shortArrayListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.SHORT_ARR), false); + private static final MessageCollectionType messageListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.GRID_CACHE_VERSION), false); /** */ - private final static MessageCollectionType stringListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.STRING), false); + private static final MessageCollectionType shortArrayListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.SHORT_ARR), false); /** */ - private final static MessageCollectionType uuidListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.UUID), false); + private static final MessageCollectionType stringListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.STRING), false); + /** */ + private static final MessageCollectionType uuidListCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.UUID), false); /** */ @Override public boolean writeTo(TestCollectionsMessage msg, MessageWriter writer) { @@ -241,6 +243,12 @@ public class TestCollectionsMessageSerializer implements MessageSerializer ctx) throws IgniteCheckedException; +public class TestDeployableMessage extends GridCacheIdMessage implements DeployableMessage { + @Order(0) + KeyCacheObject key; - /** - * Prepares the message before processing. - * - * @param ctx Cache shared context. - * @param clsLdr Class loader. - */ - void finishUnmarshal(GridCacheSharedContext ctx, ClassLoader clsLdr) throws IgniteCheckedException; + public short directType() { + return 0; + } + + @Override public boolean addDeploymentInfo() { + return true; + } + + @Override public void deploy(GridCacheSharedContext ctx) throws IgniteCheckedException { + // Custom deployment that cannot be inferred from field types. + } } diff --git a/modules/core/src/test/resources/codegen/TestDeployableMessageDeployer.java b/modules/core/src/test/resources/codegen/TestDeployableMessageDeployer.java new file mode 100644 index 0000000000000..f4705cafac8eb --- /dev/null +++ b/modules/core/src/test/resources/codegen/TestDeployableMessageDeployer.java @@ -0,0 +1,40 @@ +/* + * 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.IgniteCheckedException; +import org.apache.ignite.internal.TestDeployableMessage; +import org.apache.ignite.internal.processors.cache.GridCacheContext; +import org.apache.ignite.internal.processors.cache.GridCacheMessageDeployer; +import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; + +/** + * This class is generated automatically. + * + * @see org.apache.ignite.internal.MessageProcessor + */ +public class TestDeployableMessageDeployer implements GridCacheMessageDeployer { + /** */ + @Override public void deploy(TestDeployableMessage msg, GridCacheSharedContext ctx) throws IgniteCheckedException { + GridCacheContext cctx = ctx.cacheContext(msg.cacheId()); + + msg.deployCacheObject(msg.key, cctx); + + msg.deploy(ctx); + } +} \ No newline at end of file diff --git a/modules/core/src/test/resources/codegen/TestMapMessage.java b/modules/core/src/test/resources/codegen/TestMapMessage.java index 71a20da923709..f33fd2cc0a679 100644 --- a/modules/core/src/test/resources/codegen/TestMapMessage.java +++ b/modules/core/src/test/resources/codegen/TestMapMessage.java @@ -22,6 +22,8 @@ import java.util.Map; import java.util.UUID; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; +import org.apache.ignite.internal.processors.cache.CacheObject; +import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.util.GridLongList; import org.apache.ignite.lang.IgniteUuid; @@ -103,6 +105,9 @@ public class TestMapMessage implements Message { @Order(24) Map>> gridlistDoubleMapUuidMap; + @Order(25) + Map>> gridCacheObjectMap; + public short directType() { return 0; } diff --git a/modules/core/src/test/resources/codegen/TestMapMessageMarshaller.java b/modules/core/src/test/resources/codegen/TestMapMessageMarshaller.java new file mode 100644 index 0000000000000..240a45f59e975 --- /dev/null +++ b/modules/core/src/test/resources/codegen/TestMapMessageMarshaller.java @@ -0,0 +1,84 @@ +/* + * 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 java.util.Collection; +import java.util.List; +import java.util.Map; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.TestMapMessage; +import org.apache.ignite.internal.processors.cache.CacheObject; +import org.apache.ignite.internal.processors.cache.CacheObjectContext; +import org.apache.ignite.internal.processors.cache.KeyCacheObject; +import org.apache.ignite.plugin.extensions.communication.MessageMarshaller; + +/** + * This class is generated automatically. + * + * @see org.apache.ignite.internal.MessageProcessor + */ +public class TestMapMessageMarshaller implements MessageMarshaller { + /** */ + @Override public void marshal(TestMapMessage msg, GridKernalContext kctx, CacheObjectContext cacheObjCtx) throws IgniteCheckedException { + CacheObjectContext ctx = cacheObjCtx; + + if (msg.gridCacheObjectMap != null) { + for (KeyCacheObject e : ((Collection)msg.gridCacheObjectMap.keySet())) { + if (e != null && ctx != null) + e.marshal(ctx); + } + for (Map e : ((Collection)msg.gridCacheObjectMap.values())) { + if (e != null) { + for (List e1 : ((Collection)e.values())) { + if (e1 != null) { + for (CacheObject e2 : (Collection)e1) { + if (e2 != null && ctx != null) + e2.marshal(ctx); + } + } + } + } + } + } + } + + /** */ + @Override public void unmarshal(TestMapMessage msg, GridKernalContext kctx, CacheObjectContext cacheObjCtx, ClassLoader clsLdr) throws IgniteCheckedException { + CacheObjectContext ctx = cacheObjCtx; + + if (msg.gridCacheObjectMap != null) { + for (KeyCacheObject e : ((Collection)msg.gridCacheObjectMap.keySet())) { + if (e != null && ctx != null) + e.unmarshal(ctx, clsLdr); + } + for (Map e : ((Collection)msg.gridCacheObjectMap.values())) { + if (e != null) { + for (List e1 : ((Collection)e.values())) { + if (e1 != null) { + for (CacheObject e2 : (Collection)e1) { + if (e2 != null && ctx != null) + e2.unmarshal(ctx, clsLdr); + } + } + } + } + } + } + } +} \ No newline at end of file diff --git a/modules/core/src/test/resources/codegen/TestMapMessageSerializer.java b/modules/core/src/test/resources/codegen/TestMapMessageSerializer.java index 26834fa5d2b21..d282801982b64 100644 --- a/modules/core/src/test/resources/codegen/TestMapMessageSerializer.java +++ b/modules/core/src/test/resources/codegen/TestMapMessageSerializer.java @@ -33,55 +33,57 @@ */ public class TestMapMessageSerializer implements MessageSerializer { /** */ - private final static MessageMapType affTopVersionIgniteUuidMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.AFFINITY_TOPOLOGY_VERSION), new MessageItemType(MessageCollectionItemType.IGNITE_UUID), false); + private static final MessageMapType affTopVersionIgniteUuidMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.AFFINITY_TOPOLOGY_VERSION), new MessageItemType(MessageCollectionItemType.IGNITE_UUID), false); /** */ - private final static MessageMapType bitSetUuidMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.BIT_SET), new MessageItemType(MessageCollectionItemType.UUID), false); + private static final MessageMapType bitSetUuidMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.BIT_SET), new MessageItemType(MessageCollectionItemType.UUID), false); /** */ - private final static MessageMapType booleanArrayBoxedLongMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.BOOLEAN_ARR), new MessageItemType(MessageCollectionItemType.LONG), false); + private static final MessageMapType booleanArrayBoxedLongMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.BOOLEAN_ARR), new MessageItemType(MessageCollectionItemType.LONG), false); /** */ - private final static MessageMapType boxedBooleanAffTopVersionMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.BOOLEAN), new MessageItemType(MessageCollectionItemType.AFFINITY_TOPOLOGY_VERSION), false); + private static final MessageMapType boxedBooleanAffTopVersionMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.BOOLEAN), new MessageItemType(MessageCollectionItemType.AFFINITY_TOPOLOGY_VERSION), false); /** */ - private final static MessageMapType boxedByteBoxedBooleanMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.BYTE), new MessageItemType(MessageCollectionItemType.BOOLEAN), false); + private static final MessageMapType boxedByteBoxedBooleanMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.BYTE), new MessageItemType(MessageCollectionItemType.BOOLEAN), false); /** */ - private final static MessageMapType boxedCharBoxedLongMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.CHAR), new MessageItemType(MessageCollectionItemType.LONG), false); + private static final MessageMapType boxedCharBoxedLongMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.CHAR), new MessageItemType(MessageCollectionItemType.LONG), false); /** */ - private final static MessageMapType boxedDoubleBoxedFloatMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.DOUBLE), new MessageItemType(MessageCollectionItemType.FLOAT), false); + private static final MessageMapType boxedDoubleBoxedFloatMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.DOUBLE), new MessageItemType(MessageCollectionItemType.FLOAT), false); /** */ - private final static MessageMapType boxedFloatBoxedCharMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.FLOAT), new MessageItemType(MessageCollectionItemType.CHAR), false); + private static final MessageMapType boxedFloatBoxedCharMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.FLOAT), new MessageItemType(MessageCollectionItemType.CHAR), false); /** */ - private final static MessageMapType boxedIntBoxedShortMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.INT), new MessageItemType(MessageCollectionItemType.SHORT), false); + private static final MessageMapType boxedIntBoxedShortMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.INT), new MessageItemType(MessageCollectionItemType.SHORT), false); /** */ - private final static MessageMapType boxedLongBoxedIntMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.LONG), new MessageItemType(MessageCollectionItemType.INT), false); + private static final MessageMapType boxedLongBoxedIntMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.LONG), new MessageItemType(MessageCollectionItemType.INT), false); /** */ - private final static MessageMapType boxedShortBoxedByteMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.SHORT), new MessageItemType(MessageCollectionItemType.BYTE), false); + private static final MessageMapType boxedShortBoxedByteMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.SHORT), new MessageItemType(MessageCollectionItemType.BYTE), false); /** */ - private final static MessageMapType byteArrayBooleanArrayMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.BYTE_ARR), new MessageItemType(MessageCollectionItemType.BOOLEAN_ARR), false); + private static final MessageMapType byteArrayBooleanArrayMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.BYTE_ARR), new MessageItemType(MessageCollectionItemType.BOOLEAN_ARR), false); /** */ - private final static MessageMapType charArrayLongArrayMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.CHAR_ARR), new MessageItemType(MessageCollectionItemType.LONG_ARR), false); + private static final MessageMapType charArrayLongArrayMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.CHAR_ARR), new MessageItemType(MessageCollectionItemType.LONG_ARR), false); /** */ - private final static MessageMapType doubleArrayFloatArrayMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.DOUBLE_ARR), new MessageItemType(MessageCollectionItemType.FLOAT_ARR), false); + private static final MessageMapType doubleArrayFloatArrayMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.DOUBLE_ARR), new MessageItemType(MessageCollectionItemType.FLOAT_ARR), false); /** */ - private final static MessageMapType floatArrayCharArrayMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.FLOAT_ARR), new MessageItemType(MessageCollectionItemType.CHAR_ARR), false); + private static final MessageMapType floatArrayCharArrayMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.FLOAT_ARR), new MessageItemType(MessageCollectionItemType.CHAR_ARR), false); /** */ - private final static MessageMapType gridLongListIntegerMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.GRID_LONG_LIST), new MessageItemType(MessageCollectionItemType.INT), false); + private static final MessageMapType gridCacheObjectMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.KEY_CACHE_OBJECT), new MessageMapType(new MessageItemType(MessageCollectionItemType.UUID), new MessageCollectionType(new MessageItemType(MessageCollectionItemType.CACHE_OBJECT), false), false), false); /** */ - private final static MessageMapType gridlistDoubleMapUuidMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.GRID_LONG_LIST), new MessageMapType(new MessageItemType(MessageCollectionItemType.UUID), new MessageCollectionType(new MessageItemType(MessageCollectionItemType.DOUBLE), false), false), false); + private static final MessageMapType gridLongListIntegerMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.GRID_LONG_LIST), new MessageItemType(MessageCollectionItemType.INT), false); /** */ - private final static MessageMapType igniteUuidBitSetMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.IGNITE_UUID), new MessageItemType(MessageCollectionItemType.BIT_SET), false); + private static final MessageMapType gridlistDoubleMapUuidMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.GRID_LONG_LIST), new MessageMapType(new MessageItemType(MessageCollectionItemType.UUID), new MessageCollectionType(new MessageItemType(MessageCollectionItemType.DOUBLE), false), false), false); /** */ - private final static MessageMapType intArrayShortArrayMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.INT_ARR), new MessageItemType(MessageCollectionItemType.SHORT_ARR), false); + private static final MessageMapType igniteUuidBitSetMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.IGNITE_UUID), new MessageItemType(MessageCollectionItemType.BIT_SET), false); /** */ - private final static MessageMapType integerGridLongListMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.INT), new MessageItemType(MessageCollectionItemType.GRID_LONG_LIST), false); + private static final MessageMapType intArrayShortArrayMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.INT_ARR), new MessageItemType(MessageCollectionItemType.SHORT_ARR), false); /** */ - private final static MessageMapType longArrayIntArrayMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.LONG_ARR), new MessageItemType(MessageCollectionItemType.INT_ARR), false); + private static final MessageMapType integerGridLongListMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.INT), new MessageItemType(MessageCollectionItemType.GRID_LONG_LIST), false); /** */ - private final static MessageMapType messageBoxedDoubleMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.GRID_CACHE_VERSION), new MessageItemType(MessageCollectionItemType.DOUBLE), false); + private static final MessageMapType longArrayIntArrayMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.LONG_ARR), new MessageItemType(MessageCollectionItemType.INT_ARR), false); /** */ - private final static MessageMapType shortArrayByteArrayMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.SHORT_ARR), new MessageItemType(MessageCollectionItemType.BYTE_ARR), false); + private static final MessageMapType messageBoxedDoubleMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.GRID_CACHE_VERSION), new MessageItemType(MessageCollectionItemType.DOUBLE), false); /** */ - private final static MessageMapType stringDoubleArrayMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.STRING), new MessageItemType(MessageCollectionItemType.DOUBLE_ARR), false); + private static final MessageMapType shortArrayByteArrayMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.SHORT_ARR), new MessageItemType(MessageCollectionItemType.BYTE_ARR), false); /** */ - private final static MessageMapType uuidStringMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.UUID), new MessageItemType(MessageCollectionItemType.STRING), false); + private static final MessageMapType stringDoubleArrayMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.STRING), new MessageItemType(MessageCollectionItemType.DOUBLE_ARR), false); + /** */ + private static final MessageMapType uuidStringMapCollDesc = new MessageMapType(new MessageItemType(MessageCollectionItemType.UUID), new MessageItemType(MessageCollectionItemType.STRING), false); /** */ @Override public boolean writeTo(TestMapMessage msg, MessageWriter writer) { @@ -242,6 +244,12 @@ public class TestMapMessageSerializer implements MessageSerializer nested) throws IgniteCheckedException { + GridCacheContext ctx = nested; + + msg.marshal(marshaller); + } + + /** */ + @Override public void unmarshal(TestMarshallableMessage msg, GridKernalContext kctx, GridCacheContext nested) throws IgniteCheckedException { + GridCacheContext ctx = nested; + + msg.unmarshal(marshaller, clsLdr); + } +} \ No newline at end of file diff --git a/modules/core/src/test/resources/codegen/TestMarshallableMessageMarshaller.java b/modules/core/src/test/resources/codegen/TestMarshallableMessageMarshaller.java new file mode 100644 index 0000000000000..1b6000e40b454 --- /dev/null +++ b/modules/core/src/test/resources/codegen/TestMarshallableMessageMarshaller.java @@ -0,0 +1,50 @@ +/* + * 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.IgniteCheckedException; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.TestMarshallableMessage; +import org.apache.ignite.internal.processors.cache.CacheObjectContext; +import org.apache.ignite.marshaller.Marshaller; +import org.apache.ignite.plugin.extensions.communication.MessageMarshaller; + +/** + * This class is generated automatically. + * + * @see org.apache.ignite.internal.MessageProcessor + */ +public class TestMarshallableMessageMarshaller implements MessageMarshaller { + /** */ + private final Marshaller marshaller; + + /** */ + public TestMarshallableMessageMarshaller(Marshaller marshaller) { + this.marshaller = marshaller; + } + + /** */ + @Override public void marshal(TestMarshallableMessage msg, GridKernalContext kctx, CacheObjectContext cacheObjCtx) throws IgniteCheckedException { + msg.marshal(marshaller); + } + + /** */ + @Override public void unmarshal(TestMarshallableMessage msg, GridKernalContext kctx, CacheObjectContext cacheObjCtx, ClassLoader clsLdr) throws IgniteCheckedException { + msg.unmarshal(marshaller, clsLdr); + } +} \ No newline at end of file diff --git a/modules/core/src/test/resources/codegen/TestMarshallableMessageSerializer.java b/modules/core/src/test/resources/codegen/TestMarshallableMessageSerializer.java new file mode 100644 index 0000000000000..04b0bbafe7124 --- /dev/null +++ b/modules/core/src/test/resources/codegen/TestMarshallableMessageSerializer.java @@ -0,0 +1,93 @@ +/* + * 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.TestMarshallableMessage; +import org.apache.ignite.plugin.extensions.communication.MessageReader; +import org.apache.ignite.plugin.extensions.communication.MessageSerializer; +import org.apache.ignite.plugin.extensions.communication.MessageWriter; + +/** + * This class is generated automatically. + * + * @see org.apache.ignite.internal.MessageProcessor + */ +public class TestMarshallableMessageSerializer implements MessageSerializer { + /** */ + @Override public boolean writeTo(TestMarshallableMessage msg, MessageWriter writer) { + if (!writer.isHeaderWritten()) { + if (!writer.writeHeader(msg.directType())) + return false; + + writer.onHeaderWritten(); + } + + switch (writer.state()) { + case 0: + if (!writer.writeInt(msg.iv)) + return false; + + writer.incrementState(); + + case 1: + if (!writer.writeString(msg.sv)) + return false; + + writer.incrementState(); + + case 2: + if (!writer.writeByteArray(msg.cstDataBytes)) + return false; + + writer.incrementState(); + } + + return true; + } + + /** */ + @Override public boolean readFrom(TestMarshallableMessage msg, MessageReader reader) { + switch (reader.state()) { + case 0: + msg.iv = reader.readInt(); + + if (!reader.isLastRead()) + return false; + + reader.incrementState(); + + case 1: + msg.sv = reader.readString(); + + if (!reader.isLastRead()) + return false; + + reader.incrementState(); + + case 2: + msg.cstDataBytes = reader.readByteArray(); + + if (!reader.isLastRead()) + return false; + + reader.incrementState(); + } + + return true; + } +} diff --git a/modules/core/src/test/resources/codegen/TestMarshalledCollectionMessage.java b/modules/core/src/test/resources/codegen/TestMarshalledCollectionMessage.java new file mode 100644 index 0000000000000..3efcd07d10e41 --- /dev/null +++ b/modules/core/src/test/resources/codegen/TestMarshalledCollectionMessage.java @@ -0,0 +1,34 @@ +/* + * 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 java.util.Set; +import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; +import org.apache.ignite.plugin.extensions.communication.Message; + +public class TestMarshalledCollectionMessage implements Message { + @Marshalled("keysArr") + Set keys; + + @Order(0) + GridCacheVersion[] keysArr; + + public short directType() { + return 0; + } +} diff --git a/modules/core/src/test/resources/codegen/TestMarshalledCollectionMessageMarshaller.java b/modules/core/src/test/resources/codegen/TestMarshalledCollectionMessageMarshaller.java new file mode 100644 index 0000000000000..2fc222b7f4af9 --- /dev/null +++ b/modules/core/src/test/resources/codegen/TestMarshalledCollectionMessageMarshaller.java @@ -0,0 +1,55 @@ +/* + * 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.IgniteCheckedException; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.TestMarshalledCollectionMessage; +import org.apache.ignite.internal.processors.cache.CacheObjectContext; +import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.plugin.extensions.communication.MessageMarshaller; + +/** + * This class is generated automatically. + * + * @see org.apache.ignite.internal.MessageProcessor + */ +public class TestMarshalledCollectionMessageMarshaller implements MessageMarshaller { + /** */ + @Override public void marshal(TestMarshalledCollectionMessage msg, GridKernalContext kctx, CacheObjectContext cacheObjCtx) throws IgniteCheckedException { + if (msg.keys != null && msg.keysArr == null) + msg.keysArr = msg.keys.toArray(new GridCacheVersion[0]); + } + + /** */ + @Override public void unmarshal(TestMarshalledCollectionMessage msg, GridKernalContext kctx, CacheObjectContext cacheObjCtx, ClassLoader clsLdr) throws IgniteCheckedException { + CacheObjectContext ctx = cacheObjCtx; + + if (msg.keysArr != null) { + msg.keys = U.newHashSet(msg.keysArr.length); + + for (GridCacheVersion e : msg.keysArr) { + + msg.keys.add(e); + } + + msg.keysArr = null; + } + } +} \ No newline at end of file diff --git a/modules/core/src/test/resources/codegen/TestMarshalledCollectionMessageSerializer.java b/modules/core/src/test/resources/codegen/TestMarshalledCollectionMessageSerializer.java new file mode 100644 index 0000000000000..c87f1bea77da2 --- /dev/null +++ b/modules/core/src/test/resources/codegen/TestMarshalledCollectionMessageSerializer.java @@ -0,0 +1,72 @@ +/* + * 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.TestMarshalledCollectionMessage; +import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; +import org.apache.ignite.plugin.extensions.communication.MessageArrayType; +import org.apache.ignite.plugin.extensions.communication.MessageCollectionItemType; +import org.apache.ignite.plugin.extensions.communication.MessageItemType; +import org.apache.ignite.plugin.extensions.communication.MessageReader; +import org.apache.ignite.plugin.extensions.communication.MessageSerializer; +import org.apache.ignite.plugin.extensions.communication.MessageWriter; + +/** + * This class is generated automatically. + * + * @see org.apache.ignite.internal.MessageProcessor + */ +public class TestMarshalledCollectionMessageSerializer implements MessageSerializer { + /** */ + private static final MessageArrayType keysArrCollDesc = new MessageArrayType(new MessageItemType(MessageCollectionItemType.GRID_CACHE_VERSION), GridCacheVersion.class); + + /** */ + @Override public boolean writeTo(TestMarshalledCollectionMessage msg, MessageWriter writer) { + if (!writer.isHeaderWritten()) { + if (!writer.writeHeader(msg.directType())) + return false; + + writer.onHeaderWritten(); + } + + switch (writer.state()) { + case 0: + if (!writer.writeObjectArray(msg.keysArr, keysArrCollDesc)) + return false; + + writer.incrementState(); + } + + return true; + } + + /** */ + @Override public boolean readFrom(TestMarshalledCollectionMessage msg, MessageReader reader) { + switch (reader.state()) { + case 0: + msg.keysArr = reader.readObjectArray(keysArrCollDesc); + + if (!reader.isLastRead()) + return false; + + reader.incrementState(); + } + + return true; + } +} \ No newline at end of file diff --git a/modules/core/src/test/resources/codegen/TestMarshalledMapMessage.java b/modules/core/src/test/resources/codegen/TestMarshalledMapMessage.java new file mode 100644 index 0000000000000..07d4ec4c35ccf --- /dev/null +++ b/modules/core/src/test/resources/codegen/TestMarshalledMapMessage.java @@ -0,0 +1,38 @@ +/* + * 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 java.util.Collection; +import java.util.Map; +import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; +import org.apache.ignite.plugin.extensions.communication.Message; + +public class TestMarshalledMapMessage implements Message { + @Marshalled(keys = "mapKeys", values = "mapVals") + Map theMap; + + @Order(0) + Collection mapKeys; + + @Order(1) + Collection mapVals; + + public short directType() { + return 0; + } +} diff --git a/modules/core/src/test/resources/codegen/TestMarshalledMapMessageMarshaller.java b/modules/core/src/test/resources/codegen/TestMarshalledMapMessageMarshaller.java new file mode 100644 index 0000000000000..5aef2b06cedeb --- /dev/null +++ b/modules/core/src/test/resources/codegen/TestMarshalledMapMessageMarshaller.java @@ -0,0 +1,64 @@ +/* + * 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 java.util.Iterator; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.TestMarshalledMapMessage; +import org.apache.ignite.internal.processors.cache.CacheObjectContext; +import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.plugin.extensions.communication.MessageMarshaller; + +/** + * This class is generated automatically. + * + * @see org.apache.ignite.internal.MessageProcessor + */ +public class TestMarshalledMapMessageMarshaller implements MessageMarshaller { + /** */ + @Override public void marshal(TestMarshalledMapMessage msg, GridKernalContext kctx, CacheObjectContext cacheObjCtx) throws IgniteCheckedException { + if (msg.theMap != null && msg.mapKeys == null) { + msg.mapKeys = msg.theMap.keySet(); + msg.mapVals = msg.theMap.values(); + } + } + + /** */ + @Override public void unmarshal(TestMarshalledMapMessage msg, GridKernalContext kctx, CacheObjectContext cacheObjCtx, ClassLoader clsLdr) throws IgniteCheckedException { + CacheObjectContext ctx = cacheObjCtx; + + if (msg.mapKeys != null) { + msg.theMap = U.newHashMap(msg.mapKeys.size()); + + Iterator keyIter = msg.mapKeys.iterator(); + Iterator valIter = msg.mapVals.iterator(); + + while (keyIter.hasNext()) { + GridCacheVersion k = keyIter.next(); + GridCacheVersion v = valIter.next(); + + msg.theMap.put(k, v); + } + + msg.mapKeys = null; + msg.mapVals = null; + } + } +} \ No newline at end of file diff --git a/modules/core/src/test/resources/codegen/TestMarshalledMapMessageSerializer.java b/modules/core/src/test/resources/codegen/TestMarshalledMapMessageSerializer.java new file mode 100644 index 0000000000000..8320b6e22b860 --- /dev/null +++ b/modules/core/src/test/resources/codegen/TestMarshalledMapMessageSerializer.java @@ -0,0 +1,87 @@ +/* + * 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.TestMarshalledMapMessage; +import org.apache.ignite.plugin.extensions.communication.MessageCollectionItemType; +import org.apache.ignite.plugin.extensions.communication.MessageCollectionType; +import org.apache.ignite.plugin.extensions.communication.MessageItemType; +import org.apache.ignite.plugin.extensions.communication.MessageReader; +import org.apache.ignite.plugin.extensions.communication.MessageSerializer; +import org.apache.ignite.plugin.extensions.communication.MessageWriter; + +/** + * This class is generated automatically. + * + * @see org.apache.ignite.internal.MessageProcessor + */ +public class TestMarshalledMapMessageSerializer implements MessageSerializer { + /** */ + private static final MessageCollectionType mapKeysCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.GRID_CACHE_VERSION), false); + /** */ + private static final MessageCollectionType mapValsCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.GRID_CACHE_VERSION), false); + + /** */ + @Override public boolean writeTo(TestMarshalledMapMessage msg, MessageWriter writer) { + if (!writer.isHeaderWritten()) { + if (!writer.writeHeader(msg.directType())) + return false; + + writer.onHeaderWritten(); + } + + switch (writer.state()) { + case 0: + if (!writer.writeCollection(msg.mapKeys, mapKeysCollDesc)) + return false; + + writer.incrementState(); + + case 1: + if (!writer.writeCollection(msg.mapVals, mapValsCollDesc)) + return false; + + writer.incrementState(); + } + + return true; + } + + /** */ + @Override public boolean readFrom(TestMarshalledMapMessage msg, MessageReader reader) { + switch (reader.state()) { + case 0: + msg.mapKeys = reader.readCollection(mapKeysCollDesc); + + if (!reader.isLastRead()) + return false; + + reader.incrementState(); + + case 1: + msg.mapVals = reader.readCollection(mapValsCollDesc); + + if (!reader.isLastRead()) + return false; + + reader.incrementState(); + } + + return true; + } +} \ No newline at end of file diff --git a/modules/core/src/test/resources/codegen/TestMarshalledMessage.java b/modules/core/src/test/resources/codegen/TestMarshalledMessage.java new file mode 100644 index 0000000000000..a110f5e9ecb59 --- /dev/null +++ b/modules/core/src/test/resources/codegen/TestMarshalledMessage.java @@ -0,0 +1,32 @@ +/* + * 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.plugin.extensions.communication.Message; + +public class TestMarshalledMessage implements Message { + @Marshalled("dataBytes") + Object data; + + @Order(0) + byte[] dataBytes; + + public short directType() { + return 0; + } +} diff --git a/modules/core/src/test/resources/codegen/TestMarshalledMessageMarshaller.java b/modules/core/src/test/resources/codegen/TestMarshalledMessageMarshaller.java new file mode 100644 index 0000000000000..60de55497a981 --- /dev/null +++ b/modules/core/src/test/resources/codegen/TestMarshalledMessageMarshaller.java @@ -0,0 +1,56 @@ +/* + * 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.IgniteCheckedException; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.TestMarshalledMessage; +import org.apache.ignite.internal.processors.cache.CacheObjectContext; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.marshaller.Marshaller; +import org.apache.ignite.plugin.extensions.communication.MessageMarshaller; + +/** + * This class is generated automatically. + * + * @see org.apache.ignite.internal.MessageProcessor + */ +public class TestMarshalledMessageMarshaller implements MessageMarshaller { + /** */ + private final Marshaller marshaller; + + /** */ + public TestMarshalledMessageMarshaller(Marshaller marshaller) { + this.marshaller = marshaller; + } + + /** */ + @Override public void marshal(TestMarshalledMessage msg, GridKernalContext kctx, CacheObjectContext cacheObjCtx) throws IgniteCheckedException { + if (msg.data != null && msg.dataBytes == null) + msg.dataBytes = U.marshal(marshaller, msg.data); + } + + /** */ + @Override public void unmarshal(TestMarshalledMessage msg, GridKernalContext kctx, CacheObjectContext cacheObjCtx, ClassLoader clsLdr) throws IgniteCheckedException { + if (msg.dataBytes != null) { + msg.data = U.unmarshal(marshaller, msg.dataBytes, clsLdr); + + msg.dataBytes = null; + } + } +} \ No newline at end of file diff --git a/modules/core/src/test/resources/codegen/TestMarshalledMessageSerializer.java b/modules/core/src/test/resources/codegen/TestMarshalledMessageSerializer.java new file mode 100644 index 0000000000000..6315a46883165 --- /dev/null +++ b/modules/core/src/test/resources/codegen/TestMarshalledMessageSerializer.java @@ -0,0 +1,65 @@ +/* + * 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.TestMarshalledMessage; +import org.apache.ignite.plugin.extensions.communication.MessageReader; +import org.apache.ignite.plugin.extensions.communication.MessageSerializer; +import org.apache.ignite.plugin.extensions.communication.MessageWriter; + +/** + * This class is generated automatically. + * + * @see org.apache.ignite.internal.MessageProcessor + */ +public class TestMarshalledMessageSerializer implements MessageSerializer { + /** */ + @Override public boolean writeTo(TestMarshalledMessage msg, MessageWriter writer) { + if (!writer.isHeaderWritten()) { + if (!writer.writeHeader(msg.directType())) + return false; + + writer.onHeaderWritten(); + } + + switch (writer.state()) { + case 0: + if (!writer.writeByteArray(msg.dataBytes)) + return false; + + writer.incrementState(); + } + + return true; + } + + /** */ + @Override public boolean readFrom(TestMarshalledMessage msg, MessageReader reader) { + switch (reader.state()) { + case 0: + msg.dataBytes = reader.readByteArray(); + + if (!reader.isLastRead()) + return false; + + reader.incrementState(); + } + + return true; + } +} \ No newline at end of file diff --git a/modules/core/src/test/resources/codegen/TestMarshalledObjectsMessage.java b/modules/core/src/test/resources/codegen/TestMarshalledObjectsMessage.java new file mode 100644 index 0000000000000..b1f9a552387e1 --- /dev/null +++ b/modules/core/src/test/resources/codegen/TestMarshalledObjectsMessage.java @@ -0,0 +1,33 @@ +/* + * 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 java.util.Collection; +import org.apache.ignite.plugin.extensions.communication.Message; + +public class TestMarshalledObjectsMessage implements Message { + @Order(0) + Collection dataBytes; + + @Marshalled("dataBytes") + Collection data; + + public short directType() { + return 0; + } +} diff --git a/modules/core/src/test/resources/codegen/TestMarshalledObjectsMessageMarshaller.java b/modules/core/src/test/resources/codegen/TestMarshalledObjectsMessageMarshaller.java new file mode 100644 index 0000000000000..4f1aa050e0a91 --- /dev/null +++ b/modules/core/src/test/resources/codegen/TestMarshalledObjectsMessageMarshaller.java @@ -0,0 +1,78 @@ +/* + * 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 java.util.ArrayList; +import java.util.Map; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.TestMarshalledObjectsMessage; +import org.apache.ignite.internal.processors.cache.CacheObjectContext; +import org.apache.ignite.internal.processors.cache.KeyCacheObject; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.marshaller.Marshaller; +import org.apache.ignite.plugin.extensions.communication.MessageMarshaller; + +/** + * This class is generated automatically. + * + * @see org.apache.ignite.internal.MessageProcessor + */ +public class TestMarshalledObjectsMessageMarshaller implements MessageMarshaller { + /** */ + private final Marshaller marshaller; + + /** */ + public TestMarshalledObjectsMessageMarshaller(Marshaller marshaller) { + this.marshaller = marshaller; + } + + /** */ + @Override public void marshal(TestMarshalledObjectsMessage msg, GridKernalContext kctx, CacheObjectContext cacheObjCtx) throws IgniteCheckedException { + if (msg.data != null && msg.dataBytes == null) { + msg.dataBytes = new ArrayList<>(msg.data.size()); + + for (Object e : msg.data) + msg.dataBytes.add(U.marshal(marshaller, e)); + } + } + + /** */ + @Override public void unmarshal(TestMarshalledObjectsMessage msg, GridKernalContext kctx, CacheObjectContext cacheObjCtx, ClassLoader clsLdr) throws IgniteCheckedException { + CacheObjectContext ctx = cacheObjCtx; + + if (msg.dataBytes != null) { + msg.data = new ArrayList<>(msg.dataBytes.size()); + + for (byte[] e : msg.dataBytes) { + Object o = U.unmarshal(marshaller, e, clsLdr); + + if (o instanceof Map.Entry) { + Object key = ((Map.Entry)o).getKey(); + + if (key instanceof KeyCacheObject) + ((KeyCacheObject)key).unmarshal(ctx, clsLdr); + } + + msg.data.add(o); + } + + msg.dataBytes = null; + } + } +} \ No newline at end of file diff --git a/modules/core/src/test/resources/codegen/TestMarshalledObjectsMessageSerializer.java b/modules/core/src/test/resources/codegen/TestMarshalledObjectsMessageSerializer.java new file mode 100644 index 0000000000000..e5464b85916e5 --- /dev/null +++ b/modules/core/src/test/resources/codegen/TestMarshalledObjectsMessageSerializer.java @@ -0,0 +1,71 @@ +/* + * 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.TestMarshalledObjectsMessage; +import org.apache.ignite.plugin.extensions.communication.MessageCollectionItemType; +import org.apache.ignite.plugin.extensions.communication.MessageCollectionType; +import org.apache.ignite.plugin.extensions.communication.MessageItemType; +import org.apache.ignite.plugin.extensions.communication.MessageReader; +import org.apache.ignite.plugin.extensions.communication.MessageSerializer; +import org.apache.ignite.plugin.extensions.communication.MessageWriter; + +/** + * This class is generated automatically. + * + * @see org.apache.ignite.internal.MessageProcessor + */ +public class TestMarshalledObjectsMessageSerializer implements MessageSerializer { + /** */ + private static final MessageCollectionType dataBytesCollDesc = new MessageCollectionType(new MessageItemType(MessageCollectionItemType.BYTE_ARR), false); + + /** */ + @Override public boolean writeTo(TestMarshalledObjectsMessage msg, MessageWriter writer) { + if (!writer.isHeaderWritten()) { + if (!writer.writeHeader(msg.directType())) + return false; + + writer.onHeaderWritten(); + } + + switch (writer.state()) { + case 0: + if (!writer.writeCollection(msg.dataBytes, dataBytesCollDesc)) + return false; + + writer.incrementState(); + } + + return true; + } + + /** */ + @Override public boolean readFrom(TestMarshalledObjectsMessage msg, MessageReader reader) { + switch (reader.state()) { + case 0: + msg.dataBytes = reader.readCollection(dataBytesCollDesc); + + if (!reader.isLastRead()) + return false; + + reader.incrementState(); + } + + return true; + } +} \ No newline at end of file diff --git a/modules/core/src/test/resources/codegen/TestMessage.java b/modules/core/src/test/resources/codegen/TestMessage.java index 6f3ef5eb1353a..36b514b2ccbc2 100644 --- a/modules/core/src/test/resources/codegen/TestMessage.java +++ b/modules/core/src/test/resources/codegen/TestMessage.java @@ -21,6 +21,7 @@ import java.util.UUID; import java.util.BitSet; import org.apache.ignite.internal.processors.cache.CacheObject; +import org.apache.ignite.internal.GridTopicMessage; import org.apache.ignite.internal.processors.cache.KeyCacheObject; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion; @@ -50,6 +51,10 @@ public class TestMessage implements Message { @Order(6) GridCacheVersion[] verArr; + @NioField + @Order(15) + GridTopicMessage nioMsg; + @Order(7) UUID uuid; diff --git a/modules/core/src/test/resources/codegen/TestMessageMarshaller.java b/modules/core/src/test/resources/codegen/TestMessageMarshaller.java new file mode 100644 index 0000000000000..83f2af3624e30 --- /dev/null +++ b/modules/core/src/test/resources/codegen/TestMessageMarshaller.java @@ -0,0 +1,63 @@ +/* + * 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.IgniteCheckedException; +import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.TestMessage; +import org.apache.ignite.internal.managers.communication.MessageMarshalling; +import org.apache.ignite.internal.processors.cache.CacheObjectContext; +import org.apache.ignite.plugin.extensions.communication.MessageMarshaller; + +/** + * This class is generated automatically. + * + * @see org.apache.ignite.internal.MessageProcessor + */ +public class TestMessageMarshaller implements MessageMarshaller { + /** */ + @Override public void marshal(TestMessage msg, GridKernalContext kctx, CacheObjectContext cacheObjCtx) throws IgniteCheckedException { + CacheObjectContext ctx = cacheObjCtx; + + if (msg.keyCacheObject != null && ctx != null) + msg.keyCacheObject.marshal(ctx); + + if (msg.cacheObject != null && ctx != null) + msg.cacheObject.marshal(ctx); + + if (msg.nioMsg != null) + MessageMarshalling.marshal(msg.nioMsg, kctx, ctx); + } + + /** */ + @Override public void unmarshal(TestMessage msg, GridKernalContext kctx, CacheObjectContext cacheObjCtx, ClassLoader clsLdr) throws IgniteCheckedException { + CacheObjectContext ctx = cacheObjCtx; + + if (msg.keyCacheObject != null && ctx != null) + msg.keyCacheObject.unmarshal(ctx, clsLdr); + + if (msg.cacheObject != null && ctx != null) + msg.cacheObject.unmarshal(ctx, clsLdr); + } + + /** */ + @Override public void unmarshalNio(TestMessage msg, GridKernalContext kctx) throws IgniteCheckedException { + if (msg.nioMsg != null) + MessageMarshalling.unmarshal(msg.nioMsg, kctx); + } +} \ No newline at end of file diff --git a/modules/core/src/test/resources/codegen/TestMessageSerializer.java b/modules/core/src/test/resources/codegen/TestMessageSerializer.java index 90f8b8484d267..4d42635468b01 100644 --- a/modules/core/src/test/resources/codegen/TestMessageSerializer.java +++ b/modules/core/src/test/resources/codegen/TestMessageSerializer.java @@ -33,11 +33,11 @@ */ public class TestMessageSerializer implements MessageSerializer { /** */ - private final static MessageArrayType intMatrixCollDesc = new MessageArrayType(new MessageItemType(MessageCollectionItemType.INT_ARR), int[].class); + private static final MessageArrayType intMatrixCollDesc = new MessageArrayType(new MessageItemType(MessageCollectionItemType.INT_ARR), int[].class); /** */ - private final static MessageArrayType strArrCollDesc = new MessageArrayType(new MessageItemType(MessageCollectionItemType.STRING), String.class); + private static final MessageArrayType strArrCollDesc = new MessageArrayType(new MessageItemType(MessageCollectionItemType.STRING), String.class); /** */ - private final static MessageArrayType verArrCollDesc = new MessageArrayType(new MessageItemType(MessageCollectionItemType.GRID_CACHE_VERSION), GridCacheVersion.class); + private static final MessageArrayType verArrCollDesc = new MessageArrayType(new MessageItemType(MessageCollectionItemType.GRID_CACHE_VERSION), GridCacheVersion.class); /** */ @Override public boolean writeTo(TestMessage msg, MessageWriter writer) { @@ -138,6 +138,12 @@ public class TestMessageSerializer implements MessageSerializer { return false; writer.incrementState(); + + case 15: + if (!writer.writeMessage(msg.nioMsg)) + return false; + + writer.incrementState(); } return true; @@ -261,6 +267,14 @@ public class TestMessageSerializer implements MessageSerializer { case 14: msg.gridLongList = reader.readGridLongList(); + if (!reader.isLastRead()) + return false; + + reader.incrementState(); + + case 15: + msg.nioMsg = reader.readMessage(); + if (!reader.isLastRead()) return false; diff --git a/modules/core/src/test/resources/codegen/TestNestedDeployMessage.java b/modules/core/src/test/resources/codegen/TestNestedDeployMessage.java new file mode 100644 index 0000000000000..2ce620f2b724a --- /dev/null +++ b/modules/core/src/test/resources/codegen/TestNestedDeployMessage.java @@ -0,0 +1,33 @@ +/* + * 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.processors.cache.GridCacheIdMessage; + +public class TestNestedDeployMessage extends GridCacheIdMessage { + @Order(0) + TestCacheIdMessage nested; + + public short directType() { + return 0; + } + + @Override public boolean addDeploymentInfo() { + return true; + } +} diff --git a/modules/core/src/test/resources/codegen/TestNestedDeployMessageDeployer.java b/modules/core/src/test/resources/codegen/TestNestedDeployMessageDeployer.java new file mode 100644 index 0000000000000..3f75e24b49d46 --- /dev/null +++ b/modules/core/src/test/resources/codegen/TestNestedDeployMessageDeployer.java @@ -0,0 +1,35 @@ +/* + * 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.IgniteCheckedException; +import org.apache.ignite.internal.TestNestedDeployMessage; +import org.apache.ignite.internal.processors.cache.GridCacheMessageDeployer; +import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; + +/** + * This class is generated automatically. + * + * @see org.apache.ignite.internal.MessageProcessor + */ +public class TestNestedDeployMessageDeployer implements GridCacheMessageDeployer { + /** */ + @Override public void deploy(TestNestedDeployMessage msg, GridCacheSharedContext ctx) throws IgniteCheckedException { + GridCacheMessageDeployer.deploy(ctx.kernalContext().messageFactory(), msg.nested, ctx); + } +} \ No newline at end of file diff --git a/modules/core/src/test/resources/codegen/TestNoCacheCtxMessage.java b/modules/core/src/test/resources/codegen/TestNoCacheCtxMessage.java new file mode 100644 index 0000000000000..a9cb826dc8f8e --- /dev/null +++ b/modules/core/src/test/resources/codegen/TestNoCacheCtxMessage.java @@ -0,0 +1,34 @@ +/* + * 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.processors.cache.CacheObject; +import org.apache.ignite.internal.processors.cache.GridCacheMessage; + +public class TestNoCacheCtxMessage extends GridCacheMessage { + @Order(0) + CacheObject val; + + public short directType() { + return 0; + } + + @Override public boolean addDeploymentInfo() { + return true; + } +} diff --git a/modules/core/src/test/resources/codegen/WrongNonMarshallableMessage.java b/modules/core/src/test/resources/codegen/WrongNonMarshallableMessage.java new file mode 100644 index 0000000000000..4c329f2ed5af0 --- /dev/null +++ b/modules/core/src/test/resources/codegen/WrongNonMarshallableMessage.java @@ -0,0 +1,32 @@ +/* + * 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.plugin.extensions.communication.NonMarshallableMessage; + +public class WrongNonMarshallableMessage implements NonMarshallableMessage { + @Order(0) + byte[] dataBytes; + + @Marshalled("dataBytes") + Object data; + + public short directType() { + return 0; + } +} diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/msg/GridH2CacheObject.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/msg/GridH2CacheObject.java index 559f96bccad5c..92640ed4b75a4 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/msg/GridH2CacheObject.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/msg/GridH2CacheObject.java @@ -47,14 +47,14 @@ public GridH2CacheObject() { public GridH2CacheObject(GridH2ValueCacheObject v) throws IgniteCheckedException { obj = v.getCacheObject(); - obj.prepareMarshal(v.valueContext()); + obj.marshal(v.valueContext()); } /** {@inheritDoc} */ @Override public Value value(GridKernalContext ctx) throws IgniteCheckedException { CacheObjectValueContext valCtx = ctx.query().objectContext(); - obj.finishUnmarshal(valCtx, ctx.cache().context().deploy().globalLoader()); + obj.unmarshal(valCtx, ctx.cache().context().deploy().globalLoader()); return new GridH2ValueCacheObject(obj, valCtx); } diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/msg/GridH2ValueMessage.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/msg/GridH2ValueMessage.java index c24857ef13a17..6ebbfab981f9b 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/msg/GridH2ValueMessage.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/msg/GridH2ValueMessage.java @@ -19,13 +19,13 @@ import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.GridKernalContext; -import org.apache.ignite.plugin.extensions.communication.Message; +import org.apache.ignite.plugin.extensions.communication.NonMarshallableMessage; import org.h2.value.Value; /** * Abstract message wrapper for H2 values. */ -public abstract class GridH2ValueMessage implements Message { +public abstract class GridH2ValueMessage implements NonMarshallableMessage { /** * Gets H2 value. * diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/msg/GridH2ValueMessageFactory.java b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/msg/GridH2ValueMessageFactory.java index b26089afd70fe..54063c9a5c8e8 100644 --- a/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/msg/GridH2ValueMessageFactory.java +++ b/modules/indexing/src/main/java/org/apache/ignite/internal/processors/query/h2/twostep/msg/GridH2ValueMessageFactory.java @@ -23,11 +23,11 @@ import java.util.List; import org.apache.ignite.IgniteCheckedException; import org.apache.ignite.internal.GridKernalContext; +import org.apache.ignite.internal.managers.communication.IgniteMessageFactory; import org.apache.ignite.internal.processors.query.h2.QueryTable; import org.apache.ignite.internal.processors.query.h2.QueryTableSerializer; import org.apache.ignite.internal.processors.query.h2.opt.GridH2ValueCacheObject; import org.apache.ignite.plugin.extensions.communication.Message; -import org.apache.ignite.plugin.extensions.communication.MessageFactory; import org.apache.ignite.plugin.extensions.communication.MessageFactoryProvider; import org.h2.value.Value; @@ -36,7 +36,7 @@ */ public class GridH2ValueMessageFactory implements MessageFactoryProvider { /** {@inheritDoc} */ - @Override public void registerAll(MessageFactory factory) { + @Override public void registerAll(IgniteMessageFactory factory) { factory.register(-4, () -> GridH2Null.INSTANCE, new GridH2NullSerializer()); factory.register(-5, GridH2Boolean::new, new GridH2BooleanSerializer()); factory.register(-6, GridH2Byte::new, new GridH2ByteSerializer()); diff --git a/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/GridDirectParser.java b/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/GridDirectParser.java index a78a97ea37fcd..f30fbc5cfc0ea 100644 --- a/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/GridDirectParser.java +++ b/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/GridDirectParser.java @@ -26,7 +26,6 @@ import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.plugin.extensions.communication.MessageFactory; import org.apache.ignite.plugin.extensions.communication.MessageReader; -import org.apache.ignite.plugin.extensions.communication.MessageSerializer; import org.jetbrains.annotations.Nullable; import static org.apache.ignite.internal.util.CommonUtils.makeMessageType; @@ -85,11 +84,9 @@ public GridDirectParser(IgniteLogger log, MessageFactory msgFactory, GridNioMess boolean finished = false; if (msg != null && buf.hasRemaining()) { - MessageSerializer msgSer = msgFactory.serializer(msg.directType()); - reader.setBuffer(buf); - finished = msgSer.readFrom(msg, reader); + finished = MessageSerialization.readFrom(msgFactory, msg, reader); } if (finished) { diff --git a/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/GridNioMessageReaderFactory.java b/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/GridNioMessageReaderFactory.java index cb7e62dda5a55..a62e62e981223 100644 --- a/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/GridNioMessageReaderFactory.java +++ b/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/GridNioMessageReaderFactory.java @@ -18,6 +18,7 @@ package org.apache.ignite.internal.util.nio; import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.plugin.extensions.communication.MessageFactory; import org.apache.ignite.plugin.extensions.communication.MessageReader; @@ -33,5 +34,5 @@ public interface GridNioMessageReaderFactory { * @return Reader. * @throws IgniteCheckedException In case of error. */ - public MessageReader reader(GridNioSession ses, MessageFactory msgFactory) throws IgniteCheckedException; + public MessageReader reader(GridNioSession ses, MessageFactory msgFactory) throws IgniteCheckedException; } diff --git a/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/GridNioServer.java b/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/GridNioServer.java index fa23121fd1675..2b6de363feaa3 100644 --- a/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/GridNioServer.java +++ b/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/GridNioServer.java @@ -85,7 +85,6 @@ import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.plugin.extensions.communication.MessageFactory; import org.apache.ignite.plugin.extensions.communication.MessageReader; -import org.apache.ignite.plugin.extensions.communication.MessageSerializer; import org.apache.ignite.plugin.extensions.communication.MessageWriter; import org.apache.ignite.thread.IgniteThread; import org.jetbrains.annotations.Nullable; @@ -1641,11 +1640,9 @@ private boolean writeToBuffer( finished = ((ClientMessage)msg).writeTo(buf); } else { - MessageSerializer msgSer = messageFactory().serializer(msg.directType()); - writer.setBuffer(buf); - finished = msgSer.writeTo(msg, writer); + finished = MessageSerialization.writeTo(messageFactory(), msg, writer); } span.addTag(SOCKET_WRITE_BYTES, () -> Integer.toString(buf.position() - startPos)); @@ -1842,11 +1839,9 @@ private boolean writeToBuffer(GridSelectorNioSessionImpl ses, ByteBuffer buf, Se finished = ((ClientMessage)msg).writeTo(buf); } else { - MessageSerializer msgSer = msgFactory.serializer(msg.directType()); - writer.setBuffer(buf); - finished = msgSer.writeTo(msg, writer); + finished = MessageSerialization.writeTo(msgFactory, msg, writer); } span.addTag(SOCKET_WRITE_BYTES, () -> Integer.toString(buf.position() - startPos)); diff --git a/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/MessageSerialization.java b/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/MessageSerialization.java new file mode 100644 index 0000000000000..b436edb764d49 --- /dev/null +++ b/modules/nio/src/main/java/org/apache/ignite/internal/util/nio/MessageSerialization.java @@ -0,0 +1,68 @@ +/* + * 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.util.nio; + +import org.apache.ignite.plugin.extensions.communication.Message; +import org.apache.ignite.plugin.extensions.communication.MessageFactory; +import org.apache.ignite.plugin.extensions.communication.MessageReader; +import org.apache.ignite.plugin.extensions.communication.MessageSerializer; +import org.apache.ignite.plugin.extensions.communication.MessageWriter; + +/** + * Resolve-and-dispatch entry points for {@link MessageSerializer}: each looks up the serializer registered for the + * message's direct type in the factory and delegates to it. The counterpart of {@code MessageMarshalling} on the + * serialization side. + */ +public final class MessageSerialization { + /** */ + private MessageSerialization() { + // No-op. + } + + /** + * Writes the message using the serializer resolved from the factory. + * + * @param factory Message factory. + * @param msg Message instance. + * @param writer Writer. + * @param Message type. + * @return Whether message was fully written. + */ + public static boolean writeTo(MessageFactory factory, M msg, MessageWriter writer) { + return resolve(factory, msg).writeTo(msg, writer); + } + + /** + * Reads the message using the serializer resolved from the factory. + * + * @param factory Message factory. + * @param msg Message instance. + * @param reader Reader. + * @param Message type. + * @return Whether message was fully read. + */ + public static boolean readFrom(MessageFactory factory, M msg, MessageReader reader) { + return resolve(factory, msg).readFrom(msg, reader); + } + + /** @return the serializer registered for {@code msg}'s direct type. */ + @SuppressWarnings("unchecked") + private static MessageSerializer resolve(MessageFactory factory, M msg) { + return (MessageSerializer)factory.serializer(msg.directType()); + } +} diff --git a/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/Message.java b/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/Message.java index 1e4abc845c52c..3ed385c9c07c2 100644 --- a/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/Message.java +++ b/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/Message.java @@ -17,49 +17,47 @@ package org.apache.ignite.plugin.extensions.communication; -import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import org.apache.ignite.IgniteException; -import org.apache.ignite.internal.managers.communication.UnknownMessageException; /** - * Base class for all communication messages. + * Base type for all messages sent between nodes, both over the communication SPI and via discovery. + *

+ * Serialized fields are declared by annotating instance fields; {@ignitelink org.apache.ignite.internal.MessageProcessor} then + * generates the serializer, so implementations should not hand-write {@code writeTo}/{@code readFrom}. Available + * field annotations (see each annotation's javadoc for details): + *

    + *
  • {@ignitelink org.apache.ignite.internal.Order @Order} — an ordered serialized field (the basic building block);
  • + *
  • {@ignitelink org.apache.ignite.internal.Compress @Compress} — compress the field's serialized form;
  • + *
  • {@ignitelink org.apache.ignite.internal.NioField @NioField} — a low-level NIO field;
  • + *
  • {@ignitelink org.apache.ignite.internal.CustomMapper @CustomMapper} — map the enum field via a custom mapper;
  • + *
  • {@ignitelink org.apache.ignite.internal.Marshalled @Marshalled} — for + * {@ignitelink org.apache.ignite.internal.MarshallableMessage MarshallableMessage} payloads serialized via a + * {@link org.apache.ignite.marshaller.Marshaller}; the flavour (single blob, per-element messages or blobs, + * map) is derived from the shape of the companion wire field(s) it names.
  • + *
*/ public interface Message { /** Direct type size in bytes. */ int DIRECT_TYPE_SIZE = 2; - /** Registry of message class to direct type mappings, populated during factory initialization. */ - Map, Short> REGISTRATIONS = new ConcurrentHashMap<>(); - /** * Gets message type. * * @return Message type. */ default short directType() { - var clazz = getClass(); - Short type = REGISTRATIONS.get(clazz); - - if (type == null) - throw new UnknownMessageException(clazz); - - return type; + return MessageRegistry.directType(getClass()); } /** * Registers the direct type for this message class. Called during message factory initialization - * to populate the {@link #REGISTRATIONS} map so that {@link #directType()} can resolve types + * to populate the {@link MessageRegistry} so that {@link #directType()} can resolve types * without requiring each message class to override it. * * @param directType Direct type to register. * @throws IgniteException If this message class is already registered with a different direct type. */ default void registerAsDirectType(short directType) { - var clazz = getClass(); - var type = REGISTRATIONS.putIfAbsent(clazz, directType); - - if ((type != null) && (type != directType)) - throw new IgniteException(clazz.getSimpleName() + " is already registered for direct type " + type); + MessageRegistry.register(getClass(), directType); } } diff --git a/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageFactory.java b/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageFactory.java index 53366108bfca0..cea29ed62f054 100644 --- a/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageFactory.java +++ b/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageFactory.java @@ -23,7 +23,7 @@ /** * Message factory for all communication messages registered using {@link #register(short, Supplier, MessageSerializer)} method call. */ -public interface MessageFactory { +public interface MessageFactory { /** * Register message factory with given direct type. All messages must be registered during construction * of class which implements this interface. Any invocation of this method after initialization is done must @@ -37,7 +37,7 @@ public interface MessageFactory { * @deprecated Use {@link #register(short, Supplier, MessageSerializer)} instead. */ @Deprecated(forRemoval = true) - default void register(short directType, Supplier supplier) throws IgniteException { + default void register(short directType, Supplier supplier) throws IgniteException { throw new UnsupportedOperationException(); } @@ -54,7 +54,7 @@ default void register(short directType, Supplier supplier) throws Ignit * @deprecated Use {@link #register(int, Supplier, MessageSerializer)} instead. */ @Deprecated(forRemoval = true) - default void register(int directType, Supplier supplier) throws IgniteException { + default void register(int directType, Supplier supplier) throws IgniteException { register((short)directType, supplier); } @@ -70,7 +70,7 @@ default void register(int directType, Supplier supplier) throws IgniteE * @throws IllegalStateException On any invocation of this method when class which implements this interface * is alredy constructed. */ - public void register(short directType, Supplier supplier, MessageSerializer serializer) throws IgniteException; + public void register(short directType, Supplier supplier, MessageSerializer serializer) throws IgniteException; /** * Register message factory with given direct type and serializer. The direct type is also registered @@ -88,7 +88,7 @@ default void register(int directType, Supplier supplier) throws IgniteE * @throws IllegalStateException On any invocation of this method when class which implements this interface * is already constructed. */ - default void register(int directType, Supplier supplier, MessageSerializer serializer) throws IgniteException { + default void register(int directType, Supplier supplier, MessageSerializer serializer) throws IgniteException { register((short)directType, supplier, serializer); } @@ -98,7 +98,7 @@ default void register(int directType, Supplier supplier, MessageSeriali * @param type Message type. * @return Message instance. */ - public Message create(short type); + public T create(short type); /** * Returns {@code MessageSerializer} for provided type. @@ -106,5 +106,5 @@ default void register(int directType, Supplier supplier, MessageSeriali * @param type Message type. * @return Message instance. */ - public MessageSerializer serializer(short type); + public MessageSerializer serializer(short type); } diff --git a/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageRegistry.java b/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageRegistry.java new file mode 100644 index 0000000000000..b22aa43f7e079 --- /dev/null +++ b/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageRegistry.java @@ -0,0 +1,73 @@ +/* + * 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.plugin.extensions.communication; + +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import org.apache.ignite.IgniteException; +import org.apache.ignite.internal.managers.communication.UnknownMessageException; + +/** + * Registry of message class to direct type mappings behind {@link Message#directType()}, populated during factory + * initialization via {@link Message#registerAsDirectType(short)}. Kept package-private so the map is mutable only + * through the validated registration path. + */ +final class MessageRegistry { + /** Message class to direct type mappings. */ + private static final Map, Short> REGISTRATIONS = new ConcurrentHashMap<>(); + + /** Per-class cache over {@link #REGISTRATIONS}; keeps {@link #directType} off the map lookup done for every sent message. */ + private static final ClassValue DIRECT_TYPES = new ClassValue<>() { + @Override protected Short computeValue(Class type) { + Short directType = REGISTRATIONS.get(type); + + if (directType == null) + throw new UnknownMessageException(type.asSubclass(Message.class)); + + return directType; + } + }; + + /** */ + private MessageRegistry() { + // No-op. + } + + /** + * @param cls Message class. + * @return Direct type registered for {@code cls}. + * @throws UnknownMessageException If {@code cls} is not registered. + */ + static short directType(Class cls) { + return DIRECT_TYPES.get(cls); + } + + /** + * Registers the direct type for {@code cls}. + * + * @param cls Message class. + * @param directType Direct type to register. + * @throws IgniteException If {@code cls} is already registered with a different direct type. + */ + static void register(Class cls, short directType) { + Short type = REGISTRATIONS.putIfAbsent(cls, directType); + + if ((type != null) && (type != directType)) + throw new IgniteException(cls.getSimpleName() + " is already registered for direct type " + type); + } +} diff --git a/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageSerializer.java b/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageSerializer.java index 90df0601693c3..98de5c04de597 100644 --- a/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageSerializer.java +++ b/modules/nio/src/main/java/org/apache/ignite/plugin/extensions/communication/MessageSerializer.java @@ -18,7 +18,8 @@ package org.apache.ignite.plugin.extensions.communication; /** - * Interface for message serialization logic. + * Interface for message serialization logic. Resolve-and-dispatch entry points that look the serializer up from the + * message factory live in {@code MessageSerialization}. */ public interface MessageSerializer { /** diff --git a/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/DiscoveryMessageParser.java b/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/DiscoveryMessageParser.java index b33684d6abdb6..bcc10b0bbb018 100644 --- a/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/DiscoveryMessageParser.java +++ b/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/DiscoveryMessageParser.java @@ -25,9 +25,13 @@ import java.nio.ByteBuffer; import java.util.zip.DeflaterOutputStream; import java.util.zip.InflaterInputStream; +import org.apache.ignite.IgniteCheckedException; +import org.apache.ignite.internal.GridKernalContext; import org.apache.ignite.internal.direct.DirectMessageReader; import org.apache.ignite.internal.direct.DirectMessageWriter; +import org.apache.ignite.internal.managers.communication.MessageMarshalling; import org.apache.ignite.internal.util.CommonUtils; +import org.apache.ignite.internal.util.nio.MessageSerialization; import org.apache.ignite.plugin.extensions.communication.Message; import org.apache.ignite.plugin.extensions.communication.MessageFactory; import org.apache.ignite.plugin.extensions.communication.MessageSerializer; @@ -44,8 +48,15 @@ public class DiscoveryMessageParser { private final MessageFactory msgFactory; /** */ - public DiscoveryMessageParser(MessageFactory msgFactory) { + private final GridKernalContext kctx; + + /** + * @param msgFactory Message factory. + * @param kctx Kernal context. + */ + public DiscoveryMessageParser(MessageFactory msgFactory, GridKernalContext kctx) { this.msgFactory = msgFactory; + this.kctx = kctx; } /** Marshals discovery message to bytes array. */ @@ -82,14 +93,19 @@ private void serializeMessage(Message m, OutputStream out) throws IOException { msgWriter.setBuffer(msgBuf); - MessageSerializer msgSer = msgFactory.serializer(m.directType()); + try { + MessageMarshalling.marshal(m, kctx, null); + } + catch (IgniteCheckedException e) { + throw new IgniteSpiException("Failed to marshal discovery message", e); + } boolean finished; do { msgBuf.clear(); - finished = msgSer.writeTo(m, msgWriter); + finished = MessageSerialization.writeTo(msgFactory, m, msgWriter); out.write(msgBuf.array(), 0, msgBuf.position()); } @@ -104,7 +120,6 @@ private T deserializeMessage(InputStream in) throws IOExcept msgReader.setBuffer(msgBuf); Message msg = msgFactory.create(CommonUtils.makeMessageType((byte)in.read(), (byte)in.read())); - MessageSerializer msgSer = msgFactory.serializer(msg.directType()); boolean finished; @@ -116,7 +131,7 @@ private T deserializeMessage(InputStream in) throws IOExcept msgBuf.rewind(); } - finished = msgSer.readFrom(msg, msgReader); + finished = MessageSerialization.readFrom(msgFactory, msg, msgReader); assert read != -1 || finished : "Stream closed before message was fully read."; @@ -125,6 +140,13 @@ private T deserializeMessage(InputStream in) throws IOExcept } while (!finished); + try { + MessageMarshalling.unmarshal(msg, kctx); + } + catch (IgniteCheckedException e) { + throw new IgniteSpiException("Failed to unmarshal discovery message", e); + } + return (T)msg; } } diff --git a/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZkDiscoveryCustomEventData.java b/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZkDiscoveryCustomEventData.java index 9513108f8361b..fc8785342d0bf 100644 --- a/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZkDiscoveryCustomEventData.java +++ b/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZkDiscoveryCustomEventData.java @@ -71,13 +71,13 @@ class ZkDiscoveryCustomEventData extends ZkDiscoveryEventData { } /** */ - public void prepareMarshal(DiscoveryMessageParser parser) { + public void marshal(DiscoveryMessageParser parser) { if (resolvedMsg != null) msgBytes = parser.marshalZip(resolvedMsg); } /** */ - public void finishUnmarshal(DiscoveryMessageParser parser) { + public void unmarshal(DiscoveryMessageParser parser) { if (msgBytes != null) resolvedMsg = parser.unmarshalZip(msgBytes); } diff --git a/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZkMessageFactory.java b/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZkMessageFactory.java index e89f44f013bb7..f6153ab8b9aa6 100644 --- a/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZkMessageFactory.java +++ b/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZkMessageFactory.java @@ -17,18 +17,21 @@ package org.apache.ignite.spi.discovery.zk.internal; -import org.apache.ignite.plugin.extensions.communication.MessageFactory; -import org.apache.ignite.plugin.extensions.communication.MessageFactoryProvider; +import org.apache.ignite.internal.managers.communication.IgniteMessageFactory; +import org.apache.ignite.internal.plugin.AbstractMarshallableMessageFactoryProvider; /** */ -public class ZkMessageFactory implements MessageFactoryProvider { +public class ZkMessageFactory extends AbstractMarshallableMessageFactoryProvider { /** {@inheritDoc} */ - @Override public void registerAll(MessageFactory factory) { - factory.register(400, ZkCommunicationErrorResolveFinishMessage::new, new ZkCommunicationErrorResolveFinishMessageSerializer()); - factory.register(401, ZkCommunicationErrorResolveStartMessage::new, new ZkCommunicationErrorResolveStartMessageSerializer()); - factory.register(402, ZkForceNodeFailMessage::new, new ZkForceNodeFailMessageSerializer()); - factory.register(403, ZkNoServersMessage::new, new ZkNoServersMessageSerializer()); - factory.register(404, ZkDiscoDataBagWrapper::new, new ZkDiscoDataBagWrapperSerializer()); - factory.register(405, ZkOperationContextAwareCustomMessage::new, new ZkOperationContextAwareCustomMessageSerializer()); + @Override public void registerAll(IgniteMessageFactory factory) { + register(factory, ZkCommunicationErrorResolveFinishMessage.class, (short)400, + ZkCommunicationErrorResolveFinishMessage::new, dfltMarsh); + register(factory, ZkCommunicationErrorResolveStartMessage.class, (short)401, + ZkCommunicationErrorResolveStartMessage::new, dfltMarsh); + register(factory, ZkForceNodeFailMessage.class, (short)402, ZkForceNodeFailMessage::new, dfltMarsh); + register(factory, ZkNoServersMessage.class, (short)403, ZkNoServersMessage::new, dfltMarsh); + register(factory, ZkDiscoDataBagWrapper.class, (short)404, ZkDiscoDataBagWrapper::new, dfltMarsh); + register(factory, ZkOperationContextAwareCustomMessage.class, (short)405, + ZkOperationContextAwareCustomMessage::new, dfltMarsh); } } diff --git a/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoveryImpl.java b/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoveryImpl.java index a4a657d0877cf..e2f433ad342e9 100644 --- a/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoveryImpl.java +++ b/modules/zookeeper/src/main/java/org/apache/ignite/spi/discovery/zk/internal/ZookeeperDiscoveryImpl.java @@ -280,7 +280,7 @@ public ZookeeperDiscoveryImpl( this.stats = stats; - msgParser = new DiscoveryMessageParser(msgFactory); + msgParser = new DiscoveryMessageParser(msgFactory, ((IgniteEx)spi.ignite()).context()); opCtxDispatcher = ((IgniteEx)spi.ignite()).context().operationContextDispatcher(); } @@ -1511,7 +1511,7 @@ private void generateNoServersEvent(ZkDiscoveryEventsData evtsData, Stat evtsSta new ZkNoServersMessage(), null); - evtData.prepareMarshal(msgParser); + evtData.marshal(msgParser); Collection nodesToAck = Collections.emptyList(); @@ -1541,7 +1541,7 @@ private void previousCoordinatorCleanup(ZkDiscoveryEventsData lastEvts) throws E if (evtData instanceof ZkDiscoveryCustomEventData) { ZkDiscoveryCustomEventData evtData0 = (ZkDiscoveryCustomEventData)evtData; - evtData0.finishUnmarshal(msgParser); + evtData0.unmarshal(msgParser); // It is possible previous coordinator failed before finished cleanup. if (evtData0.resolvedMsg instanceof ZkCommunicationErrorResolveFinishMessage) { @@ -2771,7 +2771,7 @@ private void processNewEvents(final ZkDiscoveryEventsData evtsData) throws Excep if (evtData0.ackEvent() && evtData0.topologyVersion() < locNode.order()) break; - evtData0.finishUnmarshal(msgParser); + evtData0.unmarshal(msgParser); if (rtState.crd) assert evtData0.resolvedMsg != null : evtData0; @@ -3472,7 +3472,7 @@ private void onCommunicationErrorResolveStatusReceived(final ZkRuntimeState rtSt msg, null); - evtData.prepareMarshal(msgParser); + evtData.marshal(msgParser); evtsData.addEvent(rtState.top.nodesByOrder.values(), evtData);