diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/TracingConfigurationCommand.java b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/TracingConfigurationCommand.java similarity index 99% rename from modules/core/src/main/java/org/apache/ignite/internal/commandline/TracingConfigurationCommand.java rename to modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/TracingConfigurationCommand.java index cb87946847a77..66eb2ba880e37 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/TracingConfigurationCommand.java +++ b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/TracingConfigurationCommand.java @@ -28,13 +28,13 @@ import org.apache.ignite.internal.client.GridClientConfiguration; import org.apache.ignite.internal.client.GridClientNode; import org.apache.ignite.internal.commandline.argument.CommandArgUtils; -import org.apache.ignite.internal.commandline.cache.argument.TracingConfigurationCommandArg; import org.apache.ignite.internal.commandline.tracing.configuration.TracingConfigurationArguments; +import org.apache.ignite.internal.commandline.tracing.configuration.TracingConfigurationCommandArg; import org.apache.ignite.internal.commandline.tracing.configuration.TracingConfigurationSubcommand; -import org.apache.ignite.spi.tracing.Scope; import org.apache.ignite.internal.visor.tracing.configuration.VisorTracingConfigurationTask; import org.apache.ignite.internal.visor.tracing.configuration.VisorTracingConfigurationTaskArg; import org.apache.ignite.internal.visor.tracing.configuration.VisorTracingConfigurationTaskResult; +import org.apache.ignite.spi.tracing.Scope; import static org.apache.ignite.IgniteSystemProperties.IGNITE_ENABLE_EXPERIMENTAL_COMMAND; import static org.apache.ignite.internal.commandline.CommandHandler.UTILITY_NAME; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/tracing/configuration/TracingConfigurationArguments.java b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/tracing/configuration/TracingConfigurationArguments.java similarity index 100% rename from modules/core/src/main/java/org/apache/ignite/internal/commandline/tracing/configuration/TracingConfigurationArguments.java rename to modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/tracing/configuration/TracingConfigurationArguments.java index e2119425f6221..655f14515be2f 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/tracing/configuration/TracingConfigurationArguments.java +++ b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/tracing/configuration/TracingConfigurationArguments.java @@ -19,9 +19,9 @@ import java.util.Collections; import java.util.Set; -import org.apache.ignite.spi.tracing.Scope; import org.apache.ignite.internal.processors.tracing.Span; import org.apache.ignite.internal.visor.tracing.configuration.VisorTracingConfigurationItem; +import org.apache.ignite.spi.tracing.Scope; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/argument/TracingConfigurationCommandArg.java b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/tracing/configuration/TracingConfigurationCommandArg.java similarity index 97% rename from modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/argument/TracingConfigurationCommandArg.java rename to modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/tracing/configuration/TracingConfigurationCommandArg.java index 65b2b39a87bc2..3fd4fa4915d83 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/commandline/cache/argument/TracingConfigurationCommandArg.java +++ b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/tracing/configuration/TracingConfigurationCommandArg.java @@ -15,15 +15,15 @@ * limitations under the License. */ -package org.apache.ignite.internal.commandline.cache.argument; +package org.apache.ignite.internal.commandline.tracing.configuration; -import org.apache.ignite.internal.commandline.CommandList; -import org.apache.ignite.internal.commandline.argument.CommandArg; -import org.apache.ignite.spi.tracing.Scope; -import org.apache.ignite.internal.processors.tracing.Span; import java.util.Arrays; import java.util.Set; import java.util.stream.Collectors; +import org.apache.ignite.internal.commandline.CommandList; +import org.apache.ignite.internal.commandline.argument.CommandArg; +import org.apache.ignite.internal.processors.tracing.Span; +import org.apache.ignite.spi.tracing.Scope; /** * {@link CommandList#TRACING_CONFIGURATION} command arguments. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/commandline/tracing/configuration/TracingConfigurationSubcommand.java b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/tracing/configuration/TracingConfigurationSubcommand.java similarity index 100% rename from modules/core/src/main/java/org/apache/ignite/internal/commandline/tracing/configuration/TracingConfigurationSubcommand.java rename to modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/tracing/configuration/TracingConfigurationSubcommand.java diff --git a/modules/control-utility/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java b/modules/control-utility/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java index 73bcce978aaf0..7eed217386d08 100644 --- a/modules/control-utility/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java +++ b/modules/control-utility/src/test/java/org/apache/ignite/internal/commandline/CommandHandlerParsingTest.java @@ -33,12 +33,12 @@ import org.apache.ignite.internal.commandline.cache.CacheValidateIndexes; import org.apache.ignite.internal.commandline.cache.FindAndDeleteGarbage; import org.apache.ignite.internal.commandline.cache.argument.FindAndDeleteGarbageArg; -import org.apache.ignite.spi.tracing.Scope; import org.apache.ignite.internal.util.typedef.T2; import org.apache.ignite.internal.visor.tx.VisorTxOperation; import org.apache.ignite.internal.visor.tx.VisorTxProjection; import org.apache.ignite.internal.visor.tx.VisorTxSortOrder; import org.apache.ignite.internal.visor.tx.VisorTxTaskArg; +import org.apache.ignite.spi.tracing.Scope; import org.apache.ignite.testframework.junits.SystemPropertiesRule; import org.apache.ignite.testframework.junits.WithSystemProperty; import org.jetbrains.annotations.Nullable; diff --git a/modules/control-utility/src/test/java/org/apache/ignite/testsuites/IgniteControlUtilityTestSuite.java b/modules/control-utility/src/test/java/org/apache/ignite/testsuites/IgniteControlUtilityTestSuite.java index 7a57771f7c7fe..ab19b2c56a538 100644 --- a/modules/control-utility/src/test/java/org/apache/ignite/testsuites/IgniteControlUtilityTestSuite.java +++ b/modules/control-utility/src/test/java/org/apache/ignite/testsuites/IgniteControlUtilityTestSuite.java @@ -31,6 +31,7 @@ import org.apache.ignite.util.GridCommandHandlerMetadataTest; import org.apache.ignite.util.GridCommandHandlerSslTest; import org.apache.ignite.util.GridCommandHandlerTest; +import org.apache.ignite.util.GridCommandHandlerTracingConfigurationTest; import org.apache.ignite.util.GridCommandHandlerWithSSLTest; import org.apache.ignite.util.KillCommandsCommandShTest; import org.junit.runner.RunWith; @@ -61,6 +62,8 @@ GridCommandHandlerMetadataTest.class, KillCommandsCommandShTest.class, + + GridCommandHandlerTracingConfigurationTest.class, }) public class IgniteControlUtilityTestSuite { } diff --git a/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerClusterByClassTest.java b/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerClusterByClassTest.java index c445a72932b13..b3805f91eb12d 100644 --- a/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerClusterByClassTest.java +++ b/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerClusterByClassTest.java @@ -99,8 +99,8 @@ import static org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_UNEXPECTED_ERROR; import static org.apache.ignite.internal.commandline.CommandHandler.UTILITY_NAME; import static org.apache.ignite.internal.commandline.CommandList.BASELINE; -import static org.apache.ignite.internal.commandline.CommandList.TRACING_CONFIGURATION; import static org.apache.ignite.internal.commandline.CommandList.METADATA; +import static org.apache.ignite.internal.commandline.CommandList.TRACING_CONFIGURATION; import static org.apache.ignite.internal.commandline.CommandList.WAL; import static org.apache.ignite.internal.commandline.CommonArgParser.CMD_VERBOSE; import static org.apache.ignite.internal.commandline.OutputFormat.MULTI_LINE; diff --git a/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerTracingConfigurationTest.java b/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerTracingConfigurationTest.java similarity index 100% rename from modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerTracingConfigurationTest.java rename to modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerTracingConfigurationTest.java index b507484489023..eb7abe29e703f 100644 --- a/modules/core/src/test/java/org/apache/ignite/util/GridCommandHandlerTracingConfigurationTest.java +++ b/modules/control-utility/src/test/java/org/apache/ignite/util/GridCommandHandlerTracingConfigurationTest.java @@ -24,12 +24,12 @@ import java.util.Map; import org.apache.ignite.internal.IgniteEx; import org.apache.ignite.internal.commandline.CommandHandler; +import org.apache.ignite.internal.commandline.TracingConfigurationCommand; +import org.apache.ignite.internal.visor.tracing.configuration.VisorTracingConfigurationTaskResult; import org.apache.ignite.spi.tracing.Scope; import org.apache.ignite.spi.tracing.TracingConfigurationCoordinates; import org.apache.ignite.spi.tracing.TracingConfigurationManager; import org.apache.ignite.spi.tracing.TracingConfigurationParameters; -import org.apache.ignite.internal.commandline.TracingConfigurationCommand; -import org.apache.ignite.internal.visor.tracing.configuration.VisorTracingConfigurationTaskResult; import org.junit.Test; import static org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_OK; diff --git a/modules/core/src/main/java/org/apache/ignite/Ignite.java b/modules/core/src/main/java/org/apache/ignite/Ignite.java index 194a7e993d0c3..98f99374939bf 100644 --- a/modules/core/src/main/java/org/apache/ignite/Ignite.java +++ b/modules/core/src/main/java/org/apache/ignite/Ignite.java @@ -31,14 +31,14 @@ import org.apache.ignite.configuration.DataStorageConfiguration; import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.configuration.NearCacheConfiguration; -import org.apache.ignite.lang.IgniteExperimental; -import org.apache.ignite.spi.tracing.TracingConfigurationManager; import org.apache.ignite.internal.util.typedef.G; +import org.apache.ignite.lang.IgniteExperimental; import org.apache.ignite.lang.IgniteProductVersion; import org.apache.ignite.plugin.IgnitePlugin; import org.apache.ignite.plugin.PluginNotFoundException; -import org.jetbrains.annotations.Nullable; +import org.apache.ignite.spi.tracing.TracingConfigurationManager; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * Main entry-point for all Ignite APIs. diff --git a/modules/core/src/main/java/org/apache/ignite/IgniteTransactions.java b/modules/core/src/main/java/org/apache/ignite/IgniteTransactions.java index 2bb7101a71928..852f923ba8cb7 100644 --- a/modules/core/src/main/java/org/apache/ignite/IgniteTransactions.java +++ b/modules/core/src/main/java/org/apache/ignite/IgniteTransactions.java @@ -124,4 +124,11 @@ public Transaction txStart(TransactionConcurrency concurrency, TransactionIsolat * @throws NullPointerException if label is null. */ public IgniteTransactions withLabel(String lb); + + /** + * Returns an instance of {@code IgniteTransactions} tran will trace every transaction. + * + * @return Trace-enabled transactions intance. + */ + public IgniteTransactions withTracing(); } 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 6b653bbe37673..77ff68e7d0fb7 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 @@ -192,7 +192,6 @@ import org.apache.ignite.internal.processors.subscription.GridInternalSubscriptionProcessor; import org.apache.ignite.internal.processors.task.GridTaskProcessor; import org.apache.ignite.internal.processors.timeout.GridTimeoutProcessor; -import org.apache.ignite.spi.tracing.TracingConfigurationManager; import org.apache.ignite.internal.suggestions.GridPerformanceSuggestions; import org.apache.ignite.internal.suggestions.JvmConfigurationSuggestions; import org.apache.ignite.internal.suggestions.OsConfigurationSuggestions; @@ -233,6 +232,7 @@ import org.apache.ignite.spi.IgniteSpiVersionCheckException; import org.apache.ignite.spi.communication.tcp.TcpCommunicationSpi; import org.apache.ignite.spi.discovery.tcp.internal.TcpDiscoveryNode; +import org.apache.ignite.spi.tracing.TracingConfigurationManager; import org.apache.ignite.thread.IgniteStripedThreadPoolExecutor; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/managers/tracing/GridTracingManager.java b/modules/core/src/main/java/org/apache/ignite/internal/managers/tracing/GridTracingManager.java index 2da83fea7b100..94bffa6a49aeb 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/managers/tracing/GridTracingManager.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/managers/tracing/GridTracingManager.java @@ -27,32 +27,32 @@ import org.apache.ignite.internal.processors.tracing.DeferredSpan; import org.apache.ignite.internal.processors.tracing.NoopSpan; import org.apache.ignite.internal.processors.tracing.NoopTracing; -import org.apache.ignite.internal.processors.tracing.SpanImpl; -import org.apache.ignite.internal.processors.tracing.configuration.GridTracingConfigurationManager; -import org.apache.ignite.spi.tracing.NoopTracingSpi; -import org.apache.ignite.spi.tracing.Scope; import org.apache.ignite.internal.processors.tracing.Span; +import org.apache.ignite.internal.processors.tracing.SpanImpl; import org.apache.ignite.internal.processors.tracing.SpanTags; import org.apache.ignite.internal.processors.tracing.SpanType; import org.apache.ignite.internal.processors.tracing.Tracing; -import org.apache.ignite.spi.tracing.SpiSpecificSpan; -import org.apache.ignite.spi.tracing.TracingConfigurationCoordinates; -import org.apache.ignite.spi.tracing.TracingConfigurationManager; -import org.apache.ignite.spi.tracing.TracingSpi; -import org.apache.ignite.spi.tracing.TracingConfigurationParameters; +import org.apache.ignite.internal.processors.tracing.configuration.GridTracingConfigurationManager; import org.apache.ignite.internal.processors.tracing.messages.TraceableMessagesHandler; import org.apache.ignite.internal.util.typedef.internal.LT; import org.apache.ignite.logger.NullLogger; import org.apache.ignite.spi.IgniteSpiException; +import org.apache.ignite.spi.tracing.NoopTracingSpi; +import org.apache.ignite.spi.tracing.Scope; +import org.apache.ignite.spi.tracing.SpiSpecificSpan; +import org.apache.ignite.spi.tracing.TracingConfigurationCoordinates; +import org.apache.ignite.spi.tracing.TracingConfigurationManager; +import org.apache.ignite.spi.tracing.TracingConfigurationParameters; +import org.apache.ignite.spi.tracing.TracingSpi; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import static org.apache.ignite.internal.processors.tracing.SpanTags.NODE; -import static org.apache.ignite.spi.tracing.TracingConfigurationParameters.SAMPLING_RATE_NEVER; import static org.apache.ignite.internal.util.GridClientByteUtils.bytesToInt; import static org.apache.ignite.internal.util.GridClientByteUtils.bytesToShort; import static org.apache.ignite.internal.util.GridClientByteUtils.intToBytes; import static org.apache.ignite.internal.util.GridClientByteUtils.shortToBytes; +import static org.apache.ignite.spi.tracing.TracingConfigurationParameters.SAMPLING_RATE_NEVER; /** * Tracing Manager. @@ -531,4 +531,4 @@ private boolean shouldSample(double samlingRate) { return Math.random() <= samlingRate; } -} \ No newline at end of file +} 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 070ffdd79f651..8b068da63ba6f 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 @@ -4363,7 +4363,8 @@ public void awaitLastFut() { !ctx.skipStore(), ctx.mvccEnabled(), 0, - null + null, + false ); assert tx != null; @@ -4481,7 +4482,8 @@ private IgniteInternalFuture asyncOp(final AsyncOp op) { !skipStore, ctx.mvccEnabled(), 0, - null); + null, + false); return asyncOp(tx, op, opCtx, /*retry*/false); } @@ -5493,7 +5495,8 @@ public void execute(boolean retry) { opCtx == null || !opCtx.skipStore(), ctx.mvccEnabled(), 0, - null); + null, + false); IgniteInternalFuture fut = asyncOp(tx, op, opCtx, retry); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java index 97d46a1af4123..31e88fe2c6e12 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/GridCacheProcessor.java @@ -577,7 +577,7 @@ private void cleanup(CacheConfiguration cfg, @Nullable Object rsrc, boolean near locCfgMgr = new GridLocalConfigManager(this, ctx); - transactions = new IgniteTransactionsImpl(sharedCtx, null); + transactions = new IgniteTransactionsImpl(sharedCtx, null, false); // Start shared managers. for (GridCacheSharedManager mgr : sharedCtx.managers()) 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 2432c5097307b..06e554c36de2a 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 @@ -64,6 +64,8 @@ import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.processors.dr.GridDrType; import org.apache.ignite.internal.processors.timeout.GridTimeoutObjectAdapter; +import org.apache.ignite.internal.processors.tracing.MTC; +import org.apache.ignite.internal.processors.tracing.Span; import org.apache.ignite.internal.util.future.GridFutureAdapter; import org.apache.ignite.internal.util.tostring.GridToStringExclude; import org.apache.ignite.internal.util.tostring.GridToStringInclude; @@ -82,6 +84,8 @@ import static org.apache.ignite.events.EventType.EVT_CACHE_REBALANCE_OBJECT_LOADED; import static org.apache.ignite.internal.processors.dr.GridDrType.DR_NONE; import static org.apache.ignite.internal.processors.dr.GridDrType.DR_PRELOAD; +import static org.apache.ignite.internal.processors.tracing.MTC.TraceSurroundings; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_DHT_LOCK_MAP; /** * Cache lock future. @@ -91,6 +95,9 @@ public final class GridDhtLockFuture extends GridCacheCompoundIdentityFuture logRef = new AtomicReference<>(); @@ -729,30 +736,32 @@ private synchronized boolean checkLocks() { /** {@inheritDoc} */ @Override public boolean onDone(@Nullable Boolean success, @Nullable Throwable err) { - // Protect against NPE. - if (success == null) { - assert err != null; + try (TraceSurroundings ignored = MTC.support(span)) { + // Protect against NPE. + if (success == null) { + assert err != null; - success = false; - } + success = false; + } - assert err == null || !success; - assert !success || (initialized() && !hasPending()) : "Invalid done callback [success=" + success + - ", fut=" + this + ']'; + assert err == null || !success; + assert !success || (initialized() && !hasPending()) : "Invalid done callback [success=" + success + + ", fut=" + this + ']'; - if (log.isDebugEnabled()) - log.debug("Received onDone(..) callback [success=" + success + ", err=" + err + ", fut=" + this + ']'); + if (log.isDebugEnabled()) + log.debug("Received onDone(..) callback [success=" + success + ", err=" + err + ", fut=" + this + ']'); - // If locks were not acquired yet, delay completion. - if (isDone() || (err == null && success && !checkLocks())) - return false; + // If locks were not acquired yet, delay completion. + if (isDone() || (err == null && success && !checkLocks())) + return false; - synchronized (this) { - if (this.err == null) - this.err = err; - } + synchronized (this) { + if (this.err == null) + this.err = err; + } - return onComplete(success, err instanceof NodeStoppingException, true); + return onComplete(success, err instanceof NodeStoppingException, true); + } } /** @@ -810,18 +819,21 @@ private synchronized boolean onComplete(boolean success, boolean stopping, boole * */ public void map() { - if (F.isEmpty(entries)) { - onComplete(true, false, true); + try (TraceSurroundings ignored = + MTC.supportContinual(span = cctx.kernalContext().tracing().create(TX_DHT_LOCK_MAP, MTC.span()))) { + if (F.isEmpty(entries)) { + onComplete(true, false, true); - return; - } + return; + } - readyLocks(); + readyLocks(); - if (timeout > 0 && !isDone()) { // Prevent memory leak if future is completed by call to readyLocks. - timeoutObj = new LockTimeoutObject(); + if (timeout > 0 && !isDone()) { // Prevent memory leak if future is completed by call to readyLocks. + timeoutObj = new LockTimeoutObject(); - cctx.time().addTimeoutObject(timeoutObj); + cctx.time().addTimeoutObject(timeoutObj); + } } } @@ -898,7 +910,8 @@ private void map(Iterable entries) { return; if (log.isDebugEnabled()) - log.debug("Mapped DHT lock future [dhtMap=" + F.nodeIds(dhtMap.keySet()) + ", dhtLockFut=" + this + ']'); + log.debug("Mapped DHT lock future [dhtMap=" + F.nodeIds(dhtMap.keySet()) + + ", dhtLockFut=" + this + ']'); long timeout = inTx() ? tx.remainingTime() : this.timeout; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxFinishFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxFinishFuture.java index 4152993628512..dbed457ee3799 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxFinishFuture.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxFinishFuture.java @@ -40,6 +40,8 @@ import org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx; import org.apache.ignite.internal.processors.cache.transactions.TxCounters; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; +import org.apache.ignite.internal.processors.tracing.MTC; +import org.apache.ignite.internal.processors.tracing.Span; import org.apache.ignite.internal.transactions.IgniteTxOptimisticCheckedException; import org.apache.ignite.internal.transactions.IgniteTxRollbackCheckedException; import org.apache.ignite.internal.transactions.IgniteTxSerializationCheckedException; @@ -57,6 +59,8 @@ import static java.util.Objects.isNull; import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC; import static org.apache.ignite.cache.CacheWriteSynchronizationMode.PRIMARY_SYNC; +import static org.apache.ignite.internal.processors.tracing.MTC.TraceSurroundings; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_DHT_FINISH; import static org.apache.ignite.transactions.TransactionState.COMMITTING; /** @@ -67,6 +71,9 @@ public final class GridDhtTxFinishFuture extends GridCacheCompoundIdentity /** */ private static final long serialVersionUID = 0L; + /** Tracing span. */ + private Span span; + /** Logger reference. */ private static final AtomicReference logRef = new AtomicReference<>(); @@ -228,58 +235,60 @@ public void onResult(UUID nodeId, GridDhtTxFinishResponse res) { /** {@inheritDoc} */ @Override public boolean onDone(IgniteInternalTx tx, Throwable err) { - if (initialized() || err != null) { - Throwable e = this.err; + try (TraceSurroundings ignored = MTC.support(span)) { + if (initialized() || err != null) { + Throwable e = this.err; - if (this.tx.onePhaseCommit() && (this.tx.state() == COMMITTING)) { - try { - boolean nodeStopping = X.hasCause(err, NodeStoppingException.class); + if (this.tx.onePhaseCommit() && (this.tx.state() == COMMITTING)) { + try { + boolean nodeStopping = X.hasCause(err, NodeStoppingException.class); - this.tx.tmFinish(err == null, nodeStopping || cctx.kernalContext().failure().nodeStopping(), false); - } - catch (IgniteCheckedException finishErr) { - U.error(log, "Failed to finish tx: " + tx, e); + this.tx.tmFinish(err == null, nodeStopping || cctx.kernalContext().failure().nodeStopping(), false); + } + catch (IgniteCheckedException finishErr) { + U.error(log, "Failed to finish tx: " + tx, e); - if (e == null) - e = finishErr; + if (e == null) + e = finishErr; + } } - } - if (commit && e == null) - e = this.tx.commitError(); + if (commit && e == null) + e = this.tx.commitError(); - Throwable finishErr = e != null ? e : err; + Throwable finishErr = e != null ? e : err; - if (super.onDone(tx, finishErr)) { - cctx.tm().mvccFinish(this.tx); + if (super.onDone(tx, finishErr)) { + cctx.tm().mvccFinish(this.tx); - if (finishErr == null) - finishErr = this.tx.commitError(); + if (finishErr == null) + finishErr = this.tx.commitError(); - if (this.tx.syncMode() != PRIMARY_SYNC) - this.tx.sendFinishReply(finishErr); + if (this.tx.syncMode() != PRIMARY_SYNC) + this.tx.sendFinishReply(finishErr); - if (!this.tx.txState().mvccEnabled() && !commit && shouldApplyCountersOnRollbackError(finishErr)) { - TxCounters txCounters = this.tx.txCounters(false); + if (!this.tx.txState().mvccEnabled() && !commit && shouldApplyCountersOnRollbackError(finishErr)) { + TxCounters txCounters = this.tx.txCounters(false); - if (txCounters != null) { - try { - cctx.tm().txHandler().applyPartitionsUpdatesCounters(txCounters.updateCounters(), true, true); - } - catch (IgniteCheckedException e0) { - throw new IgniteException(e0); + if (txCounters != null) { + try { + cctx.tm().txHandler().applyPartitionsUpdatesCounters(txCounters.updateCounters(), true, true); + } + catch (IgniteCheckedException e0) { + throw new IgniteException(e0); + } } } - } - // Don't forget to clean up. - cctx.mvcc().removeFuture(futId); + // Don't forget to clean up. + cctx.mvcc().removeFuture(futId); - return true; + return true; + } } - } - return false; + return false; + } } /** @@ -317,22 +326,25 @@ private void onComplete() { */ @SuppressWarnings({"SimplifiableIfStatement"}) public void finish(boolean commit) { - boolean sync; + try (MTC.TraceSurroundings ignored = + MTC.supportContinual(span = cctx.kernalContext().tracing().create(TX_DHT_FINISH, MTC.span()))) { + boolean sync; - assert !tx.txState().mvccEnabled() || tx.mvccSnapshot() != null; + assert !tx.txState().mvccEnabled() || tx.mvccSnapshot() != null; - if (!F.isEmpty(dhtMap) || !F.isEmpty(nearMap)) - sync = finish(commit, dhtMap, nearMap); - else if (!commit && !F.isEmpty(tx.lockTransactionNodes())) - sync = rollbackLockTransactions(tx.lockTransactionNodes()); - else - // No backup or near nodes to send commit message to (just complete then). - sync = false; + if (!F.isEmpty(dhtMap) || !F.isEmpty(nearMap)) + sync = finish(commit, dhtMap, nearMap); + else if (!commit && !F.isEmpty(tx.lockTransactionNodes())) + sync = rollbackLockTransactions(tx.lockTransactionNodes()); + else + // No backup or near nodes to send commit message to (just complete then). + sync = false; - markInitialized(); + markInitialized(); - if (!sync) - onComplete(); + if (!sync) + onComplete(); + } } /** 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 2902d616e6176..6c30c54d6eb78 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 @@ -45,6 +45,8 @@ import org.apache.ignite.internal.processors.cache.transactions.IgniteTxLocalAdapter; import org.apache.ignite.internal.processors.cache.transactions.TxCounters; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; +import org.apache.ignite.internal.processors.tracing.NoopSpan; +import org.apache.ignite.internal.processors.tracing.Span; import org.apache.ignite.internal.util.F0; import org.apache.ignite.internal.util.GridLeanMap; import org.apache.ignite.internal.util.GridLeanSet; @@ -118,6 +120,9 @@ protected GridDhtTxLocalAdapter() { // No-op. } + /** Tracing span. */ + private Span span = NoopSpan.INSTANCE; + /** * @param xidVer Transaction version. * @param implicit Implicit flag. @@ -936,6 +941,20 @@ protected final IgniteInternalFuture chainOnePhasePre return prepFut; } + /** + * @return Tracing span. + */ + public Span span() { + return span; + } + + /** + * @param span New tracing span. + */ + public void span(Span span) { + this.span = span; + } + /** {@inheritDoc} */ @Override public String toString() { return GridToStringBuilder.toString(GridDhtTxLocalAdapter.class, this, "nearNodes", nearMap.keySet(), diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareFuture.java index 2ad04b48b4f61..c0acc2b21126c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareFuture.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/GridDhtTxPrepareFuture.java @@ -75,6 +75,8 @@ import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.processors.dr.GridDrType; import org.apache.ignite.internal.processors.timeout.GridTimeoutObjectAdapter; +import org.apache.ignite.internal.processors.tracing.MTC; +import org.apache.ignite.internal.processors.tracing.Span; import org.apache.ignite.internal.transactions.IgniteTxOptimisticCheckedException; import org.apache.ignite.internal.transactions.IgniteTxRollbackCheckedException; import org.apache.ignite.internal.util.GridLeanSet; @@ -105,6 +107,8 @@ import static org.apache.ignite.internal.processors.cache.GridCacheOperation.READ; import static org.apache.ignite.internal.processors.cache.GridCacheOperation.TRANSFORM; import static org.apache.ignite.internal.processors.cache.GridCacheOperation.UPDATE; +import static org.apache.ignite.internal.processors.tracing.MTC.TraceSurroundings; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_DHT_PREPARE; import static org.apache.ignite.internal.util.lang.GridFunc.isEmpty; import static org.apache.ignite.transactions.TransactionState.PREPARED; @@ -117,6 +121,9 @@ public final class GridDhtTxPrepareFuture extends GridCacheCompoundFuture logRef = new AtomicReference<>(); @@ -737,104 +744,106 @@ private boolean mapIfLocked() { /** {@inheritDoc} */ @Override public boolean onDone(GridNearTxPrepareResponse res0, Throwable err) { - assert err != null || (initialized() && !hasPending()) : "On done called for prepare future that has " + - "pending mini futures: " + this; + try (TraceSurroundings ignored2 = MTC.support(span)) { + assert err != null || (initialized() && !hasPending()) : "On done called for prepare future that has " + + "pending mini futures: " + this; - ERR_UPD.compareAndSet(this, null, err); + ERR_UPD.compareAndSet(this, null, err); - // Must clear prepare future before response is sent or listeners are notified. - if (tx.optimistic()) - tx.clearPrepareFuture(this); + // Must clear prepare future before response is sent or listeners are notified. + if (tx.optimistic()) + tx.clearPrepareFuture(this); - // Do not commit one-phase commit transaction if originating node has near cache enabled. - if (tx.commitOnPrepare()) { - assert last; + // Do not commit one-phase commit transaction if originating node has near cache enabled. + if (tx.commitOnPrepare()) { + assert last; - Throwable prepErr = this.err; + Throwable prepErr = this.err; - // Must create prepare response before transaction is committed to grab correct return value. - final GridNearTxPrepareResponse res = createPrepareResponse(prepErr); + // Must create prepare response before transaction is committed to grab correct return value. + final GridNearTxPrepareResponse res = createPrepareResponse(prepErr); - onComplete(res); + onComplete(res); - if (tx.markFinalizing(IgniteInternalTx.FinalizationStatus.USER_FINISH)) { - CIX1> resClo = - new CIX1>() { - @Override public void applyx(IgniteInternalFuture fut) { - if (res.error() == null && fut.error() != null) - res.error(fut.error()); + if (tx.markFinalizing(IgniteInternalTx.FinalizationStatus.USER_FINISH)) { + CIX1> resClo = + new CIX1>() { + @Override public void applyx(IgniteInternalFuture fut) { + if (res.error() == null && fut.error() != null) + res.error(fut.error()); - if (REPLIED_UPD.compareAndSet(GridDhtTxPrepareFuture.this, 0, 1)) - sendPrepareResponse(res); - } - }; + if (REPLIED_UPD.compareAndSet(GridDhtTxPrepareFuture.this, 0, 1)) + sendPrepareResponse(res); + } + }; - try { - if (prepErr == null) { - try { - tx.commitAsync().listen(resClo); - } - catch (Throwable e) { - res.error(e); + try { + if (prepErr == null) { + try { + tx.commitAsync().listen(resClo); + } + catch (Throwable e) { + res.error(e); + + tx.systemInvalidate(true); - tx.systemInvalidate(true); + try { + tx.rollbackAsync().listen(resClo); + } + catch (Throwable e1) { + e.addSuppressed(e1); + } + throw e; + } + } + else if (!cctx.kernalContext().isStopping()) { try { tx.rollbackAsync().listen(resClo); } - catch (Throwable e1) { - e.addSuppressed(e1); - } + catch (Throwable e) { + if (err != null) + err.addSuppressed(e); - throw e; + throw err; + } } } - else if (!cctx.kernalContext().isStopping()) { - try { - tx.rollbackAsync().listen(resClo); - } - catch (Throwable e) { - if (err != null) - err.addSuppressed(e); + catch (Throwable e) { + tx.logTxFinishErrorSafe(log, true, e); - throw err; - } + cctx.kernalContext().failure().process(new FailureContext(FailureType.CRITICAL_ERROR, e)); } } - catch (Throwable e) { - tx.logTxFinishErrorSafe(log, true, e); - cctx.kernalContext().failure().process(new FailureContext(FailureType.CRITICAL_ERROR, e)); - } + return true; } + else { + if (REPLIED_UPD.compareAndSet(this, 0, 1)) { + GridNearTxPrepareResponse res = createPrepareResponse(this.err); - return true; - } - else { - if (REPLIED_UPD.compareAndSet(this, 0, 1)) { - GridNearTxPrepareResponse res = createPrepareResponse(this.err); - - // Will call super.onDone(). - onComplete(res); + // Will call super.onDone(). + onComplete(res); - sendPrepareResponse(res); + sendPrepareResponse(res); - return true; - } - else { - // Other thread is completing future. Wait for it to complete. - try { - if (err != null) - get(); - } - catch (IgniteInterruptedException e) { - onError(new IgniteCheckedException("Got interrupted while waiting for replies to be sent.", e)); - } - catch (IgniteCheckedException ignored) { - // No-op, get() was just synchronization. + return true; } + else { + // Other thread is completing future. Wait for it to complete. + try { + if (err != null) + get(); + } + catch (IgniteInterruptedException e) { + onError(new IgniteCheckedException("Got interrupted while waiting for replies to be sent.", e)); + } + catch (IgniteCheckedException ignored) { + // No-op, get() was just synchronization. + } - return false; + return false; + } } } } @@ -1044,18 +1053,19 @@ public void complete() { */ public void prepare(GridNearTxPrepareRequest req) { assert req != null; + try (MTC.TraceSurroundings ignored = + MTC.supportContinual(span = cctx.kernalContext().tracing().create(TX_DHT_PREPARE, MTC.span()))) { + if (tx.empty() && !req.queryUpdate()) { + tx.setRollbackOnly(); - if (tx.empty() && !req.queryUpdate()) { - tx.setRollbackOnly(); - - onDone((GridNearTxPrepareResponse)null); - } + onDone((GridNearTxPrepareResponse)null); + } - this.req = req; + this.req = req; - ClusterNode node = cctx.discovery().node(tx.topologyVersion(), tx.nearNodeId()); + ClusterNode node = cctx.discovery().node(tx.topologyVersion(), tx.nearNodeId()); - boolean validateCache = needCacheValidation(node); + boolean validateCache = needCacheValidation(node); boolean writesEmpty = isEmpty(req.writes()); @@ -1070,35 +1080,36 @@ public void prepare(GridNearTxPrepareRequest req) { } } - boolean ser = tx.serializable() && tx.optimistic(); + boolean ser = tx.serializable() && tx.optimistic(); if (!writesEmpty || (ser && !F.isEmpty(req.reads()))) { Map> forceKeys = null; - for (IgniteTxEntry entry : req.writes()) - forceKeys = checkNeedRebalanceKeys(entry, forceKeys); - - if (ser) { - for (IgniteTxEntry entry : req.reads()) + for (IgniteTxEntry entry : req.writes()) forceKeys = checkNeedRebalanceKeys(entry, forceKeys); + + if (ser) { + for (IgniteTxEntry entry : req.reads()) + forceKeys = checkNeedRebalanceKeys(entry, forceKeys); + } + + forceKeysFut = forceRebalanceKeys(forceKeys); } - forceKeysFut = forceRebalanceKeys(forceKeys); - } + readyLocks(); - readyLocks(); + // Start timeout tracking after 'readyLocks' to avoid race with timeout processing. + if (timeoutObj != null) { + cctx.time().addTimeoutObject(timeoutObj); - // Start timeout tracking after 'readyLocks' to avoid race with timeout processing. - if (timeoutObj != null) { - cctx.time().addTimeoutObject(timeoutObj); + // Fix race with add/remove timeout object if locks are mapped from another + // thread before timeout object is enqueued. + if (tx.onePhaseCommit()) + timeoutAddedLatch.countDown(); + } - // Fix race with add/remove timeout object if locks are mapped from another - // thread before timeout object is enqueued. - if (tx.onePhaseCommit()) - timeoutAddedLatch.countDown(); + mapIfLocked(); } - - mapIfLocked(); } /** diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/colocated/GridDhtColocatedLockFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/colocated/GridDhtColocatedLockFuture.java index 43fb30aa5fb61..8b6ebedcbe05c 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/colocated/GridDhtColocatedLockFuture.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/dht/colocated/GridDhtColocatedLockFuture.java @@ -62,6 +62,9 @@ import org.apache.ignite.internal.processors.cache.transactions.TxDeadlock; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.processors.timeout.GridTimeoutObjectAdapter; +import org.apache.ignite.internal.processors.tracing.MTC; +import org.apache.ignite.internal.processors.tracing.Span; +import org.apache.ignite.internal.processors.tracing.SpanType; import org.apache.ignite.internal.transactions.IgniteTxTimeoutCheckedException; import org.apache.ignite.internal.util.future.GridEmbeddedFuture; import org.apache.ignite.internal.util.future.GridFutureAdapter; @@ -82,6 +85,8 @@ import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC; import static org.apache.ignite.events.EventType.EVT_CACHE_OBJECT_READ; +import static org.apache.ignite.internal.processors.tracing.MTC.TraceSurroundings; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_COLOCATED_LOCK_MAP; /** * Colocated cache lock future. @@ -91,6 +96,9 @@ public final class GridDhtColocatedLockFuture extends GridCacheCompoundIdentityF /** */ private static final long serialVersionUID = 0L; + /** Tracing span. */ + private Span span; + /** Logger reference. */ private static final AtomicReference logRef = new AtomicReference<>(); @@ -598,23 +606,25 @@ private synchronized void onError(Throwable t) { /** {@inheritDoc} */ @Override public boolean onDone(Boolean success, Throwable err) { - if (log.isDebugEnabled()) - log.debug("Received onDone(..) callback [success=" + success + ", err=" + err + ", fut=" + this + ']'); + try (TraceSurroundings ignored = MTC.support(span)) { + if (log.isDebugEnabled()) + log.debug("Received onDone(..) callback [success=" + success + ", err=" + err + ", fut=" + this + ']'); - // Local GridDhtLockFuture - if (inTx() && this.err instanceof IgniteTxTimeoutCheckedException && cctx.tm().deadlockDetectionEnabled()) - return false; + // Local GridDhtLockFuture + if (inTx() && this.err instanceof IgniteTxTimeoutCheckedException && cctx.tm().deadlockDetectionEnabled()) + return false; - if (isDone()) - return false; + if (isDone()) + return false; - if (err != null) - onError(err); + if (err != null) + onError(err); - if (err != null) - success = false; + if (err != null) + success = false; - return onComplete(success, true); + return onComplete(success, true); + } } /** @@ -752,75 +762,80 @@ private boolean isMini(IgniteInternalFuture f) { * part. Note that if primary node leaves grid, the future will fail and transaction will be rolled back. */ void map() { - if (isDone()) // Possible due to async rollback. - return; + try (TraceSurroundings ignored = + MTC.supportContinual(span = cctx.kernalContext().tracing().create(TX_COLOCATED_LOCK_MAP, MTC.span()))) { + if (isDone()) // Possible due to async rollback. + return; - if (timeout > 0) { - timeoutObj = new LockTimeoutObject(); + if (timeout > 0) { + timeoutObj = new LockTimeoutObject(); - cctx.time().addTimeoutObject(timeoutObj); - } + cctx.time().addTimeoutObject(timeoutObj); + } - // Obtain the topology version to use. - AffinityTopologyVersion topVer = cctx.mvcc().lastExplicitLockTopologyVersion(threadId); + // Obtain the topology version to use. + AffinityTopologyVersion topVer = cctx.mvcc().lastExplicitLockTopologyVersion(threadId); - // If there is another system transaction in progress, use it's topology version to prevent deadlock. - if (topVer == null && tx != null && tx.system()) - topVer = cctx.tm().lockedTopologyVersion(Thread.currentThread().getId(), tx); + // If there is another system transaction in progress, use it's topology version to prevent deadlock. + if (topVer == null && tx != null && tx.system()) + topVer = cctx.tm().lockedTopologyVersion(Thread.currentThread().getId(), tx); - if (topVer != null && tx != null) - tx.topologyVersion(topVer); + if (topVer != null && tx != null) + tx.topologyVersion(topVer); - if (topVer == null && tx != null) - topVer = tx.topologyVersionSnapshot(); + if (topVer == null && tx != null) + topVer = tx.topologyVersionSnapshot(); - if (topVer != null) { - AffinityTopologyVersion lastChangeVer = cctx.shared().exchange().lastAffinityChangedTopologyVersion(topVer); + if (topVer != null) { + AffinityTopologyVersion lastChangeVer = + cctx.shared().exchange().lastAffinityChangedTopologyVersion(topVer); - IgniteInternalFuture affFut = cctx.shared().exchange().affinityReadyFuture(lastChangeVer); + IgniteInternalFuture affFut = + cctx.shared().exchange().affinityReadyFuture(lastChangeVer); - if (!affFut.isDone()) { - try { - affFut.get(); - } - catch (IgniteCheckedException e) { - onDone(err); + if (!affFut.isDone()) { + try { + affFut.get(); + } + catch (IgniteCheckedException e) { + onDone(err); - return; + return; + } } - } - for (GridDhtTopologyFuture fut : cctx.shared().exchange().exchangeFutures()) { - if (fut.exchangeDone() && fut.topologyVersion().equals(lastChangeVer)) { - Throwable err = fut.validateCache(cctx, recovery, read, null, keys); + for (GridDhtTopologyFuture fut : cctx.shared().exchange().exchangeFutures()) { + if (fut.exchangeDone() && fut.topologyVersion().equals(lastChangeVer)) { + Throwable err = fut.validateCache(cctx, recovery, read, null, keys); - if (err != null) { - onDone(err); + if (err != null) { + onDone(err); - return; + return; + } + + break; } + } - break; + // Continue mapping on the same topology version as it was before. + synchronized (this) { + if (this.topVer == null) + this.topVer = topVer; } - } - // Continue mapping on the same topology version as it was before. - synchronized (this) { - if (this.topVer == null) - this.topVer = topVer; - } + cctx.mvcc().addFuture(this); - cctx.mvcc().addFuture(this); + map(keys, false, true); - map(keys, false, true); + markInitialized(); - markInitialized(); + return; + } - return; + // Must get topology snapshot and map on that version. + mapOnTopology(false, null); } - - // Must get topology snapshot and map on that version. - mapOnTopology(false, null); } /** @@ -1172,14 +1187,17 @@ private synchronized void map0( * @throws IgniteCheckedException If failed. */ private void proceedMapping() throws IgniteCheckedException { - boolean set = tx != null && cctx.shared().tm().setTxTopologyHint(tx.topologyVersionSnapshot()); + try (TraceSurroundings ignored = + MTC.support(cctx.kernalContext().tracing().create(SpanType.TX_MAP_PROCEED, MTC.span()))) { + boolean set = tx != null && cctx.shared().tm().setTxTopologyHint(tx.topologyVersionSnapshot()); - try { - proceedMapping0(); - } - finally { - if (set) - cctx.tm().setTxTopologyHint(null); + try { + proceedMapping0(); + } + finally { + if (set) + cctx.tm().setTxTopologyHint(null); + } } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticSerializableTxPrepareFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticSerializableTxPrepareFuture.java index 1a7cfb07331af..82672e601462b 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticSerializableTxPrepareFuture.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticSerializableTxPrepareFuture.java @@ -41,6 +41,7 @@ import org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx; import org.apache.ignite.internal.processors.cache.transactions.IgniteTxEntry; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; +import org.apache.ignite.internal.processors.tracing.MTC; import org.apache.ignite.internal.transactions.IgniteTxOptimisticCheckedException; import org.apache.ignite.internal.transactions.IgniteTxRollbackCheckedException; import org.apache.ignite.internal.util.future.GridCompoundFuture; @@ -60,6 +61,7 @@ import org.jetbrains.annotations.Nullable; import static org.apache.ignite.internal.processors.cache.GridCacheOperation.TRANSFORM; +import static org.apache.ignite.internal.processors.tracing.MTC.TraceSurroundings; import static org.apache.ignite.transactions.TransactionState.PREPARED; import static org.apache.ignite.transactions.TransactionState.PREPARING; @@ -170,22 +172,24 @@ public GridNearOptimisticSerializableTxPrepareFuture(GridCacheSharedContext cctx * @param e Error. */ private void onError(@Nullable GridDistributedTxMapping m, Throwable e) { - if (X.hasCause(e, ClusterTopologyCheckedException.class) || X.hasCause(e, ClusterTopologyException.class)) { - if (tx.onePhaseCommit()) { - tx.markForBackupCheck(); + try (TraceSurroundings ignored = MTC.support(span)) { + if (X.hasCause(e, ClusterTopologyCheckedException.class) || X.hasCause(e, ClusterTopologyException.class)) { + if (tx.onePhaseCommit()) { + tx.markForBackupCheck(); - onComplete(); + onComplete(); - return; + return; + } } - } - if (e instanceof IgniteTxOptimisticCheckedException) { - if (m != null) - tx.removeMapping(m.primary().id()); - } + if (e instanceof IgniteTxOptimisticCheckedException) { + if (m != null) + tx.removeMapping(m.primary().id()); + } - prepareError(e); + prepareError(e); + } } /** @@ -210,17 +214,19 @@ private void prepareError(Throwable e) { /** {@inheritDoc} */ @Override public boolean onDone(IgniteInternalTx t, Throwable err) { - if (isDone()) - return false; + try (TraceSurroundings ignored = MTC.support(span)) { + if (isDone()) + return false; - if (err != null) { - ERR_UPD.compareAndSet(this, null, err); + if (err != null) { + ERR_UPD.compareAndSet(this, null, err); - if (keyLockFut != null) - keyLockFut.onDone(err); - } + if (keyLockFut != null) + keyLockFut.onDone(err); + } - return onComplete(); + return onComplete(); + } } /** diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFuture.java index 71d436f8a4b5d..095497477abdb 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFuture.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFuture.java @@ -48,6 +48,7 @@ import org.apache.ignite.internal.processors.cache.transactions.IgniteTxKey; import org.apache.ignite.internal.processors.cache.transactions.TxDeadlock; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; +import org.apache.ignite.internal.processors.tracing.MTC; import org.apache.ignite.internal.transactions.IgniteTxRollbackCheckedException; import org.apache.ignite.internal.transactions.IgniteTxTimeoutCheckedException; import org.apache.ignite.internal.util.future.GridEmbeddedFuture; @@ -67,6 +68,8 @@ import org.jetbrains.annotations.Nullable; import static org.apache.ignite.internal.processors.cache.GridCacheOperation.TRANSFORM; +import static org.apache.ignite.internal.processors.tracing.MTC.TraceSurroundings; +import static org.apache.ignite.internal.processors.tracing.MTC.support; import static org.apache.ignite.transactions.TransactionState.PREPARED; import static org.apache.ignite.transactions.TransactionState.PREPARING; @@ -139,24 +142,26 @@ public GridNearOptimisticTxPrepareFuture(GridCacheSharedContext cctx, GridNearTx * @param discoThread {@code True} if executed from discovery thread. */ private void onError(Throwable e, boolean discoThread) { - if (e instanceof IgniteTxTimeoutCheckedException) { - onTimeout(); + try (TraceSurroundings ignored = support(span)) { + if (e instanceof IgniteTxTimeoutCheckedException) { + onTimeout(); - return; - } + return; + } - if (X.hasCause(e, ClusterTopologyCheckedException.class) || X.hasCause(e, ClusterTopologyException.class)) { - if (tx.onePhaseCommit()) { - tx.markForBackupCheck(); + if (X.hasCause(e, ClusterTopologyCheckedException.class) || X.hasCause(e, ClusterTopologyException.class)) { + if (tx.onePhaseCommit()) { + tx.markForBackupCheck(); - onComplete(); + onComplete(); - return; + return; + } } - } - if (ERR_UPD.compareAndSet(this, null, e)) - onComplete(); + if (ERR_UPD.compareAndSet(this, null, e)) + onComplete(); + } } /** {@inheritDoc} */ @@ -250,12 +255,14 @@ private MiniFuture miniFuture(int miniId) { /** {@inheritDoc} */ @Override public boolean onDone(IgniteInternalTx t, Throwable err) { - if (isDone()) - return false; + try (TraceSurroundings ignored = MTC.support(span)) { + if (isDone()) + return false; - ERR_UPD.compareAndSet(this, null, err); + ERR_UPD.compareAndSet(this, null, err); - return onComplete(); + return onComplete(); + } } /** @@ -704,59 +711,61 @@ else if (!cacheCtx.isLocal()) * */ private void onTimeout() { - if (cctx.tm().deadlockDetectionEnabled()) { - Set keys = null; + try (TraceSurroundings ignored = MTC.support(span)) { + if (cctx.tm().deadlockDetectionEnabled()) { + Set keys = null; - if (keyLockFut != null) - keys = new HashSet<>(keyLockFut.lockKeys); - else { - synchronized (this) { - int size = futuresCountNoLock(); + if (keyLockFut != null) + keys = new HashSet<>(keyLockFut.lockKeys); + else { + synchronized (this) { + int size = futuresCountNoLock(); - for (int i = 0; i < size; i++) { - IgniteInternalFuture fut = future(i); + for (int i = 0; i < size; i++) { + IgniteInternalFuture fut = future(i); - if (isMini(fut) && !fut.isDone()) { - MiniFuture miniFut = (MiniFuture)fut; + if (isMini(fut) && !fut.isDone()) { + MiniFuture miniFut = (MiniFuture)fut; - Collection entries = miniFut.mapping().entries(); + Collection entries = miniFut.mapping().entries(); - keys = U.newHashSet(entries.size()); + keys = U.newHashSet(entries.size()); - for (IgniteTxEntry entry : entries) - keys.add(entry.txKey()); + for (IgniteTxEntry entry : entries) + keys.add(entry.txKey()); - break; + break; + } } } } - } - add(new GridEmbeddedFuture<>(new IgniteBiClosure() { - @Override public GridNearTxPrepareResponse apply(TxDeadlock deadlock, Exception e) { - if (e != null) - U.warn(log, "Failed to detect deadlock.", e); - else { - e = new IgniteTxTimeoutCheckedException("Failed to acquire lock within provided timeout for " + - "transaction [timeout=" + tx.timeout() + ", tx=" + CU.txString(tx) + ']', - deadlock != null ? new TransactionDeadlockException(deadlock.toString(cctx)) : null); + add(new GridEmbeddedFuture<>(new IgniteBiClosure() { + @Override public GridNearTxPrepareResponse apply(TxDeadlock deadlock, Exception e) { + if (e != null) + U.warn(log, "Failed to detect deadlock.", e); + else { + e = new IgniteTxTimeoutCheckedException("Failed to acquire lock within provided timeout for " + + "transaction [timeout=" + tx.timeout() + ", tx=" + CU.txString(tx) + ']', + deadlock != null ? new TransactionDeadlockException(deadlock.toString(cctx)) : null); - if (!ERR_UPD.compareAndSet(GridNearOptimisticTxPrepareFuture.this, null, e) && err instanceof IgniteTxTimeoutCheckedException) { - err = e; + if (!ERR_UPD.compareAndSet(GridNearOptimisticTxPrepareFuture.this, null, e) && err instanceof IgniteTxTimeoutCheckedException) { + err = e; + } } - } - onDone(null, e); + onDone(null, e); - return null; - } - }, cctx.tm().detectDeadlock(tx, keys))); - } - else { - ERR_UPD.compareAndSet(this, null, new IgniteTxTimeoutCheckedException("Failed to acquire lock " + - "within provided timeout for transaction [timeout=" + tx.timeout() + ", tx=" + tx + ']')); + return null; + } + }, cctx.tm().detectDeadlock(tx, keys))); + } + else { + ERR_UPD.compareAndSet(this, null, new IgniteTxTimeoutCheckedException("Failed to acquire lock " + + "within provided timeout for transaction [timeout=" + tx.timeout() + ", tx=" + tx + ']')); - onComplete(); + onComplete(); + } } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFutureAdapter.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFutureAdapter.java index eee66121d3d30..c0fbfc23538f0 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFutureAdapter.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearOptimisticTxPrepareFutureAdapter.java @@ -25,6 +25,8 @@ import org.apache.ignite.internal.processors.cache.distributed.dht.GridDhtTopologyFuture; import org.apache.ignite.internal.processors.cache.transactions.IgniteTxEntry; import org.apache.ignite.internal.processors.cache.transactions.IgniteTxKey; +import org.apache.ignite.internal.processors.tracing.MTC; +import org.apache.ignite.internal.processors.tracing.Span; import org.apache.ignite.internal.transactions.IgniteTxRollbackCheckedException; import org.apache.ignite.internal.transactions.IgniteTxTimeoutCheckedException; import org.apache.ignite.internal.util.GridConcurrentHashSet; @@ -35,6 +37,9 @@ import org.apache.ignite.internal.util.typedef.internal.S; import org.jetbrains.annotations.Nullable; +import static org.apache.ignite.internal.processors.tracing.MTC.TraceSurroundings; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_NEAR_PREPARE; + /** * */ @@ -42,6 +47,9 @@ public abstract class GridNearOptimisticTxPrepareFutureAdapter extends GridNearT /** */ private static final long serialVersionUID = 7460376140787916619L; + /** Tracing span. */ + protected Span span; + /** */ @GridToStringExclude protected KeyLockFuture keyLockFut; @@ -80,40 +88,46 @@ protected GridNearOptimisticTxPrepareFutureAdapter(GridCacheSharedContext cctx, /** {@inheritDoc} */ @Override public final void onNearTxLocalTimeout() { - if (keyLockFut != null && !keyLockFut.isDone()) { - ERR_UPD.compareAndSet(this, null, new IgniteTxTimeoutCheckedException("Failed to acquire lock " + - "within provided timeout for transaction [timeout=" + tx.timeout() + ", tx=" + tx + ']')); + try (TraceSurroundings ignored = MTC.support(span)) { + if (keyLockFut != null && !keyLockFut.isDone()) { + ERR_UPD.compareAndSet(this, null, new IgniteTxTimeoutCheckedException( + "Failed to acquire lock within provided timeout for transaction [timeout=" + tx.timeout() + + ", tx=" + tx + ']')); - keyLockFut.onDone(); + keyLockFut.onDone(); + } } } /** {@inheritDoc} */ @Override public final void prepare() { - // Obtain the topology version to use. - long threadId = Thread.currentThread().getId(); + try (TraceSurroundings ignored = + MTC.supportContinual(span = cctx.kernalContext().tracing().create(TX_NEAR_PREPARE, MTC.span()))) { + // Obtain the topology version to use. + long threadId = Thread.currentThread().getId(); - AffinityTopologyVersion topVer = cctx.mvcc().lastExplicitLockTopologyVersion(threadId); + AffinityTopologyVersion topVer = cctx.mvcc().lastExplicitLockTopologyVersion(threadId); - // If there is another system transaction in progress, use it's topology version to prevent deadlock. - if (topVer == null && tx.system()) { - topVer = cctx.tm().lockedTopologyVersion(threadId, tx); + // If there is another system transaction in progress, use it's topology version to prevent deadlock. + if (topVer == null && tx.system()) { + topVer = cctx.tm().lockedTopologyVersion(threadId, tx); - if (topVer == null) - topVer = tx.topologyVersionSnapshot(); - } + if (topVer == null) + topVer = tx.topologyVersionSnapshot(); + } - if (topVer != null) { - tx.topologyVersion(topVer); + if (topVer != null) { + tx.topologyVersion(topVer); - cctx.mvcc().addFuture(this); + cctx.mvcc().addFuture(this); - prepare0(false, true); + prepare0(false, true); - return; - } + return; + } - prepareOnTopology(false, null); + prepareOnTopology(false, null); + } } /** diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearPessimisticTxPrepareFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearPessimisticTxPrepareFuture.java index 4680e66f08c7e..5300ad3cd2428 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearPessimisticTxPrepareFuture.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearPessimisticTxPrepareFuture.java @@ -38,6 +38,8 @@ import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionTopology; import org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx; import org.apache.ignite.internal.processors.cache.transactions.IgniteTxEntry; +import org.apache.ignite.internal.processors.tracing.MTC; +import org.apache.ignite.internal.processors.tracing.Span; import org.apache.ignite.internal.transactions.IgniteTxTimeoutCheckedException; import org.apache.ignite.internal.util.future.GridFutureAdapter; import org.apache.ignite.internal.util.typedef.C1; @@ -48,6 +50,8 @@ import org.jetbrains.annotations.Nullable; import static org.apache.ignite.internal.processors.cache.GridCacheOperation.TRANSFORM; +import static org.apache.ignite.internal.processors.tracing.MTC.TraceSurroundings; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_NEAR_PREPARE; import static org.apache.ignite.transactions.TransactionState.PREPARED; import static org.apache.ignite.transactions.TransactionState.PREPARING; @@ -58,6 +62,9 @@ public class GridNearPessimisticTxPrepareFuture extends GridNearTxPrepareFutureA /** */ private static final long serialVersionUID = 4014479758215810181L; + /** Tracing span. */ + private Span span; + /** * @param cctx Context. * @param tx Transaction. @@ -166,29 +173,32 @@ private MiniFuture miniFuture(int miniId) { /** {@inheritDoc} */ @Override public void prepare() { - if (!tx.state(PREPARING)) { - if (tx.isRollbackOnly() || tx.setRollbackOnly()) { - if (tx.remainingTime() == -1) - onDone(tx.timeoutException()); + try (TraceSurroundings ignored = + MTC.supportContinual(span = cctx.kernalContext().tracing().create(TX_NEAR_PREPARE, MTC.span()))) { + if (!tx.state(PREPARING)) { + if (tx.isRollbackOnly() || tx.setRollbackOnly()) { + if (tx.remainingTime() == -1) + onDone(tx.timeoutException()); + else + onDone(tx.rollbackException()); + } else - onDone(tx.rollbackException()); - } - else - onDone(new IgniteCheckedException("Invalid transaction state for prepare " + - "[state=" + tx.state() + ", tx=" + this + ']')); + onDone(new IgniteCheckedException("Invalid transaction state for prepare " + + "[state=" + tx.state() + ", tx=" + this + ']')); - return; - } + return; + } - try { - tx.userPrepare(Collections.emptyList()); + try { + tx.userPrepare(Collections.emptyList()); - cctx.mvcc().addFuture(this); + cctx.mvcc().addFuture(this); - preparePessimistic(); - } - catch (IgniteCheckedException e) { - onDone(e); + preparePessimistic(); + } + catch (IgniteCheckedException e) { + onDone(e); + } } } @@ -433,22 +443,24 @@ private void preparePessimistic() { /** {@inheritDoc} */ @Override public boolean onDone(@Nullable IgniteInternalTx res, @Nullable Throwable err) { - if (err != null) - ERR_UPD.compareAndSet(GridNearPessimisticTxPrepareFuture.this, null, err); + try (TraceSurroundings ignored = MTC.support(span)) { + if (err != null) + ERR_UPD.compareAndSet(GridNearPessimisticTxPrepareFuture.this, null, err); - err = this.err; + err = this.err; - if ((!tx.onePhaseCommit() || tx.mappings().get(cctx.localNodeId()) == null) && - (err == null || tx.needCheckBackup())) - tx.state(PREPARED); + if ((!tx.onePhaseCommit() || tx.mappings().get(cctx.localNodeId()) == null) && + (err == null || tx.needCheckBackup())) + tx.state(PREPARED); - if (super.onDone(tx, err)) { - cctx.mvcc().removeVersionedFuture(this); + if (super.onDone(tx, err)) { + cctx.mvcc().removeVersionedFuture(this); - return true; - } + return true; + } - return false; + return false; + } } /** {@inheritDoc} */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxFinishFuture.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxFinishFuture.java index cc1509b1c9d04..fc239da9c5f0a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxFinishFuture.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/distributed/near/GridNearTxFinishFuture.java @@ -43,6 +43,8 @@ import org.apache.ignite.internal.processors.cache.mvcc.MvccFuture; import org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx; import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; +import org.apache.ignite.internal.processors.tracing.MTC; +import org.apache.ignite.internal.processors.tracing.Span; import org.apache.ignite.internal.transactions.IgniteTxRollbackCheckedException; import org.apache.ignite.internal.util.future.GridFutureAdapter; import org.apache.ignite.internal.util.tostring.GridToStringInclude; @@ -58,6 +60,9 @@ import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_ASYNC; import static org.apache.ignite.cache.CacheWriteSynchronizationMode.FULL_SYNC; +import static org.apache.ignite.internal.processors.tracing.MTC.TraceSurroundings; +import static org.apache.ignite.internal.processors.tracing.MTC.support; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_NEAR_FINISH; import static org.apache.ignite.transactions.TransactionState.UNKNOWN; /** @@ -68,6 +73,9 @@ public final class GridNearTxFinishFuture extends GridCacheCompoundIdentit /** */ private static final long serialVersionUID = 0L; + /** Tracing span. */ + private Span span; + /** Logger reference. */ private static final AtomicReference logRef = new AtomicReference<>(); @@ -288,73 +296,75 @@ void forceFinish() { /** {@inheritDoc} */ @Override public boolean onDone(IgniteInternalTx tx0, Throwable err) { - if (isDone()) - return false; - - synchronized (this) { + try (MTC.TraceSurroundings ignored = support(span)) { if (isDone()) return false; - boolean nodeStop = false; + synchronized (this) { + if (isDone()) + return false; - if (err != null) { - tx.setRollbackOnly(); + boolean nodeStop = false; - nodeStop = err instanceof NodeStoppingException || cctx.kernalContext().failure().nodeStopping(); - } + if (err != null) { + tx.setRollbackOnly(); - if (commit) { - if (tx.commitError() != null) - err = tx.commitError(); - else if (err != null) - tx.commitError(err); - } + nodeStop = err instanceof NodeStoppingException || cctx.kernalContext().failure().nodeStopping(); + } - if (initialized() || err != null) { - if (tx.needCheckBackup()) { - assert tx.onePhaseCommit(); + if (commit) { + if (tx.commitError() != null) + err = tx.commitError(); + else if (err != null) + tx.commitError(err); + } - if (err != null) - err = new TransactionRollbackException("Failed to commit transaction.", err); + if (initialized() || err != null) { + if (tx.needCheckBackup()) { + assert tx.onePhaseCommit(); - try { - tx.localFinish(err == null, true); - } - catch (IgniteCheckedException e) { if (err != null) - err.addSuppressed(e); - else - err = e; + err = new TransactionRollbackException("Failed to commit transaction.", err); + + try { + tx.localFinish(err == null, true); + } + catch (IgniteCheckedException e) { + if (err != null) + err.addSuppressed(e); + else + err = e; + } } - } - if (tx.onePhaseCommit()) { - boolean commit = this.commit && err == null; + if (tx.onePhaseCommit()) { + boolean commit = this.commit && err == null; - if (!nodeStop) - finishOnePhase(commit); + if (!nodeStop) + finishOnePhase(commit); - try { - tx.tmFinish(commit, nodeStop, true); - } - catch (IgniteCheckedException e) { - U.error(log, "Failed to finish tx: " + tx, e); + try { + tx.tmFinish(commit, nodeStop, true); + } + catch (IgniteCheckedException e) { + U.error(log, "Failed to finish tx: " + tx, e); - if (err == null) - err = e; + if (err == null) + err = e; + } } - } - if (super.onDone(tx0, err)) { - // Don't forget to clean up. - cctx.mvcc().removeFuture(futId); + if (super.onDone(tx0, err)) { + // Don't forget to clean up. + cctx.mvcc().removeFuture(futId); - return true; + return true; + } } } - } - return false; + return false; + } } /** @@ -369,25 +379,28 @@ private boolean isMini(IgniteInternalFuture fut) { /** {@inheritDoc} */ @Override public void finish(final boolean commit, final boolean clearThreadMap, final boolean onTimeout) { - if (!cctx.mvcc().addFuture(this, futureId())) - return; + try (TraceSurroundings ignored = + MTC.supportContinual(span = cctx.kernalContext().tracing().create(TX_NEAR_FINISH, MTC.span()))) { + if (!cctx.mvcc().addFuture(this, futureId())) + return; - if (tx.onNeedCheckBackup()) { - assert tx.onePhaseCommit(); + if (tx.onNeedCheckBackup()) { + assert tx.onePhaseCommit(); - checkBackup(); + checkBackup(); - // If checkBackup is set, it means that primary node has crashed and we will not need to send - // finish request to it, so we can mark future as initialized. - markInitialized(); + // If checkBackup is set, it means that primary node has crashed and we will not need to send + // finish request to it, so we can mark future as initialized. + markInitialized(); - return; - } + return; + } - if (!commit && !clearThreadMap) - rollbackAsyncSafe(onTimeout); - else - doFinish(commit, clearThreadMap); + if (!commit && !clearThreadMap) + rollbackAsyncSafe(onTimeout); + else + doFinish(commit, clearThreadMap); + } } /** 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 5739028858034..3f828b30cf8a9 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 @@ -86,6 +86,7 @@ import org.apache.ignite.internal.processors.query.EnlistOperation; import org.apache.ignite.internal.processors.query.UpdateSourceIterator; import org.apache.ignite.internal.processors.timeout.GridTimeoutObject; +import org.apache.ignite.internal.processors.tracing.MTC; import org.apache.ignite.internal.transactions.IgniteTxOptimisticCheckedException; import org.apache.ignite.internal.transactions.IgniteTxRollbackCheckedException; import org.apache.ignite.internal.transactions.IgniteTxTimeoutCheckedException; @@ -127,6 +128,9 @@ import static org.apache.ignite.internal.processors.cache.GridCacheOperation.UPDATE; import static org.apache.ignite.internal.processors.cache.transactions.IgniteTxEntry.SER_READ_EMPTY_ENTRY_VER; import static org.apache.ignite.internal.processors.cache.transactions.IgniteTxEntry.SER_READ_NOT_EMPTY_VER; +import static org.apache.ignite.internal.processors.tracing.MTC.TraceSurroundings; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_NEAR_ENLIST_READ; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_NEAR_ENLIST_WRITE; import static org.apache.ignite.transactions.TransactionState.ACTIVE; import static org.apache.ignite.transactions.TransactionState.COMMITTED; import static org.apache.ignite.transactions.TransactionState.COMMITTING; @@ -273,6 +277,7 @@ public GridNearTxLocal() { * @param taskNameHash Task name hash code. * @param lb Label. * @param txDumpsThrottling Log throttling information. + * @param tracingEnabled {@code true} if the transaction should be traced. */ public GridNearTxLocal( GridCacheSharedContext ctx, @@ -289,7 +294,8 @@ public GridNearTxLocal( @Nullable UUID subjId, int taskNameHash, @Nullable String lb, - IgniteTxManager.TxDumpsThrottling txDumpsThrottling + IgniteTxManager.TxDumpsThrottling txDumpsThrottling, + boolean tracingEnabled ) { super( ctx, @@ -1070,88 +1076,91 @@ private IgniteInternalFuture enlistWrite( boolean keepBinary, boolean recovery, Byte dataCenterId) { - GridFutureAdapter enlistFut = new GridFutureAdapter<>(); + try (TraceSurroundings ignored2 = + MTC.support(context().kernalContext().tracing().create(TX_NEAR_ENLIST_WRITE, MTC.span()))) { + GridFutureAdapter enlistFut = new GridFutureAdapter<>(); - try { - if (!updateLockFuture(null, enlistFut)) - return finishFuture(enlistFut, timedOut() ? timeoutException() : rollbackException(), false); - - addActiveCache(cacheCtx, recovery); - - final boolean hasFilters = !F.isEmptyOrNulls(filter) && !F.isAlwaysTrue(filter); - final boolean needVal = singleRmv || retval || hasFilters; - final boolean needReadVer = needVal && (serializable() && optimistic()); - - if (entryProcessor != null) - transform = true; + try { + if (!updateLockFuture(null, enlistFut)) + return finishFuture(enlistFut, timedOut() ? timeoutException() : rollbackException(), false); - GridCacheVersion drVer = dataCenterId != null ? cctx.versions().next(dataCenterId) : null; + addActiveCache(cacheCtx, recovery); - boolean loadMissed = enlistWriteEntry(cacheCtx, - entryTopVer, - cacheKey, - val, - entryProcessor, - invokeArgs, - expiryPlc, - retval, - lockOnly, - filter, - /*drVer*/drVer, - /*drTtl*/-1L, - /*drExpireTime*/-1L, - ret, - /*enlisted*/null, - skipStore, - singleRmv, - hasFilters, - needVal, - needReadVer, - keepBinary, - recovery); + final boolean hasFilters = !F.isEmptyOrNulls(filter) && !F.isAlwaysTrue(filter); + final boolean needVal = singleRmv || retval || hasFilters; + final boolean needReadVer = needVal && (serializable() && optimistic()); - if (loadMissed) { - AffinityTopologyVersion topVer = topologyVersionSnapshot(); + if (entryProcessor != null) + transform = true; - if (topVer == null) - topVer = entryTopVer; + GridCacheVersion drVer = dataCenterId != null ? cctx.versions().next(dataCenterId) : null; - IgniteInternalFuture loadFut = loadMissing(cacheCtx, - topVer != null ? topVer : topologyVersion(), - Collections.singleton(cacheKey), + boolean loadMissed = enlistWriteEntry(cacheCtx, + entryTopVer, + cacheKey, + val, + entryProcessor, + invokeArgs, + expiryPlc, + retval, + lockOnly, filter, + /*drVer*/drVer, + /*drTtl*/-1L, + /*drExpireTime*/-1L, ret, - needReadVer, + /*enlisted*/null, + skipStore, singleRmv, hasFilters, - /*read through*/(entryProcessor != null || cacheCtx.config().isLoadPreviousValue()) && !skipStore, - retval, + needVal, + needReadVer, keepBinary, - recovery, - expiryPlc); + recovery); - loadFut.listen(new IgniteInClosure>() { - @Override public void apply(IgniteInternalFuture fut) { - try { - fut.get(); + if (loadMissed) { + AffinityTopologyVersion topVer = topologyVersionSnapshot(); - finishFuture(enlistFut, null, true); - } - catch (IgniteCheckedException e) { - finishFuture(enlistFut, e, true); + if (topVer == null) + topVer = entryTopVer; + + IgniteInternalFuture loadFut = loadMissing(cacheCtx, + topVer != null ? topVer : topologyVersion(), + Collections.singleton(cacheKey), + filter, + ret, + needReadVer, + singleRmv, + hasFilters, + /*read through*/(entryProcessor != null || cacheCtx.config().isLoadPreviousValue()) && !skipStore, + retval, + keepBinary, + recovery, + expiryPlc); + + loadFut.listen(new IgniteInClosure>() { + @Override public void apply(IgniteInternalFuture fut) { + try { + fut.get(); + + finishFuture(enlistFut, null, true); + } + catch (IgniteCheckedException e) { + finishFuture(enlistFut, e, true); + } } - } - }); + }); - return enlistFut; - } + return enlistFut; + } - finishFuture(enlistFut, null, true); + finishFuture(enlistFut, null, true); - return enlistFut; - } - catch (IgniteCheckedException e) { - return finishFuture(enlistFut, e, true); + return enlistFut; + } + catch (IgniteCheckedException e) { + return finishFuture(enlistFut, e, true); + } } } @@ -1201,59 +1210,61 @@ private IgniteInternalFuture enlistWrite( ) { assert retval || invokeMap == null; - GridFutureAdapter enlistFut = new GridFutureAdapter<>(); + try (TraceSurroundings ignored2 = + MTC.support(context().kernalContext().tracing().create(TX_NEAR_ENLIST_WRITE, MTC.span()))) { + GridFutureAdapter enlistFut = new GridFutureAdapter<>(); - if (!updateLockFuture(null, enlistFut)) - return finishFuture(enlistFut, timedOut() ? timeoutException() : rollbackException(), false); + if (!updateLockFuture(null, enlistFut)) + return finishFuture(enlistFut, timedOut() ? timeoutException() : rollbackException(), false); - try { - addActiveCache(cacheCtx, recovery); - } - catch (IgniteCheckedException e) { - return finishFuture(enlistFut, e, false); - } + try { + addActiveCache(cacheCtx, recovery); + } + catch (IgniteCheckedException e) { + return finishFuture(enlistFut, e, false); + } - boolean rmv = lookup == null && invokeMap == null; + boolean rmv = lookup == null && invokeMap == null; - final boolean hasFilters = !F.isEmptyOrNulls(filter) && !F.isAlwaysTrue(filter); - final boolean needVal = singleRmv || retval || hasFilters; - final boolean needReadVer = needVal && (serializable() && optimistic()); + final boolean hasFilters = !F.isEmptyOrNulls(filter) && !F.isAlwaysTrue(filter); + final boolean needVal = singleRmv || retval || hasFilters; + final boolean needReadVer = needVal && (serializable() && optimistic()); - try { - // Set transform flag for transaction. - if (invokeMap != null) - transform = true; + try { + // Set transform flag for transaction. + if (invokeMap != null) + transform = true; - Set missedForLoad = null; + Set missedForLoad = null; - for (Object key : keys) { - if (isRollbackOnly()) - return finishFuture(enlistFut, timedOut() ? timeoutException() : rollbackException(), false); + for (Object key : keys) { + if (isRollbackOnly()) + return finishFuture(enlistFut, timedOut() ? timeoutException() : rollbackException(), false); - if (key == null) { - rollback(); + if (key == null) { + rollback(); - throw new NullPointerException("Null key."); - } + throw new NullPointerException("Null key."); + } - Object val = rmv || lookup == null ? null : lookup.get(key); - EntryProcessor entryProcessor = invokeMap == null ? null : invokeMap.get(key); + Object val = rmv || lookup == null ? null : lookup.get(key); + EntryProcessor entryProcessor = invokeMap == null ? null : invokeMap.get(key); - GridCacheVersion drVer; - long drTtl; - long drExpireTime; + GridCacheVersion drVer; + long drTtl; + long drExpireTime; - if (drPutMap != null) { - GridCacheDrInfo info = drPutMap.get(key); + if (drPutMap != null) { + GridCacheDrInfo info = drPutMap.get(key); - assert info != null; + assert info != null; - drVer = info.version(); - drTtl = info.ttl(); - drExpireTime = info.expireTime(); - } - else if (drRmvMap != null) { - assert drRmvMap.get(key) != null; + drVer = info.version(); + drTtl = info.ttl(); + drExpireTime = info.expireTime(); + } + else if (drRmvMap != null) { + assert drRmvMap.get(key) != null; drVer = drRmvMap.get(key); drTtl = -1L; @@ -1270,85 +1281,86 @@ else if (dataCenterId != null) { drExpireTime = -1L; } - if (!rmv && val == null && entryProcessor == null) { - setRollbackOnly(); + if (!rmv && val == null && entryProcessor == null) { + setRollbackOnly(); - throw new NullPointerException("Null value."); - } + throw new NullPointerException("Null value."); + } - KeyCacheObject cacheKey = cacheCtx.toCacheKeyObject(key); + KeyCacheObject cacheKey = cacheCtx.toCacheKeyObject(key); - boolean loadMissed = enlistWriteEntry(cacheCtx, - entryTopVer, - cacheKey, - val, - entryProcessor, - invokeArgs, - expiryPlc, - retval, - lockOnly, - filter, - drVer, - drTtl, - drExpireTime, - ret, - enlisted, - skipStore, - singleRmv, - hasFilters, - needVal, - needReadVer, - keepBinary, - recovery); + boolean loadMissed = enlistWriteEntry(cacheCtx, + entryTopVer, + cacheKey, + val, + entryProcessor, + invokeArgs, + expiryPlc, + retval, + lockOnly, + filter, + drVer, + drTtl, + drExpireTime, + ret, + enlisted, + skipStore, + singleRmv, + hasFilters, + needVal, + needReadVer, + keepBinary, + recovery); - if (loadMissed) { - if (missedForLoad == null) - missedForLoad = new HashSet<>(); + if (loadMissed) { + if (missedForLoad == null) + missedForLoad = new HashSet<>(); - missedForLoad.add(cacheKey); + missedForLoad.add(cacheKey); + } } - } - if (missedForLoad != null) { - AffinityTopologyVersion topVer = topologyVersionSnapshot(); + if (missedForLoad != null) { + AffinityTopologyVersion topVer = topologyVersionSnapshot(); - if (topVer == null) - topVer = entryTopVer; + if (topVer == null) + topVer = entryTopVer; - IgniteInternalFuture loadFut = loadMissing(cacheCtx, - topVer != null ? topVer : topologyVersion(), - missedForLoad, - filter, - ret, - needReadVer, - singleRmv, - hasFilters, - /*read through*/(invokeMap != null || cacheCtx.config().isLoadPreviousValue()) && !skipStore, - retval, - keepBinary, - recovery, - expiryPlc); + IgniteInternalFuture loadFut = loadMissing(cacheCtx, + topVer != null ? topVer : topologyVersion(), + missedForLoad, + filter, + ret, + needReadVer, + singleRmv, + hasFilters, + /*read through*/(invokeMap != null || cacheCtx.config().isLoadPreviousValue()) && !skipStore, + retval, + keepBinary, + recovery, + expiryPlc); - loadFut.listen(new IgniteInClosure>() { - @Override public void apply(IgniteInternalFuture fut) { - try { - fut.get(); + loadFut.listen(new IgniteInClosure>() { + @Override public void apply(IgniteInternalFuture fut) { + try { + fut.get(); - finishFuture(enlistFut, null, true); - } - catch (IgniteCheckedException e) { - finishFuture(enlistFut, e, true); + finishFuture(enlistFut, null, true); + } + catch (IgniteCheckedException e) { + finishFuture(enlistFut, e, true); + } } - } - }); + }); - return enlistFut; - } + return enlistFut; + } - return finishFuture(enlistFut, null, true); - } - catch (IgniteCheckedException e) { - return finishFuture(enlistFut, e, true); + return finishFuture(enlistFut, null, true); + } + catch (IgniteCheckedException e) { + return finishFuture(enlistFut, e, true); + } } } @@ -2597,282 +2609,285 @@ private Collection enlistRead( assert !F.isEmpty(keys); assert keysCnt == keys.size(); - cacheCtx.checkSecurity(SecurityPermission.CACHE_READ); + try (TraceSurroundings ignored2 = + MTC.support(context().kernalContext().tracing().create(TX_NEAR_ENLIST_READ, MTC.span()))) { + cacheCtx.checkSecurity(SecurityPermission.CACHE_READ); - boolean single = keysCnt == 1; + boolean single = keysCnt == 1; - Collection lockKeys = null; + Collection lockKeys = null; - AffinityTopologyVersion topVer = entryTopVer != null ? entryTopVer : topologyVersion(); + AffinityTopologyVersion topVer = entryTopVer != null ? entryTopVer : topologyVersion(); - boolean needReadVer = (serializable() && optimistic()) || needVer; + boolean needReadVer = (serializable() && optimistic()) || needVer; - // In this loop we cover only read-committed or optimistic transactions. - // Transactions that are pessimistic and not read-committed are covered - // outside of this loop. - for (KeyCacheObject key : keys) { - if (isRollbackOnly()) - throw timedOut() ? timeoutException() : rollbackException(); + // In this loop we cover only read-committed or optimistic transactions. + // Transactions that are pessimistic and not read-committed are covered + // outside of this loop. + for (KeyCacheObject key : keys) { + if (isRollbackOnly()) + throw timedOut() ? timeoutException() : rollbackException(); - if ((pessimistic() || needReadVer) && !readCommitted() && !skipVals) - addActiveCache(cacheCtx, recovery); + if ((pessimistic() || needReadVer) && !readCommitted() && !skipVals) + addActiveCache(cacheCtx, recovery); - IgniteTxKey txKey = cacheCtx.txKey(key); + IgniteTxKey txKey = cacheCtx.txKey(key); - // Check write map (always check writes first). - IgniteTxEntry txEntry = entry(txKey); + // Check write map (always check writes first). + IgniteTxEntry txEntry = entry(txKey); - // Either non-read-committed or there was a previous write. - if (txEntry != null) { - CacheObject val = txEntry.value(); + // Either non-read-committed or there was a previous write. + if (txEntry != null) { + CacheObject val = txEntry.value(); - if (txEntry.hasValue()) { - if (!F.isEmpty(txEntry.entryProcessors())) - val = txEntry.applyEntryProcessors(val); + if (txEntry.hasValue()) { + if (!F.isEmpty(txEntry.entryProcessors())) + val = txEntry.applyEntryProcessors(val); - if (val != null) { - GridCacheVersion ver = null; + if (val != null) { + GridCacheVersion ver = null; - if (needVer) { - if (txEntry.op() != READ) - ver = IgniteTxEntry.GET_ENTRY_INVALID_VER_UPDATED; - else { - ver = txEntry.entryReadVersion(); + if (needVer) { + if (txEntry.op() != READ) + ver = IgniteTxEntry.GET_ENTRY_INVALID_VER_UPDATED; + else { + ver = txEntry.entryReadVersion(); - if (ver == null && pessimistic()) { - while (true) { - try { - GridCacheEntryEx cached = txEntry.cached(); + if (ver == null && pessimistic()) { + while (true) { + try { + GridCacheEntryEx cached = txEntry.cached(); - ver = cached.isNear() ? - ((GridNearCacheEntry)cached).dhtVersion() : cached.version(); + ver = cached.isNear() ? + ((GridNearCacheEntry)cached).dhtVersion() : cached.version(); - break; - } - catch (GridCacheEntryRemovedException ignored) { - txEntry.cached(entryEx(cacheCtx, txEntry.txKey(), topVer)); + break; + } + catch (GridCacheEntryRemovedException ignored) { + txEntry.cached(entryEx(cacheCtx, txEntry.txKey(), topVer)); + } } } - } - if (ver == null) { - assert optimistic() && repeatableRead() : this; + if (ver == null) { + assert optimistic() && repeatableRead() : this; - ver = IgniteTxEntry.GET_ENTRY_INVALID_VER_AFTER_GET; + ver = IgniteTxEntry.GET_ENTRY_INVALID_VER_AFTER_GET; + } } + + assert ver != null; } - assert ver != null; + cacheCtx.addResult(map, key, val, skipVals, keepCacheObjects, deserializeBinary, false, + ver, 0, 0); } - - cacheCtx.addResult(map, key, val, skipVals, keepCacheObjects, deserializeBinary, false, - ver, 0, 0); } - } - else { - assert txEntry.op() == TRANSFORM; + else { + assert txEntry.op() == TRANSFORM; - while (true) { - try { - GridCacheVersion readVer = null; - EntryGetResult getRes = null; + while (true) { + try { + GridCacheVersion readVer = null; + EntryGetResult getRes = null; - Object transformClo = - (txEntry.op() == TRANSFORM && - cctx.gridEvents().isRecordable(EVT_CACHE_OBJECT_READ)) ? - F.first(txEntry.entryProcessors()) : null; + Object transformClo = + (txEntry.op() == TRANSFORM && + cctx.gridEvents().isRecordable(EVT_CACHE_OBJECT_READ)) ? + F.first(txEntry.entryProcessors()) : null; - if (needVer) { - getRes = txEntry.cached().innerGetVersioned( - null, - this, - /*update-metrics*/true, - /*event*/!skipVals, - CU.subjectId(this, cctx), - transformClo, - resolveTaskName(), - null, - txEntry.keepBinary(), - null); + if (needVer) { + getRes = txEntry.cached().innerGetVersioned( + null, + this, + /*update-metrics*/true, + /*event*/!skipVals, + CU.subjectId(this, cctx), + transformClo, + resolveTaskName(), + null, + txEntry.keepBinary(), + null); - if (getRes != null) { - val = getRes.value(); - readVer = getRes.version(); + if (getRes != null) { + val = getRes.value(); + readVer = getRes.version(); + } + } + else { + val = txEntry.cached().innerGet( + null, + this, + /*read-through*/false, + /*metrics*/true, + /*event*/!skipVals, + CU.subjectId(this, cctx), + transformClo, + resolveTaskName(), + null, + txEntry.keepBinary()); } - } - else { - val = txEntry.cached().innerGet( - null, - this, - /*read-through*/false, - /*metrics*/true, - /*event*/!skipVals, - CU.subjectId(this, cctx), - transformClo, - resolveTaskName(), - null, - txEntry.keepBinary()); - } - - if (val != null) { - if (!readCommitted() && !skipVals) - txEntry.readValue(val); - if (!F.isEmpty(txEntry.entryProcessors())) - val = txEntry.applyEntryProcessors(val); + if (val != null) { + if (!readCommitted() && !skipVals) + txEntry.readValue(val); + + if (!F.isEmpty(txEntry.entryProcessors())) + val = txEntry.applyEntryProcessors(val); + + cacheCtx.addResult(map, + key, + val, + skipVals, + keepCacheObjects, + deserializeBinary, + false, + getRes, + readVer, + 0, + 0, + needVer); + } + else + missed.put(key, txEntry.cached().version()); - cacheCtx.addResult(map, - key, - val, - skipVals, - keepCacheObjects, - deserializeBinary, - false, - getRes, - readVer, - 0, - 0, - needVer); + break; + } + catch (GridCacheEntryRemovedException ignored) { + txEntry.cached(entryEx(cacheCtx, txEntry.txKey(), topVer)); } - else - missed.put(key, txEntry.cached().version()); - - break; - } - catch (GridCacheEntryRemovedException ignored) { - txEntry.cached(entryEx(cacheCtx, txEntry.txKey(), topVer)); } } } - } - // First time access within transaction. - else { - if (lockKeys == null && !skipVals) - lockKeys = single ? Collections.singleton(key) : new ArrayList(keysCnt); + // First time access within transaction. + else { + if (lockKeys == null && !skipVals) + lockKeys = single ? Collections.singleton(key) : new ArrayList(keysCnt); - if (!single && !skipVals) - lockKeys.add(key); + if (!single && !skipVals) + lockKeys.add(key); - while (true) { - GridCacheEntryEx entry = entryEx(cacheCtx, txKey, topVer); + while (true) { + GridCacheEntryEx entry = entryEx(cacheCtx, txKey, topVer); - try { - GridCacheVersion ver = entry.version(); + try { + GridCacheVersion ver = entry.version(); - CacheObject val = null; - GridCacheVersion readVer = null; - EntryGetResult getRes = null; + CacheObject val = null; + GridCacheVersion readVer = null; + EntryGetResult getRes = null; if ((!pessimistic() || (readCommitted() && !skipVals)) && !readRepair) { IgniteCacheExpiryPolicy accessPlc = optimistic() ? accessPolicy(cacheCtx, txKey, expiryPlc) : null; - if (needReadVer) { - getRes = primaryLocal(entry) ? - entry.innerGetVersioned( + if (needReadVer) { + getRes = primaryLocal(entry) ? + entry.innerGetVersioned( + null, + this, + /*metrics*/true, + /*event*/true, + CU.subjectId(this, cctx), + null, + resolveTaskName(), + accessPlc, + !deserializeBinary, + null) : null; + + if (getRes != null) { + val = getRes.value(); + readVer = getRes.version(); + } + } + else { + val = entry.innerGet( null, this, + /*read-through*/false, /*metrics*/true, - /*event*/true, + /*event*/!skipVals, CU.subjectId(this, cctx), null, resolveTaskName(), accessPlc, - !deserializeBinary, - null) : null; - - if (getRes != null) { - val = getRes.value(); - readVer = getRes.version(); + !deserializeBinary); } - } - else { - val = entry.innerGet( - null, - this, - /*read-through*/false, - /*metrics*/true, - /*event*/!skipVals, - CU.subjectId(this, cctx), - null, - resolveTaskName(), - accessPlc, - !deserializeBinary); - } - if (val != null) { - cacheCtx.addResult(map, - key, - val, - skipVals, - keepCacheObjects, - deserializeBinary, - false, - getRes, - readVer, - 0, - 0, - needVer); + if (val != null) { + cacheCtx.addResult(map, + key, + val, + skipVals, + keepCacheObjects, + deserializeBinary, + false, + getRes, + readVer, + 0, + 0, + needVer); + } + else + missed.put(key, ver); } else + // We must wait for the lock in pessimistic mode. missed.put(key, ver); - } - else - // We must wait for the lock in pessimistic mode. - missed.put(key, ver); - - if (!readCommitted() && !skipVals) { - txEntry = addEntry(READ, - val, - null, - null, - entry, - expiryPlc, - null, - true, - -1L, - -1L, - null, - skipStore, - !deserializeBinary, - CU.isNearEnabled(cacheCtx)); - // As optimization, mark as checked immediately - // for non-pessimistic if value is not null. - if (val != null && !pessimistic()) { - txEntry.markValid(); + if (!readCommitted() && !skipVals) { + txEntry = addEntry(READ, + val, + null, + null, + entry, + expiryPlc, + null, + true, + -1L, + -1L, + null, + skipStore, + !deserializeBinary, + CU.isNearEnabled(cacheCtx)); - if (needReadVer) { - assert readVer != null; + // As optimization, mark as checked immediately + // for non-pessimistic if value is not null. + if (val != null && !pessimistic()) { + txEntry.markValid(); - txEntry.entryReadVersion(readVer); + if (needReadVer) { + assert readVer != null; + + txEntry.entryReadVersion(readVer); + } } } - } - break; // While. - } - catch (GridCacheEntryRemovedException ignored) { - if (log.isDebugEnabled()) - log.debug("Got removed entry in transaction getAllAsync(..) (will retry): " + key); - } - finally { - if (entry != null && readCommitted()) { - if (cacheCtx.isNear()) { - if (cacheCtx.affinity().partitionBelongs(cacheCtx.localNode(), entry.partition(), topVer)) { - if (entry.markObsolete(xidVer)) - cacheCtx.cache().removeEntry(entry); + break; // While. + } + catch (GridCacheEntryRemovedException ignored) { + if (log.isDebugEnabled()) + log.debug("Got removed entry in transaction getAllAsync(..) (will retry): " + key); + } + finally { + if (entry != null && readCommitted()) { + if (cacheCtx.isNear()) { + if (cacheCtx.affinity().partitionBelongs(cacheCtx.localNode(), entry.partition(), topVer)) { + if (entry.markObsolete(xidVer)) + cacheCtx.cache().removeEntry(entry); + } } + else + entry.touch(); } - else - entry.touch(); } } } } - } - return lockKeys != null ? lockKeys : Collections.emptyList(); + return lockKeys != null ? lockKeys : Collections.emptyList(); + } } /** diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/mvcc/MvccUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/mvcc/MvccUtils.java index 6bbafc7b9091d..bccbb1197c47a 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/mvcc/MvccUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/mvcc/MvccUtils.java @@ -770,7 +770,8 @@ private static GridNearTxLocal txStart(GridKernalContext ctx, @Nullable GridCach cctx == null || !cctx.skipStore(), true, 0, - null + null, + false ); tx.syncMode(FULL_SYNC); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTransactionsImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTransactionsImpl.java index 2a7999f854c6b..b6ce2a0bc7946 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTransactionsImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/IgniteTransactionsImpl.java @@ -24,6 +24,7 @@ import org.apache.ignite.internal.processors.cache.GridCacheContext; import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxLocal; +import org.apache.ignite.internal.processors.tracing.MTC; import org.apache.ignite.internal.util.typedef.F; import org.apache.ignite.internal.util.typedef.internal.A; import org.apache.ignite.internal.util.typedef.internal.CU; @@ -36,6 +37,8 @@ import org.apache.ignite.transactions.TransactionMetrics; import org.jetbrains.annotations.Nullable; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX; + /** * Grid transactions implementation. */ @@ -46,13 +49,17 @@ public class IgniteTransactionsImpl implements IgniteTransactionsEx { /** Label. */ private String lb; + /** Tracing enabled flag. */ + private boolean tracingEnabled; + /** * @param cctx Cache shared context. * @param lb Label. */ - public IgniteTransactionsImpl(GridCacheSharedContext cctx, @Nullable String lb) { + public IgniteTransactionsImpl(GridCacheSharedContext cctx, @Nullable String lb, boolean tracingEnabled) { this.cctx = cctx; this.lb = lb; + this.tracingEnabled = tracingEnabled; } /** {@inheritDoc} */ @@ -160,6 +167,18 @@ private GridNearTxLocal txStart0( ) { cctx.kernalContext().gateway().readLock(); + MTC.supportInitial(cctx.kernalContext().tracing().create( + TX, + null, + lb)); + + MTC.span().addTag("isolation", isolation::name); + MTC.span().addTag("concurrency", concurrency::name); + MTC.span().addTag("timeout", () -> String.valueOf(timeout)); + + if (lb != null) + MTC.span().addTag("label", () -> lb); + try { GridNearTxLocal tx = cctx.tm().userTx(sysCacheCtx); @@ -177,11 +196,11 @@ private GridNearTxLocal txStart0( true, null, txSize, - lb + lb, + tracingEnabled ); assert tx != null; - return tx; } finally { @@ -223,7 +242,12 @@ private GridNearTxLocal txStart0( @Override public IgniteTransactions withLabel(String lb) { A.notNull(lb, "label should not be empty."); - return new IgniteTransactionsImpl<>(cctx, lb); + return new IgniteTransactionsImpl<>(cctx, lb, tracingEnabled); + } + + /** {@inheritDoc} */ + @Override public IgniteTransactions withTracing() { + return new IgniteTransactionsImpl<>(cctx, lb, true); } /** 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 a2bd1e80b684c..ad43c6425656d 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 @@ -83,6 +83,7 @@ import org.apache.ignite.internal.processors.cache.version.GridCacheVersion; import org.apache.ignite.internal.processors.query.EnlistOperation; import org.apache.ignite.internal.processors.query.IgniteSQLException; +import org.apache.ignite.internal.processors.tracing.MTC; import org.apache.ignite.internal.transactions.IgniteTxHeuristicCheckedException; import org.apache.ignite.internal.transactions.IgniteTxOptimisticCheckedException; import org.apache.ignite.internal.transactions.IgniteTxRollbackCheckedException; @@ -110,6 +111,16 @@ import static org.apache.ignite.internal.processors.cache.GridCacheUtils.isNearEnabled; import static org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState.RENTING; import static org.apache.ignite.internal.processors.cache.transactions.IgniteInternalTx.FinalizationStatus.USER_FINISH; +import static org.apache.ignite.internal.processors.tracing.MTC.TraceSurroundings; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_NEAR_FINISH_REQ; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_NEAR_FINISH_RESP; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_NEAR_PREPARE_REQ; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_NEAR_PREPARE_RESP; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_PROCESS_DHT_FINISH_REQ; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_PROCESS_DHT_FINISH_RESP; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_PROCESS_DHT_ONE_PHASE_COMMIT_ACK_REQ; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_PROCESS_DHT_PREPARE_REQ; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_PROCESS_DHT_PREPARE_RESP; import static org.apache.ignite.transactions.TransactionConcurrency.OPTIMISTIC; import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC; import static org.apache.ignite.transactions.TransactionState.PREPARED; @@ -140,24 +151,27 @@ public class IgniteTxHandler { * @param req Request. */ private void processNearTxPrepareRequest(UUID nearNodeId, GridNearTxPrepareRequest req) { - if (txPrepareMsgLog.isDebugEnabled()) { - txPrepareMsgLog.debug("Received near prepare request [txId=" + req.version() + - ", node=" + nearNodeId + ']'); - } - - ClusterNode nearNode = ctx.node(nearNodeId); - - if (nearNode == null) { + try (TraceSurroundings ignored = + MTC.support(ctx.kernalContext().tracing().create(TX_NEAR_PREPARE_REQ, MTC.span()))) { if (txPrepareMsgLog.isDebugEnabled()) { - txPrepareMsgLog.debug("Received near prepare from node that left grid (will ignore) [" + - "txId=" + req.version() + + txPrepareMsgLog.debug("Received near prepare request [txId=" + req.version() + ", node=" + nearNodeId + ']'); } - return; - } + ClusterNode nearNode = ctx.node(nearNodeId); - processNearTxPrepareRequest0(nearNode, req); + if (nearNode == null) { + if (txPrepareMsgLog.isDebugEnabled()) { + txPrepareMsgLog.debug("Received near prepare from node that left grid (will ignore) [" + + "txId=" + req.version() + + ", node=" + nearNodeId + ']'); + } + + return; + } + + processNearTxPrepareRequest0(nearNode, req); + } } /** @@ -750,27 +764,31 @@ private boolean needRemap(AffinityTopologyVersion expVer, * @param res Response. */ private void processNearTxPrepareResponse(UUID nodeId, GridNearTxPrepareResponse res) { - if (txPrepareMsgLog.isDebugEnabled()) - txPrepareMsgLog.debug("Received near prepare response [txId=" + res.version() + ", node=" + nodeId + ']'); + try (TraceSurroundings ignored = + MTC.support(ctx.kernalContext().tracing().create(TX_NEAR_PREPARE_RESP, MTC.span()))) { + if (txPrepareMsgLog.isDebugEnabled()) + txPrepareMsgLog.debug("Received near prepare response [txId=" + res.version() + ", node=" + + nodeId + ']'); - GridNearTxPrepareFutureAdapter fut = (GridNearTxPrepareFutureAdapter)ctx.mvcc() - .versionedFuture(res.version(), res.futureId()); + GridNearTxPrepareFutureAdapter fut = (GridNearTxPrepareFutureAdapter)ctx.mvcc() + .versionedFuture(res.version(), res.futureId()); - if (fut == null) { - U.warn(log, "Failed to find future for near prepare response [txId=" + res.version() + - ", node=" + nodeId + - ", res=" + res + ']'); + if (fut == null) { + U.warn(log, "Failed to find future for near prepare response [txId=" + res.version() + + ", node=" + nodeId + + ", res=" + res + ']'); - return; - } + return; + } - IgniteInternalTx tx = fut.tx(); + IgniteInternalTx tx = fut.tx(); - assert tx != null; + assert tx != null; - res.txState(tx.txState()); + res.txState(tx.txState()); - fut.onResult(nodeId, res); + fut.onResult(nodeId, res); + } } /** @@ -778,22 +796,25 @@ private void processNearTxPrepareResponse(UUID nodeId, GridNearTxPrepareResponse * @param res Response. */ private void processNearTxFinishResponse(UUID nodeId, GridNearTxFinishResponse res) { - if (txFinishMsgLog.isDebugEnabled()) - txFinishMsgLog.debug("Received near finish response [txId=" + res.xid() + ", node=" + nodeId + ']'); + try (TraceSurroundings ignored = + MTC.support(ctx.kernalContext().tracing().create(TX_NEAR_FINISH_RESP, MTC.span()))) { + if (txFinishMsgLog.isDebugEnabled()) + txFinishMsgLog.debug("Received near finish response [txId=" + res.xid() + ", node=" + nodeId + ']'); - GridNearTxFinishFuture fut = (GridNearTxFinishFuture)ctx.mvcc().future(res.futureId()); + GridNearTxFinishFuture fut = (GridNearTxFinishFuture)ctx.mvcc().future(res.futureId()); - if (fut == null) { - if (txFinishMsgLog.isDebugEnabled()) { - txFinishMsgLog.debug("Failed to find future for near finish response [txId=" + res.xid() + - ", node=" + nodeId + - ", res=" + res + ']'); + if (fut == null) { + if (txFinishMsgLog.isDebugEnabled()) { + txFinishMsgLog.debug("Failed to find future for near finish response [txId=" + res.xid() + + ", node=" + nodeId + + ", res=" + res + ']'); + } + + return; } - return; + fut.onResult(nodeId, res); } - - fut.onResult(nodeId, res); } /** @@ -801,28 +822,33 @@ private void processNearTxFinishResponse(UUID nodeId, GridNearTxFinishResponse r * @param res Response. */ private void processDhtTxPrepareResponse(UUID nodeId, GridDhtTxPrepareResponse res) { - GridDhtTxPrepareFuture fut = (GridDhtTxPrepareFuture)ctx.mvcc().versionedFuture(res.version(), res.futureId()); + try (TraceSurroundings ignored = + MTC.support(ctx.kernalContext().tracing().create(TX_PROCESS_DHT_PREPARE_RESP, MTC.span()))) { + GridDhtTxPrepareFuture fut = + (GridDhtTxPrepareFuture)ctx.mvcc().versionedFuture(res.version(), res.futureId()); - if (fut == null) { - if (txPrepareMsgLog.isDebugEnabled()) { - txPrepareMsgLog.debug("Failed to find future for dht prepare response [txId=null" + - ", dhtTxId=" + res.version() + - ", node=" + nodeId + - ", res=" + res + ']'); - } + if (fut == null) { + if (txPrepareMsgLog.isDebugEnabled()) { + txPrepareMsgLog.debug("Failed to find future for dht prepare response [txId=null" + + ", dhtTxId=" + res.version() + + ", node=" + nodeId + + ", res=" + res + ']'); + } - return; - } - else if (txPrepareMsgLog.isDebugEnabled()) - txPrepareMsgLog.debug("Received dht prepare response [txId=" + fut.tx().nearXidVersion() + ", node=" + nodeId + ']'); + return; + } + else if (txPrepareMsgLog.isDebugEnabled()) + txPrepareMsgLog.debug("Received dht prepare response [txId=" + fut.tx().nearXidVersion() + + ", node=" + nodeId + ']'); - IgniteInternalTx tx = fut.tx(); + IgniteInternalTx tx = fut.tx(); - assert tx != null; + assert tx != null; - res.txState(tx.txState()); + res.txState(tx.txState()); - fut.onResult(nodeId, res); + fut.onResult(nodeId, res); + } } /** @@ -830,50 +856,53 @@ else if (txPrepareMsgLog.isDebugEnabled()) * @param res Response. */ private void processDhtTxFinishResponse(UUID nodeId, GridDhtTxFinishResponse res) { - assert nodeId != null; - assert res != null; + try (TraceSurroundings ignored = + MTC.support(ctx.kernalContext().tracing().create(TX_PROCESS_DHT_FINISH_RESP, MTC.span()))) { + assert nodeId != null; + assert res != null; - if (res.checkCommitted()) { - GridNearTxFinishFuture fut = (GridNearTxFinishFuture)ctx.mvcc().future(res.futureId()); + if (res.checkCommitted()) { + GridNearTxFinishFuture fut = (GridNearTxFinishFuture)ctx.mvcc().future(res.futureId()); - if (fut == null) { - if (txFinishMsgLog.isDebugEnabled()) { - txFinishMsgLog.debug("Failed to find future for dht finish check committed response [txId=null" + + if (fut == null) { + if (txFinishMsgLog.isDebugEnabled()) { + txFinishMsgLog.debug("Failed to find future for dht finish check committed response [txId=null" + + ", dhtTxId=" + res.xid() + + ", node=" + nodeId + + ", res=" + res + ']'); + } + + return; + } + else if (txFinishMsgLog.isDebugEnabled()) { + txFinishMsgLog.debug("Received dht finish check committed response [txId=" + fut.tx().nearXidVersion() + ", dhtTxId=" + res.xid() + - ", node=" + nodeId + - ", res=" + res + ']'); + ", node=" + nodeId + ']'); } - return; - } - else if (txFinishMsgLog.isDebugEnabled()) { - txFinishMsgLog.debug("Received dht finish check committed response [txId=" + fut.tx().nearXidVersion() + - ", dhtTxId=" + res.xid() + - ", node=" + nodeId + ']'); + fut.onResult(nodeId, res); } + else { + GridDhtTxFinishFuture fut = (GridDhtTxFinishFuture)ctx.mvcc().future(res.futureId()); - fut.onResult(nodeId, res); - } - else { - GridDhtTxFinishFuture fut = (GridDhtTxFinishFuture)ctx.mvcc().future(res.futureId()); + if (fut == null) { + if (txFinishMsgLog.isDebugEnabled()) { + txFinishMsgLog.debug("Failed to find future for dht finish response [txId=null" + + ", dhtTxId=" + res.xid() + + ", node=" + nodeId + + ", res=" + res); + } - if (fut == null) { - if (txFinishMsgLog.isDebugEnabled()) { - txFinishMsgLog.debug("Failed to find future for dht finish response [txId=null" + + return; + } + else if (txFinishMsgLog.isDebugEnabled()) { + txFinishMsgLog.debug("Received dht finish response [txId=" + fut.tx().nearXidVersion() + ", dhtTxId=" + res.xid() + - ", node=" + nodeId + - ", res=" + res); + ", node=" + nodeId + ']'); } - return; + fut.onResult(nodeId, res); } - else if (txFinishMsgLog.isDebugEnabled()) { - txFinishMsgLog.debug("Received dht finish response [txId=" + fut.tx().nearXidVersion() + - ", dhtTxId=" + res.xid() + - ", node=" + nodeId + ']'); - } - - fut.onResult(nodeId, res); } } @@ -886,16 +915,20 @@ else if (txFinishMsgLog.isDebugEnabled()) { UUID nodeId, GridNearTxFinishRequest req ) { - if (txFinishMsgLog.isDebugEnabled()) - txFinishMsgLog.debug("Received near finish request [txId=" + req.version() + ", node=" + nodeId + ']'); + try (TraceSurroundings ignored = + MTC.support(ctx.kernalContext().tracing().create(TX_NEAR_FINISH_REQ, MTC.span()))) { + if (txFinishMsgLog.isDebugEnabled()) + txFinishMsgLog.debug("Received near finish request [txId=" + req.version() + ", node=" + nodeId + + ']'); - IgniteInternalFuture fut = finish(nodeId, null, req); + IgniteInternalFuture fut = finish(nodeId, null, req); - assert req.txState() != null || fut == null || fut.error() != null || - (ctx.tm().tx(req.version()) == null && ctx.tm().nearTx(req.version()) == null) : - "[req=" + req + ", fut=" + fut + "]"; + assert req.txState() != null || fut == null || fut.error() != null || + (ctx.tm().tx(req.version()) == null && ctx.tm().nearTx(req.version()) == null) : + "[req=" + req + ", fut=" + fut + "]"; - return fut; + return fut; + } } /** @@ -1155,142 +1188,145 @@ public IgniteInternalFuture finishColocatedLocal(boolean commi * @param req Request. */ private void processDhtTxPrepareRequest(final UUID nodeId, final GridDhtTxPrepareRequest req) { - if (txPrepareMsgLog.isDebugEnabled()) { - txPrepareMsgLog.debug("Received dht prepare request [txId=" + req.nearXidVersion() + - ", dhtTxId=" + req.version() + - ", node=" + nodeId + ']'); - } + try (TraceSurroundings ignored = + MTC.support(ctx.kernalContext().tracing().create(TX_PROCESS_DHT_PREPARE_REQ, MTC.span()))) { + if (txPrepareMsgLog.isDebugEnabled()) { + txPrepareMsgLog.debug("Received dht prepare request [txId=" + req.nearXidVersion() + + ", dhtTxId=" + req.version() + + ", node=" + nodeId + ']'); + } - assert nodeId != null; - assert req != null; + assert nodeId != null; + assert req != null; - assert req.transactionNodes() != null; + assert req.transactionNodes() != null; - GridDhtTxRemote dhtTx = null; - GridNearTxRemote nearTx = null; + GridDhtTxRemote dhtTx = null; + GridNearTxRemote nearTx = null; - GridDhtTxPrepareResponse res; + GridDhtTxPrepareResponse res; - try { - res = new GridDhtTxPrepareResponse( - req.partition(), - req.version(), - req.futureId(), - req.miniId(), - req.deployInfo() != null); + try { + res = new GridDhtTxPrepareResponse( + req.partition(), + req.version(), + req.futureId(), + req.miniId(), + req.deployInfo() != null); - // Start near transaction first. - nearTx = !F.isEmpty(req.nearWrites()) ? startNearRemoteTx(ctx.deploy().globalLoader(), nodeId, req) : null; - dhtTx = startRemoteTx(nodeId, req, res); + // Start near transaction first. + nearTx = !F.isEmpty(req.nearWrites()) ? startNearRemoteTx(ctx.deploy().globalLoader(), nodeId, req) : null; + dhtTx = startRemoteTx(nodeId, req, res); - // Set evicted keys from near transaction. - if (nearTx != null) - res.nearEvicted(nearTx.evicted()); + // Set evicted keys from near transaction. + if (nearTx != null) + res.nearEvicted(nearTx.evicted()); - List writesCacheMissed = req.nearWritesCacheMissed(); + List writesCacheMissed = req.nearWritesCacheMissed(); - if (writesCacheMissed != null) { - Collection evicted0 = res.nearEvicted(); + if (writesCacheMissed != null) { + Collection evicted0 = res.nearEvicted(); - if (evicted0 != null) - writesCacheMissed.addAll(evicted0); + if (evicted0 != null) + writesCacheMissed.addAll(evicted0); - res.nearEvicted(writesCacheMissed); - } + res.nearEvicted(writesCacheMissed); + } - if (dhtTx != null) - req.txState(dhtTx.txState()); - else if (nearTx != null) - req.txState(nearTx.txState()); + if (dhtTx != null) + req.txState(dhtTx.txState()); + else if (nearTx != null) + req.txState(nearTx.txState()); - if (dhtTx != null && !F.isEmpty(dhtTx.invalidPartitions())) - res.invalidPartitionsByCacheId(dhtTx.invalidPartitions()); + if (dhtTx != null && !F.isEmpty(dhtTx.invalidPartitions())) + res.invalidPartitionsByCacheId(dhtTx.invalidPartitions()); - if (req.onePhaseCommit()) { - assert req.last(); + if (req.onePhaseCommit()) { + assert req.last(); - if (dhtTx != null) { - dhtTx.onePhaseCommit(true); - dhtTx.needReturnValue(req.needReturnValue()); + if (dhtTx != null) { + dhtTx.onePhaseCommit(true); + dhtTx.needReturnValue(req.needReturnValue()); - finish(dhtTx, req); - } + finish(dhtTx, req); + } - if (nearTx != null) { - nearTx.onePhaseCommit(true); + if (nearTx != null) { + nearTx.onePhaseCommit(true); - finish(nearTx, req); + finish(nearTx, req); + } } } - } - catch (IgniteCheckedException e) { - if (e instanceof IgniteTxRollbackCheckedException) - U.error(log, "Transaction was rolled back before prepare completed: " + req, e); - else if (e instanceof IgniteTxOptimisticCheckedException) { - if (log.isDebugEnabled()) - log.debug("Optimistic failure for remote transaction (will rollback): " + req); - } - else - U.error(log, "Failed to process prepare request: " + req, e); - - if (nearTx != null) - try { - nearTx.rollbackRemoteTx(); - } - catch (Throwable e1) { - e.addSuppressed(e1); + catch (IgniteCheckedException e) { + if (e instanceof IgniteTxRollbackCheckedException) + U.error(log, "Transaction was rolled back before prepare completed: " + req, e); + else if (e instanceof IgniteTxOptimisticCheckedException) { + if (log.isDebugEnabled()) + log.debug("Optimistic failure for remote transaction (will rollback): " + req); } + else + U.error(log, "Failed to process prepare request: " + req, e); - res = new GridDhtTxPrepareResponse( - req.partition(), - req.version(), - req.futureId(), - req.miniId(), - e, - req.deployInfo() != null); - } + if (nearTx != null) + try { + nearTx.rollbackRemoteTx(); + } + catch (Throwable e1) { + e.addSuppressed(e1); + } - if (req.onePhaseCommit()) { - IgniteInternalFuture completeFut; + res = new GridDhtTxPrepareResponse( + req.partition(), + req.version(), + req.futureId(), + req.miniId(), + e, + req.deployInfo() != null); + } - IgniteInternalFuture dhtFin = dhtTx == null ? - null : dhtTx.done() ? null : dhtTx.finishFuture(); + if (req.onePhaseCommit()) { + IgniteInternalFuture completeFut; - final IgniteInternalFuture nearFin = nearTx == null ? - null : nearTx.done() ? null : nearTx.finishFuture(); + IgniteInternalFuture dhtFin = dhtTx == null ? + null : dhtTx.done() ? null : dhtTx.finishFuture(); - if (dhtFin != null && nearFin != null) { - GridCompoundFuture fut = new GridCompoundFuture(); + final IgniteInternalFuture nearFin = nearTx == null ? + null : nearTx.done() ? null : nearTx.finishFuture(); - fut.add(dhtFin); - fut.add(nearFin); + if (dhtFin != null && nearFin != null) { + GridCompoundFuture fut = new GridCompoundFuture(); - fut.markInitialized(); + fut.add(dhtFin); + fut.add(nearFin); - completeFut = fut; - } - else - completeFut = dhtFin != null ? dhtFin : nearFin; + fut.markInitialized(); - if (completeFut != null) { - final GridDhtTxPrepareResponse res0 = res; - final GridDhtTxRemote dhtTx0 = dhtTx; - final GridNearTxRemote nearTx0 = nearTx; + completeFut = fut; + } + else + completeFut = dhtFin != null ? dhtFin : nearFin; - completeFut.listen(new CI1>() { - @Override public void apply(IgniteInternalFuture fut) { - sendReply(nodeId, req, res0, dhtTx0, nearTx0); - } - }); + if (completeFut != null) { + final GridDhtTxPrepareResponse res0 = res; + final GridDhtTxRemote dhtTx0 = dhtTx; + final GridNearTxRemote nearTx0 = nearTx; + + completeFut.listen(new CI1>() { + @Override public void apply(IgniteInternalFuture fut) { + sendReply(nodeId, req, res0, dhtTx0, nearTx0); + } + }); + } + else + sendReply(nodeId, req, res, dhtTx, nearTx); } else sendReply(nodeId, req, res, dhtTx, nearTx); - } - else - sendReply(nodeId, req, res, dhtTx, nearTx); - assert req.txState() != null || res.error() != null || (dhtTx == null && nearTx == null) : - req + " tx=" + dhtTx + " nearTx=" + nearTx; + assert req.txState() != null || res.error() != null || (dhtTx == null && nearTx == null) : + req + " tx=" + dhtTx + " nearTx=" + nearTx; + } } /** @@ -1299,14 +1335,17 @@ else if (e instanceof IgniteTxOptimisticCheckedException) { */ private void processDhtTxOnePhaseCommitAckRequest(final UUID nodeId, final GridDhtTxOnePhaseCommitAckRequest req) { - assert nodeId != null; - assert req != null; + try (TraceSurroundings ignored = + MTC.support(ctx.kernalContext().tracing().create(TX_PROCESS_DHT_ONE_PHASE_COMMIT_ACK_REQ, MTC.span()))) { + assert nodeId != null; + assert req != null; - if (log.isDebugEnabled()) - log.debug("Processing dht tx one phase commit ack request [nodeId=" + nodeId + ", req=" + req + ']'); + if (log.isDebugEnabled()) + log.debug("Processing dht tx one phase commit ack request [nodeId=" + nodeId + ", req=" + req + ']'); - for (GridCacheVersion ver : req.versions()) - ctx.tm().removeTxReturn(ver); + for (GridCacheVersion ver : req.versions()) + ctx.tm().removeTxReturn(ver); + } } /** @@ -1315,95 +1354,98 @@ private void processDhtTxOnePhaseCommitAckRequest(final UUID nodeId, */ @SuppressWarnings({"unchecked"}) private void processDhtTxFinishRequest(final UUID nodeId, final GridDhtTxFinishRequest req) { - assert nodeId != null; - assert req != null; + try (TraceSurroundings ignored = + MTC.support(ctx.kernalContext().tracing().create(TX_PROCESS_DHT_FINISH_REQ, MTC.span()))) { + assert nodeId != null; + assert req != null; - if (req.checkCommitted()) { - boolean committed = req.waitRemoteTransactions() || !ctx.tm().addRolledbackTx(null, req.version()); + if (req.checkCommitted()) { + boolean committed = req.waitRemoteTransactions() || !ctx.tm().addRolledbackTx(null, req.version()); - if (!committed || req.syncMode() != FULL_SYNC) - sendReply(nodeId, req, committed, null); - else { - IgniteInternalFuture fut = ctx.tm().remoteTxFinishFuture(req.version()); + if (!committed || req.syncMode() != FULL_SYNC) + sendReply(nodeId, req, committed, null); + else { + IgniteInternalFuture fut = ctx.tm().remoteTxFinishFuture(req.version()); - fut.listen(new CI1>() { - @Override public void apply(IgniteInternalFuture fut) { - sendReply(nodeId, req, true, null); - } - }); + fut.listen(new CI1>() { + @Override public void apply(IgniteInternalFuture fut) { + sendReply(nodeId, req, true, null); + } + }); + } + + return; } - return; - } + // Always add version to rollback history to prevent races with rollbacks. + if (!req.commit()) + ctx.tm().addRolledbackTx(null, req.version()); - // Always add version to rollback history to prevent races with rollbacks. - if (!req.commit()) - ctx.tm().addRolledbackTx(null, req.version()); + GridDhtTxRemote dhtTx = ctx.tm().tx(req.version()); + GridNearTxRemote nearTx = ctx.tm().nearTx(req.version()); - GridDhtTxRemote dhtTx = ctx.tm().tx(req.version()); - GridNearTxRemote nearTx = ctx.tm().nearTx(req.version()); + IgniteInternalTx anyTx = U.firstNotNull(dhtTx, nearTx); - IgniteInternalTx anyTx = U.firstNotNull(dhtTx, nearTx); + final GridCacheVersion nearTxId = anyTx != null ? anyTx.nearXidVersion() : null; - final GridCacheVersion nearTxId = anyTx != null ? anyTx.nearXidVersion() : null; - - if (txFinishMsgLog.isDebugEnabled()) - txFinishMsgLog.debug("Received dht finish request [txId=" + nearTxId + ", dhtTxId=" + req.version() + - ", node=" + nodeId + ']'); + if (txFinishMsgLog.isDebugEnabled()) + txFinishMsgLog.debug("Received dht finish request [txId=" + nearTxId + ", dhtTxId=" + req.version() + + ", node=" + nodeId + ']'); - if (anyTx == null && req.commit()) - ctx.tm().addCommittedTx(null, req.version(), null); + if (anyTx == null && req.commit()) + ctx.tm().addCommittedTx(null, req.version(), null); - if (dhtTx != null) - finish(nodeId, dhtTx, req); - else { - try { - applyPartitionsUpdatesCounters(req.updateCounters(), !req.commit(), false); - } - catch (IgniteCheckedException e) { - throw new IgniteException(e); + if (dhtTx != null) + finish(nodeId, dhtTx, req); + else { + try { + applyPartitionsUpdatesCounters(req.updateCounters(), !req.commit(), false); + } + catch (IgniteCheckedException e) { + throw new IgniteException(e); + } } - } - if (nearTx != null) - finish(nodeId, nearTx, req); + if (nearTx != null) + finish(nodeId, nearTx, req); - if (req.replyRequired()) { - IgniteInternalFuture completeFut; + if (req.replyRequired()) { + IgniteInternalFuture completeFut; - IgniteInternalFuture dhtFin = dhtTx == null ? - null : dhtTx.done() ? null : dhtTx.finishFuture(); + IgniteInternalFuture dhtFin = dhtTx == null ? + null : dhtTx.done() ? null : dhtTx.finishFuture(); - final IgniteInternalFuture nearFin = nearTx == null ? - null : nearTx.done() ? null : nearTx.finishFuture(); + final IgniteInternalFuture nearFin = nearTx == null ? + null : nearTx.done() ? null : nearTx.finishFuture(); - if (dhtFin != null && nearFin != null) { - GridCompoundFuture fut = new GridCompoundFuture(); + if (dhtFin != null && nearFin != null) { + GridCompoundFuture fut = new GridCompoundFuture(); - fut.add(dhtFin); - fut.add(nearFin); + fut.add(dhtFin); + fut.add(nearFin); - fut.markInitialized(); + fut.markInitialized(); - completeFut = fut; - } - else - completeFut = dhtFin != null ? dhtFin : nearFin; + completeFut = fut; + } + else + completeFut = dhtFin != null ? dhtFin : nearFin; - if (completeFut != null) { - completeFut.listen(new CI1>() { - @Override public void apply(IgniteInternalFuture fut) { - sendReply(nodeId, req, true, nearTxId); - } - }); + if (completeFut != null) { + completeFut.listen(new CI1>() { + @Override public void apply(IgniteInternalFuture fut) { + sendReply(nodeId, req, true, nearTxId); + } + }); + } + else + sendReply(nodeId, req, true, nearTxId); } else - sendReply(nodeId, req, true, nearTxId); - } - else - sendReply(nodeId, req, true, null); + sendReply(nodeId, req, true, null); - assert req.txState() != null || (dhtTx == null && nearTx == null) : req + " tx=" + dhtTx + " nearTx=" + nearTx; + assert req.txState() != null || (dhtTx == null && nearTx == null) : req + " tx=" + dhtTx + " nearTx=" + nearTx; + } } /** 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 459b2f5111cd6..f43995239e62e 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 @@ -747,7 +747,8 @@ public GridNearTxLocal newTx( boolean storeEnabled, Boolean mvccOp, int txSize, - @Nullable String lb + @Nullable String lb, + boolean tracingEnabled ) { assert sysCacheCtx == null || sysCacheCtx.systemTx(); @@ -770,7 +771,8 @@ public GridNearTxLocal newTx( subjId, taskNameHash, lb, - txDumpsThrottling + txDumpsThrottling, + tracingEnabled ); if (tx.system()) { diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TransactionProxyImpl.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TransactionProxyImpl.java index 486d9ba09793d..d9d683930b6f6 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TransactionProxyImpl.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/cache/transactions/TransactionProxyImpl.java @@ -28,6 +28,7 @@ import org.apache.ignite.internal.IgniteInternalFuture; import org.apache.ignite.internal.processors.cache.GridCacheSharedContext; import org.apache.ignite.internal.processors.cache.distributed.near.GridNearTxLocal; +import org.apache.ignite.internal.processors.tracing.MTC; import org.apache.ignite.internal.util.future.IgniteFinishedFutureImpl; import org.apache.ignite.internal.util.future.IgniteFutureImpl; import org.apache.ignite.internal.util.tostring.GridToStringExclude; @@ -45,6 +46,12 @@ import org.apache.ignite.transactions.TransactionState; import org.jetbrains.annotations.Nullable; +import static org.apache.ignite.internal.processors.tracing.MTC.TraceSurroundings; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_CLOSE; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_COMMIT; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_RESUME; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_ROLLBACK; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_SUSPEND; import static org.apache.ignite.transactions.TransactionState.SUSPENDED; /** @@ -224,16 +231,19 @@ private void leave() { /** {@inheritDoc} */ @Override public void suspend() throws IgniteException { - enter(); + try (TraceSurroundings ignored = + MTC.support(cctx.kernalContext().tracing().create(TX_SUSPEND, MTC.span()))) { + enter(); - try { - cctx.suspendTx(tx); - } - catch (IgniteCheckedException e) { - throw U.convertException(e); - } - finally { - leave(); + try { + cctx.suspendTx(tx); + } + catch (IgniteCheckedException e) { + throw U.convertException(e); + } + finally { + leave(); + } } } @@ -295,95 +305,128 @@ private void leave() { /** {@inheritDoc} */ @Override public void commit() { - enter(); + try (TraceSurroundings ignored = + MTC.support(cctx.kernalContext().tracing().create(TX_COMMIT, MTC.span()))) { + enter(); - try { - IgniteInternalFuture commitFut = cctx.commitTxAsync(tx); + try { + IgniteInternalFuture commitFut = cctx.commitTxAsync(tx); - if (async) - saveFuture(commitFut); - else - commitFut.get(); - } - catch (IgniteCheckedException e) { - throw U.convertException(e); + if (async) + saveFuture(commitFut); + else + commitFut.get(); + } + catch (IgniteCheckedException e) { + throw U.convertException(e); + } + finally { + leave(); + } } finally { - leave(); + MTC.span().end(); } } /** {@inheritDoc} */ @Override public IgniteFuture commitAsync() throws IgniteException { - enter(); + try (TraceSurroundings ignored = + MTC.support(cctx.kernalContext().tracing().create(TX_COMMIT, MTC.span()))) { + enter(); - try { - return (IgniteFuture)createFuture(cctx.commitTxAsync(tx)); + try { + return (IgniteFuture)createFuture(cctx.commitTxAsync(tx)); + } + finally { + leave(); + } } finally { - leave(); + MTC.span().end(); } } /** {@inheritDoc} */ @Override public void close() { - enter(); + try (TraceSurroundings ignored = + MTC.support(cctx.kernalContext().tracing().create(TX_CLOSE, MTC.span()))) { + enter(); - try { - cctx.endTx(tx); - } - catch (IgniteCheckedException e) { - throw U.convertException(e); + try { + cctx.endTx(tx); + } + catch (IgniteCheckedException e) { + throw U.convertException(e); + } + finally { + leave(); + } } finally { - leave(); + MTC.span().end(); } } /** {@inheritDoc} */ @Override public void rollback() { - enter(); + try (TraceSurroundings ignored = + MTC.support(cctx.kernalContext().tracing().create(TX_ROLLBACK, MTC.span()))) { + enter(); - try { - IgniteInternalFuture rollbackFut = cctx.rollbackTxAsync(tx); + try { + IgniteInternalFuture rollbackFut = cctx.rollbackTxAsync(tx); - if (async) - asyncRes = new IgniteFutureImpl(rollbackFut); - else - rollbackFut.get(); - } - catch (IgniteCheckedException e) { - throw U.convertException(e); + if (async) + asyncRes = new IgniteFutureImpl(rollbackFut); + else + rollbackFut.get(); + } + catch (IgniteCheckedException e) { + throw U.convertException(e); + } + finally { + leave(); + } } finally { - leave(); + MTC.span().end(); } } /** {@inheritDoc} */ @Override public IgniteFuture rollbackAsync() throws IgniteException { - enter(); + try (TraceSurroundings ignored = + MTC.support(cctx.kernalContext().tracing().create(TX_ROLLBACK, MTC.span()))) { + enter(); - try { - return (IgniteFuture)(new IgniteFutureImpl(cctx.rollbackTxAsync(tx))); + try { + return (IgniteFuture)(new IgniteFutureImpl(cctx.rollbackTxAsync(tx))); + } + finally { + leave(); + } } finally { - leave(); + MTC.span().end(); } } /** {@inheritDoc} */ @Override public void resume() throws IgniteException { - enter(true); + try (TraceSurroundings ignored = + MTC.support(cctx.kernalContext().tracing().create(TX_RESUME, MTC.span()))) { + enter(true); - try { - cctx.resumeTx(tx); - } - catch (IgniteCheckedException e) { - throw U.convertException(e); - } - finally { - leave(); + try { + cctx.resumeTx(tx); + } + catch (IgniteCheckedException e) { + throw U.convertException(e); + } + finally { + leave(); + } } } diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/tx/ClientTxStartRequest.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/tx/ClientTxStartRequest.java index ef93627f589d5..49ce9a92d1ab8 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/tx/ClientTxStartRequest.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/platform/client/tx/ClientTxStartRequest.java @@ -75,7 +75,8 @@ public ClientTxStartRequest(BinaryRawReader reader) { true, null, 0, - lb + lb, + false ); } finally { diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/tracing/NoopTracing.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/tracing/NoopTracing.java index 0427bb0de8102..77563757c5742 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/tracing/NoopTracing.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/tracing/NoopTracing.java @@ -18,9 +18,9 @@ package org.apache.ignite.internal.processors.tracing; import org.apache.ignite.internal.processors.tracing.configuration.NoopTracingConfigurationManager; -import org.apache.ignite.spi.tracing.TracingConfigurationManager; import org.apache.ignite.internal.processors.tracing.messages.TraceableMessagesHandler; import org.apache.ignite.logger.NullLogger; +import org.apache.ignite.spi.tracing.TracingConfigurationManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/tracing/SpanType.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/tracing/SpanType.java index a58d8b0a9a4d8..6aa282e2e0d59 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/tracing/SpanType.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/tracing/SpanType.java @@ -67,6 +67,97 @@ public enum SpanType { /** Process ordered. */ COMMUNICATION_ORDERED_PROCESS(Scope.COMMUNICATION, "process.ordered", 14), + // Tx traces. + /** Transaction start. */ + TX(Scope.TX, "transaction", 15, true), + + /** Transaction commit. */ + TX_COMMIT(Scope.TX, "transactions.commit", 16), + + /** Transaction rollback. */ + TX_ROLLBACK(Scope.TX, "transactions.rollback", 17), + + /** Transaction close. */ + TX_CLOSE(Scope.TX, "transactions.close", 18), + + /** Transaction suspend. */ + TX_SUSPEND(Scope.TX, "transactions.suspend", 19), + + /** Transaction resume. */ + TX_RESUME(Scope.TX, "transactions.resume", 20), + + /** Transaction near prepare. */ + TX_NEAR_PREPARE(Scope.TX, "transactions.near.prepare", 21), + + /** Transaction near prepare ondone. */ + TX_NEAR_PREPARE_ON_DONE(Scope.TX, "transactions.near.prepare.ondone", 22), + + /** Transaction near prepare onerror. */ + TX_NEAR_PREPARE_ON_ERROR(Scope.TX, "transactions.near.prepare.onerror", 23), + + /** Transaction near prepare ontimeout. */ + TX_NEAR_PREPARE_ON_TIMEOUT(Scope.TX, "transactions.near.prepare.ontimeout", 24), + + /** Transaction dht prepare. */ + TX_DHT_PREPARE(Scope.TX, "transactions.dht.prepare", 25), + + /** Transaction dht prepare ondone. */ + TX_DHT_PREPARE_ON_DONE(Scope.TX, "transactions.dht.prepare.ondone", 26), + + /** Transaction near finish. */ + TX_NEAR_FINISH(Scope.TX, "transactions.near.finish", 27), + + /** Transaction near finish ondone. */ + TX_NEAR_FINISH_ON_DONE(Scope.TX, "transactions.near.finish.ondone", 28), + + /** Transaction dht finish. */ + TX_DHT_FINISH(Scope.TX, "transactions.dht.finish", 29), + + /** Transaction dht finish ondone. */ + TX_DHT_FINISH_ON_DONE(Scope.TX, "transactions.dht.finish.ondone", 30), + + /** Transaction map proceed. */ + TX_MAP_PROCEED(Scope.TX, "transactions.lock.map.proceed", 31), + + /** Transaction map proceed. */ + TX_COLOCATED_LOCK_MAP(Scope.TX, "transactions.colocated.lock.map", 32), + + /** Transaction lock map. */ + TX_DHT_LOCK_MAP(Scope.TX, "transactions.dht.lock.map", 33), + + /** Transaction near enlist read. */ + TX_NEAR_ENLIST_READ(Scope.TX, "transactions.near.enlist.read", 34), + + /** Transaction near enlist write. */ + TX_NEAR_ENLIST_WRITE(Scope.TX, "transactions.near.enlist.write", 35), + + /** Transaction dht process prepare request. */ + TX_PROCESS_DHT_PREPARE_REQ(Scope.TX, "tx.dht.process.prepare.req", 36), + + /** Transaction dht process finish request. */ + TX_PROCESS_DHT_FINISH_REQ(Scope.TX, "tx.dht.process.finish.req", 37), + + /** Transaction dht finish response. */ + TX_PROCESS_DHT_FINISH_RESP(Scope.TX, "tx.dht.process.finish.resp", 38), + + /** Transaction dht one phase commit ack request. */ + TX_PROCESS_DHT_ONE_PHASE_COMMIT_ACK_REQ(Scope.TX, "tx.dht.process.one-phase-commit-ack.req", 39), + + /** Transaction dht prepare response. */ + TX_PROCESS_DHT_PREPARE_RESP(Scope.TX, "tx.dht.process.prepare.response", 40), + + /** Transaction near finish request. */ + TX_NEAR_FINISH_REQ(Scope.TX, "tx.near.process.finish.request", 41), + + /** Transaction near finish response. */ + TX_NEAR_FINISH_RESP(Scope.TX, "tx.near.process.finish.response", 42), + + /** Transaction near prepare request. */ + TX_NEAR_PREPARE_REQ(Scope.TX, "tx.near.process.prepare.request", 43), + + /** Transaction near prepare response. */ + TX_NEAR_PREPARE_RESP(Scope.TX, "tx.near.process.prepare.response", 44), + /** Custom job call. */ CUSTOM_JOB_CALL(Scope.COMMUNICATION, "job.call", 45, true); diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/tracing/configuration/DistributedTracingConfiguration.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/tracing/configuration/DistributedTracingConfiguration.java index fd74c84569f15..862477866bcfc 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/processors/tracing/configuration/DistributedTracingConfiguration.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/tracing/configuration/DistributedTracingConfiguration.java @@ -18,10 +18,10 @@ package org.apache.ignite.internal.processors.tracing.configuration; import java.util.HashMap; +import org.apache.ignite.internal.processors.configuration.distributed.DistributedConfigurationProcessor; import org.apache.ignite.internal.processors.configuration.distributed.SimpleDistributedProperty; import org.apache.ignite.spi.tracing.TracingConfigurationCoordinates; import org.apache.ignite.spi.tracing.TracingConfigurationParameters; -import org.apache.ignite.internal.processors.configuration.distributed.DistributedConfigurationProcessor; /** * The wrapper of {@code HashMap} diff --git a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java index 222e0a44bee09..a23daf392526b 100755 --- a/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/util/IgniteUtils.java @@ -1543,6 +1543,18 @@ public static void printStackTrace(long threadId, GridStringBuilder sb) { printThreadInfo(threadInfo, sb, Collections.emptySet()); } + /** + * @return Stacktrace of current thread as {@link String}. + */ + public static String stackTrace() { + GridStringBuilder sb = new GridStringBuilder(); + long threadId = Thread.currentThread().getId(); + + printStackTrace(threadId, sb); + + return sb.toString(); + } + /** * @return {@code true} if there is java level deadlock. */ diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/tracing/configuration/VisorTracingConfigurationItem.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/tracing/configuration/VisorTracingConfigurationItem.java index 152233d0b1f00..7ff0830e25450 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/visor/tracing/configuration/VisorTracingConfigurationItem.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/tracing/configuration/VisorTracingConfigurationItem.java @@ -22,10 +22,10 @@ import java.io.ObjectOutput; import java.util.Set; import org.apache.ignite.internal.dto.IgniteDataTransferObject; -import org.apache.ignite.spi.tracing.Scope; import org.apache.ignite.internal.processors.tracing.Span; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.spi.tracing.Scope; /** * Data transfer object that contains scope, label, sampling rate and set of included scopes. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/tracing/configuration/VisorTracingConfigurationTask.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/tracing/configuration/VisorTracingConfigurationTask.java index 5be8d3f1262f4..d7b0bc2a526d3 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/visor/tracing/configuration/VisorTracingConfigurationTask.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/tracing/configuration/VisorTracingConfigurationTask.java @@ -22,12 +22,12 @@ import org.apache.ignite.IgniteException; import org.apache.ignite.internal.processors.task.GridInternal; import org.apache.ignite.internal.processors.task.GridVisorManagementTask; -import org.apache.ignite.spi.tracing.Scope; -import org.apache.ignite.spi.tracing.TracingConfigurationCoordinates; -import org.apache.ignite.spi.tracing.TracingConfigurationParameters; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.visor.VisorJob; import org.apache.ignite.internal.visor.VisorOneNodeTask; +import org.apache.ignite.spi.tracing.Scope; +import org.apache.ignite.spi.tracing.TracingConfigurationCoordinates; +import org.apache.ignite.spi.tracing.TracingConfigurationParameters; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/tracing/configuration/VisorTracingConfigurationTaskArg.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/tracing/configuration/VisorTracingConfigurationTaskArg.java index 972a0a1632703..48f08dffbebb3 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/visor/tracing/configuration/VisorTracingConfigurationTaskArg.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/tracing/configuration/VisorTracingConfigurationTaskArg.java @@ -21,10 +21,10 @@ import java.io.ObjectInput; import java.io.ObjectOutput; import java.util.Set; -import org.apache.ignite.spi.tracing.Scope; import org.apache.ignite.internal.processors.tracing.Span; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.spi.tracing.Scope; /** * Argument for {@link VisorTracingConfigurationTask}. diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/tracing/configuration/VisorTracingConfigurationTaskResult.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/tracing/configuration/VisorTracingConfigurationTaskResult.java index dd892b2d3d36a..7fbf9b84b82bd 100644 --- a/modules/core/src/main/java/org/apache/ignite/internal/visor/tracing/configuration/VisorTracingConfigurationTaskResult.java +++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/tracing/configuration/VisorTracingConfigurationTaskResult.java @@ -27,9 +27,9 @@ import java.util.List; import java.util.function.Consumer; import org.apache.ignite.internal.dto.IgniteDataTransferObject; +import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.spi.tracing.TracingConfigurationCoordinates; import org.apache.ignite.spi.tracing.TracingConfigurationParameters; -import org.apache.ignite.internal.util.typedef.internal.U; /** * Result for {@link VisorTracingConfigurationTask}. diff --git a/modules/core/src/main/java/org/apache/ignite/spi/tracing/TracingConfigurationCoordinates.java b/modules/core/src/main/java/org/apache/ignite/spi/tracing/TracingConfigurationCoordinates.java index 7611d4e2d82d4..30a791ae051cc 100644 --- a/modules/core/src/main/java/org/apache/ignite/spi/tracing/TracingConfigurationCoordinates.java +++ b/modules/core/src/main/java/org/apache/ignite/spi/tracing/TracingConfigurationCoordinates.java @@ -17,12 +17,11 @@ package org.apache.ignite.spi.tracing; +import java.io.Serializable; import org.apache.ignite.internal.util.typedef.internal.S; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.io.Serializable; - /** * Specifies to which traces, specific configuration will be applied. In other words it's a sort of tracing * configuration locator. diff --git a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxDataConsistencyOnCommitFailureTest.java b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxDataConsistencyOnCommitFailureTest.java index 3d21b24a96801..e2cb1e2807a25 100644 --- a/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxDataConsistencyOnCommitFailureTest.java +++ b/modules/core/src/test/java/org/apache/ignite/internal/processors/cache/transactions/TxDataConsistencyOnCommitFailureTest.java @@ -187,7 +187,7 @@ private void injectMockedTxManager(Ignite ignite) { } }).when(mockTm). newTx(locTx.implicit(), locTx.implicitSingle(), null, locTx.concurrency(), - locTx.isolation(), locTx.timeout(), locTx.storeEnabled(), null, locTx.size(), locTx.label()); + locTx.isolation(), locTx.timeout(), locTx.storeEnabled(), null, locTx.size(), locTx.label(), false); ctx.setTxManager(mockTm); } @@ -228,7 +228,7 @@ public MockGridNearTxLocal(GridCacheSharedContext ctx, boolean implicit, boolean boolean storeEnabled, Boolean mvccOp, int txSize, @Nullable UUID subjId, int taskNameHash, @Nullable String lb, IgniteTxManager.TxDumpsThrottling txDumpsThrottling) { super(ctx, implicit, implicitSingle, sys, plc, concurrency, isolation, timeout, storeEnabled, mvccOp, - txSize, subjId, taskNameHash, lb, txDumpsThrottling); + txSize, subjId, taskNameHash, lb, txDumpsThrottling, false); } /** {@inheritDoc} */ 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 1306d8003ef66..34566bad67cc1 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 @@ -68,13 +68,13 @@ import org.apache.ignite.internal.binary.builder.BinaryObjectBuilderImpl; import org.apache.ignite.internal.processors.cacheobject.NoOpBinary; import org.apache.ignite.internal.processors.tracing.configuration.NoopTracingConfigurationManager; -import org.apache.ignite.spi.tracing.TracingConfigurationManager; import org.apache.ignite.internal.util.typedef.internal.U; import org.apache.ignite.lang.IgniteProductVersion; import org.apache.ignite.logger.NullLogger; import org.apache.ignite.marshaller.Marshaller; import org.apache.ignite.plugin.IgnitePlugin; import org.apache.ignite.plugin.PluginNotFoundException; +import org.apache.ignite.spi.tracing.TracingConfigurationManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; diff --git a/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteProcessProxy.java b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteProcessProxy.java index 344c31ebd07c4..d9cedc5f2483c 100644 --- a/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteProcessProxy.java +++ b/modules/core/src/test/java/org/apache/ignite/testframework/junits/multijvm/IgniteProcessProxy.java @@ -82,7 +82,6 @@ import org.apache.ignite.internal.processors.cache.GridCacheUtilityKey; import org.apache.ignite.internal.processors.cache.IgniteInternalCache; import org.apache.ignite.internal.processors.hadoop.Hadoop; -import org.apache.ignite.spi.tracing.TracingConfigurationManager; import org.apache.ignite.internal.util.GridJavaProcess; import org.apache.ignite.internal.util.lang.IgnitePredicateX; import org.apache.ignite.internal.util.typedef.G; @@ -99,6 +98,7 @@ import org.apache.ignite.plugin.IgnitePlugin; import org.apache.ignite.plugin.PluginNotFoundException; import org.apache.ignite.resources.IgniteInstanceResource; +import org.apache.ignite.spi.tracing.TracingConfigurationManager; import org.apache.ignite.testframework.junits.IgniteTestResources; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; 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 4a413458f9afa..d04ae92a18299 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 @@ -128,7 +128,6 @@ import org.apache.ignite.testframework.test.ParametersTest; import org.apache.ignite.testframework.test.VariationsIteratorTest; import org.apache.ignite.util.AttributeNodeFilterSelfTest; -import org.apache.ignite.util.GridCommandHandlerTracingConfigurationTest; import org.junit.runner.RunWith; import org.junit.runners.Suite; @@ -298,9 +297,6 @@ ClusterActivationStartedEventTest.class, IgniteThreadGroupNodeRestartTest.class, - - // Tests for tracing configuration - GridCommandHandlerTracingConfigurationTest.class }) public class IgniteBasicTestSuite { } diff --git a/modules/jta/src/main/java/org/apache/ignite/internal/processors/cache/jta/CacheJtaManager.java b/modules/jta/src/main/java/org/apache/ignite/internal/processors/cache/jta/CacheJtaManager.java index 88c86b2040aca..0ccfc4e9d8ce4 100644 --- a/modules/jta/src/main/java/org/apache/ignite/internal/processors/cache/jta/CacheJtaManager.java +++ b/modules/jta/src/main/java/org/apache/ignite/internal/processors/cache/jta/CacheJtaManager.java @@ -169,7 +169,8 @@ private CacheTmLookup createTmLookup(String tmLookupClsName) throws IgniteChecke /*store enabled*/true, /*sql*/false, /*tx size*/0, - null + null, + false ); } diff --git a/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/AbstractTracingTest.java b/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/AbstractTracingTest.java new file mode 100644 index 0000000000000..602a03e997933 --- /dev/null +++ b/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/AbstractTracingTest.java @@ -0,0 +1,369 @@ +/* + * 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.monitoring.opencensus; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.stream.Collectors; +import java.util.stream.Stream; +import io.opencensus.common.Functions; +import io.opencensus.trace.AttributeValue; +import io.opencensus.trace.Span; +import io.opencensus.trace.SpanId; +import io.opencensus.trace.Tracing; +import io.opencensus.trace.export.SpanData; +import io.opencensus.trace.export.SpanExporter; +import io.opencensus.trace.samplers.Samplers; +import org.apache.ignite.cache.CacheAtomicityMode; +import org.apache.ignite.configuration.CacheConfiguration; +import org.apache.ignite.configuration.IgniteConfiguration; +import org.apache.ignite.internal.IgniteInterruptedCheckedException; +import org.apache.ignite.internal.processors.tracing.SpanType; +import org.apache.ignite.internal.util.typedef.internal.U; +import org.apache.ignite.spi.tracing.Scope; +import org.apache.ignite.spi.tracing.TracingConfigurationCoordinates; +import org.apache.ignite.spi.tracing.TracingConfigurationManager; +import org.apache.ignite.spi.tracing.TracingConfigurationParameters; +import org.apache.ignite.spi.tracing.TracingSpi; +import org.apache.ignite.spi.tracing.opencensus.OpenCensusTraceExporter; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; +import org.junit.After; +import org.junit.Before; +import org.junit.BeforeClass; + +import static io.opencensus.trace.AttributeValue.stringAttributeValue; +import static org.apache.ignite.spi.tracing.Scope.COMMUNICATION; +import static org.apache.ignite.spi.tracing.Scope.EXCHANGE; +import static org.apache.ignite.spi.tracing.Scope.TX; + +/** + * Abstract class for open census tracing tests. + */ +public abstract class AbstractTracingTest extends GridCommonAbstractTest { + /** Grid count. */ + static final int GRID_CNT = 3; + + /** Span buffer count - hardcode in open census. */ + private static final int SPAN_BUFFER_COUNT = 32; + + /** Default configuration map. */ + static final Map DFLT_CONFIG_MAP = + new HashMap<>(); + + /** TX scope specific coordinates to be used within several tests. */ + static final TracingConfigurationCoordinates TX_SCOPE_SPECIFIC_COORDINATES = + new TracingConfigurationCoordinates.Builder(TX).build(); + + /** EXCHANGE scope specific coordinates to be used within several tests. */ + static final TracingConfigurationCoordinates EXCHANGE_SCOPE_SPECIFIC_COORDINATES = + new TracingConfigurationCoordinates.Builder(EXCHANGE).build(); + + /** Updated scope specific parameters to be used within several tests. */ + static final TracingConfigurationParameters SOME_SCOPE_SPECIFIC_PARAMETERS = + new TracingConfigurationParameters.Builder().withSamplingRate(0.75). + withIncludedScopes(Collections.singleton(COMMUNICATION)).build(); + + /** TX Label specific coordinates to be used within several tests. */ + static final TracingConfigurationCoordinates TX_LABEL_SPECIFIC_COORDINATES = + new TracingConfigurationCoordinates.Builder(TX).withLabel("label").build(); + + /** Updated label specific parameters to be used within several tests. */ + static final TracingConfigurationParameters SOME_LABEL_SPECIFIC_PARAMETERS = + new TracingConfigurationParameters.Builder().withSamplingRate(0.111). + withIncludedScopes(Collections.singleton(EXCHANGE)).build(); + + static { + DFLT_CONFIG_MAP.put( + new TracingConfigurationCoordinates.Builder(Scope.TX).build(), + TracingConfigurationManager.DEFAULT_TX_CONFIGURATION); + + DFLT_CONFIG_MAP.put( + new TracingConfigurationCoordinates.Builder(Scope.COMMUNICATION).build(), + TracingConfigurationManager.DEFAULT_COMMUNICATION_CONFIGURATION); + + DFLT_CONFIG_MAP.put( + new TracingConfigurationCoordinates.Builder(Scope.EXCHANGE).build(), + TracingConfigurationManager.DEFAULT_EXCHANGE_CONFIGURATION); + + DFLT_CONFIG_MAP.put( + new TracingConfigurationCoordinates.Builder(Scope.DISCOVERY).build(), + TracingConfigurationManager.DEFAULT_DISCOVERY_CONFIGURATION); + } + + /** Test trace exporter handler. */ + private OpenCensusTxTracingTest.TraceExporterTestHandler hnd; + + /** Wrapper of test exporter handler. */ + private OpenCensusTraceExporter exporter; + + /** + * @return Tracing SPI to be used within tests. + */ + protected abstract TracingSpi getTracingSpi(); + + /** {@inheritDoc} */ + @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception { + IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName); + + cfg.setConsistentId(igniteInstanceName); + + if (igniteInstanceName.contains("client")) + cfg.setClientMode(true); + + cfg.setTracingSpi(getTracingSpi()); + + CacheConfiguration ccfg = new CacheConfiguration(DEFAULT_CACHE_NAME); + + ccfg.setAtomicityMode(CacheAtomicityMode.TRANSACTIONAL); + ccfg.setBackups(2); + + cfg.setCacheConfiguration(ccfg); + + return cfg; + } + + /** + * + */ + @BeforeClass + public static void beforeTests() { + /* Uncomment following code to see visualisation on local Zipkin: */ + +// ZipkinTraceExporter.createAndRegister(ZipkinExporterConfiguration.builder() +// .setV2Url("http://localhost:9411/api/v2/spans") +// .setServiceName("ignite") +// .build()); + } + + /** + * + */ + @Before + public void before() throws Exception { + stopAllGrids(); + + hnd = new OpenCensusTxTracingTest.TraceExporterTestHandler(); + + exporter = new OpenCensusTraceExporter(hnd); + + exporter.start("test"); + + startGrids(GRID_CNT); + } + + /** + * + */ + @After + public void after() { + exporter.stop(); + + stopAllGrids(); + } + + /** + * @return Handler. + */ + OpenCensusTxTracingTest.TraceExporterTestHandler handler() { + return hnd; + } + + /** + * Check span. + * + * @param spanType Span type. + * @param parentSpanId Parent span id. + * @param expSpansCnt expected spans count. + * @param expAttrs Attributes to check. + * @return List of founded span ids. + */ + java.util.List checkSpan( + SpanType spanType, + SpanId parentSpanId, + int expSpansCnt, + /* tagName: tagValue*/ Map expAttrs + ) { + java.util.List gotSpans = hnd.allSpans() + .filter( + span -> parentSpanId != null ? + parentSpanId.equals(span.getParentSpanId()) && spanType.spanName().equals(span.getName()) : + spanType.spanName().equals(span.getName())) + .collect(Collectors.toList()); + + assertEquals(expSpansCnt, gotSpans.size()); + + java.util.List spanIds = new ArrayList<>(); + + gotSpans.forEach(spanData -> { + spanIds.add(spanData.getContext().getSpanId()); + + checkSpanAttributes(spanData, expAttrs); + }); + + return spanIds; + } + + /** + * Verify that given spanData contains all (and only) propagated expected attributes. + * @param spanData Span data to check. + * @param expAttrs Attributes to check. + */ + private void checkSpanAttributes(SpanData spanData, /* tagName: tagValue*/ Map expAttrs) { + Map attrs = spanData.getAttributes().getAttributeMap(); + + if (expAttrs != null) { + assertEquals(expAttrs.size(), attrs.size()); + + for (Map.Entry entry : expAttrs.entrySet()) + assertEquals(entry.getValue(), attributeValueToString(attrs.get(entry.getKey()))); + } + } + + /** + * @param attributeVal Attribute value. + */ + protected static String attributeValueToString(AttributeValue attributeVal) { + if (attributeVal == null) + return null; + + return attributeVal.match( + Functions.returnToString(), + Functions.returnToString(), + Functions.returnToString(), + Functions.returnToString(), + Functions.returnConstant("")); + } + + /** + * Test span exporter handler. + */ + static class TraceExporterTestHandler extends SpanExporter.Handler { + /** Collected spans. */ + private final Map collectedSpans = new ConcurrentHashMap<>(); + + /** */ + private final Map> collectedSpansByParents = new ConcurrentHashMap<>(); + + /** {@inheritDoc} */ + @Override public void export(Collection spanDataList) { + for (SpanData data : spanDataList) { + collectedSpans.put(data.getContext().getSpanId(), data); + + if (data.getParentSpanId() != null) + collectedSpansByParents.computeIfAbsent(data.getParentSpanId(), (k) -> new ArrayList<>()).add(data); + } + } + + /** + * @return Stream of all exported spans. + */ + Stream allSpans() { + return collectedSpans.values().stream(); + } + + /** + * @param id Span id. + * @return Exported span by given id. + */ + SpanData spanById(SpanId id) { + return collectedSpans.get(id); + } + + /** + * @param name Span name for search. + * @return Span with given name. + */ + SpanData spanByName(String name) { + return allSpans() + .filter(span -> span.getName().contains(name)) + .findFirst() + .orElse(null); + } + + /** + * @param parentId Parent id. + * @return All spans by parent id. + */ + java.util.List spanByParentId(SpanId parentId) { + return collectedSpansByParents.get(parentId); + } + + /** + * @param parentSpan Top span. + * @return All span which are child of parentSpan in any generation. + */ + java.util.List unrollByParent(SpanData parentSpan) { + ArrayList spanChain = new ArrayList<>(); + + LinkedList queue = new LinkedList<>(); + + queue.add(parentSpan); + + spanChain.add(parentSpan); + + while (!queue.isEmpty()) { + SpanData cur = queue.pollFirst(); + + assert cur != null; + + List child = spanByParentId(cur.getContext().getSpanId()); + + if (child != null) { + spanChain.addAll(child); + + queue.addAll(child); + } + } + + return spanChain; + } + + /** + * @param igniteInstanceName Ignite instance name. + * @return Stream of SpanData. + */ + Stream spansReportedByNode(String igniteInstanceName) { + return collectedSpans.values().stream() + .filter(spanData -> stringAttributeValue(igniteInstanceName) + .equals(spanData.getAttributes().getAttributeMap().get("node.name"))); + } + + /** + * Forces to flush ended spans that not passed to exporter yet. + */ + void flush() throws IgniteInterruptedCheckedException { + // There is hardcoded invariant, that ended spans will be passed to exporter in 2 cases: + // By 5 seconds timeout and if buffer size exceeds 32 spans. + // There is no ability to change this behavior in Opencensus, so this hack is needed to "flush" real spans to exporter. + // @see io.opencensus.implcore.trace.export.ExportComponentImpl. + for (int i = 0; i < SPAN_BUFFER_COUNT; i++) { + Span span = Tracing.getTracer().spanBuilder("test-" + i).setSampler(Samplers.alwaysSample()).startSpan(); + + U.sleep(10); // See same hack in OpenCensusSpanAdapter#end() method. + + span.end(); + } + } + } +} diff --git a/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/IgniteOpenCensusSuite.java b/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/IgniteOpenCensusSuite.java new file mode 100644 index 0000000000000..784244cf5686e --- /dev/null +++ b/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/IgniteOpenCensusSuite.java @@ -0,0 +1,41 @@ +/* + * 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.monitoring.opencensus; + +import org.apache.ignite.TracingConfigurationValidationTest; +import org.junit.runner.RunWith; +import org.junit.runners.Suite; + +/** + * Suite to test OpenCensus integration. + */ +@RunWith(Suite.class) +@Suite.SuiteClasses({ + OpenCensusMetricExporterSpiTest.class, + OpenCensusTracingSpiTest.class, + OpenCensusTxTracingTest.class, + MixedTracingSpiTest.class, + TracingConfigurationValidationTest.class, + OpenCensusTxTracingConfigurationTest.class, + OpenCensusTracingConfigurationGetTest.class, + OpenCensusTracingConfigurationGetAllTest.class, + OpenCensusTracingConfigurationResetTest.class, + OpenCensusTracingConfigurationResetAllTest.class +}) +public class IgniteOpenCensusSuite { +} diff --git a/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/MixedTracingSpiTest.java b/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/MixedTracingSpiTest.java new file mode 100644 index 0000000000000..69435d7ea80dc --- /dev/null +++ b/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/MixedTracingSpiTest.java @@ -0,0 +1,126 @@ +/* + * 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.monitoring.opencensus; + +import java.util.ArrayList; +import java.util.List; +import org.apache.ignite.spi.tracing.NoopTracingSpi; +import org.apache.ignite.spi.tracing.opencensus.OpenCensusTracingSpi; +import org.apache.ignite.testframework.ListeningTestLogger; +import org.apache.ignite.testframework.LogListener; +import org.apache.ignite.testframework.junits.common.GridCommonAbstractTest; +import org.junit.Test; + +/** + * Tests for mixed tracing spi instances. + */ +public class MixedTracingSpiTest extends GridCommonAbstractTest { + + /** */ + private ListeningTestLogger testLog = new ListeningTestLogger(false, log); + + /** {@inheritDoc} */ + @Override protected void afterTest() throws Exception { + stopAllGrids(); + + super.afterTest(); + } + + /** + * Prepares log listeners list. + * + * @return List of prepared log listeners. + */ + private List prepareLogListeners() { + testLog.clearListeners(); + + List listeners = new ArrayList<>(); + + listeners.add(LogListener.matches( + ">>> Remote SPI with the same name is not configured: OpenCensusTracingSpi").build()); + + listeners.add(LogListener.matches( + ">>> Remote SPI with the same name is not configured: NoopTracingSpi").build()); + + listeners.forEach(testLog::registerListener); + + return listeners; + } + + /** + * Start two nodes: one with noop tracing spi and another one with open census tracing spi. + *

+ * Cause both tracing spi instances are annotated with {@code @IgniteSpiConsistencyChecked(optional = true)} + * 'Remote SPI with the same name is not configured: ' warning message is expected on + * node start. + *

+ * Besides that 'Failed to create span from serialized value' is expected, cause it's not possible + * to deserialize {@code NoopSpan.INSTANCE} from {@link NoopTracingSpi} on the node + * with {@link OpenCensusTracingSpi}. + * + * @throws Exception If failed. + */ + @Test + public void testNodesWithDifferentTracingSpiPrintsWarningOnConsistencyCheck() throws Exception { + List listeners = prepareLogListeners(); + + startGrid(getConfiguration(getTestIgniteInstanceName(0) + + "node-with-noop-tracing").setTracingSpi(new NoopTracingSpi()).setGridLogger(testLog)); + + startGrid(getConfiguration(getTestIgniteInstanceName(1) + + "node-with-open-census-tracing").setTracingSpi(new OpenCensusTracingSpi()).setGridLogger(testLog)); + + listeners.forEach(lsnr -> assertTrue(lsnr.check())); + } + + /** + * Start two nodes, both with noop tracing spi instances. No warning messages are expected. + * + * @throws Exception If failed. + */ + @Test + public void testNodesWithNoopTracingSpiPrintsNothingOnConsistencyCheck() throws Exception { + List listeners = prepareLogListeners(); + + startGrid(getConfiguration(getTestIgniteInstanceName(0) + + "node-with-noop-tracing").setTracingSpi(new NoopTracingSpi()).setGridLogger(testLog)); + + startGrid(getConfiguration(getTestIgniteInstanceName(1) + + "node-with-noop-tracing").setTracingSpi(new NoopTracingSpi()).setGridLogger(testLog)); + + listeners.forEach(lsnr -> assertFalse(lsnr.check())); + } + + /** + * Start two nodes, both with open census tracing spi instances. No warning messages are expected. + * + * @throws Exception If failed. + */ + @Test + public void testNodesWithOpenCensusTracingSpiPrintsNothingOnConsistencyCheck() throws Exception { + List listeners = prepareLogListeners(); + + startGrid(getConfiguration(getTestIgniteInstanceName(0) + + "node-with-open-census-tracing").setTracingSpi(new OpenCensusTracingSpi()).setGridLogger(testLog)); + + startGrid(getConfiguration(getTestIgniteInstanceName(1) + + "node-with-open-census-tracing").setTracingSpi(new OpenCensusTracingSpi()).setGridLogger(testLog)); + + listeners.forEach(lsnr -> assertFalse(lsnr.check())); + } +} diff --git a/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/OpenCensusTracingConfigurationGetAllTest.java b/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/OpenCensusTracingConfigurationGetAllTest.java new file mode 100644 index 0000000000000..bad320d250fc6 --- /dev/null +++ b/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/OpenCensusTracingConfigurationGetAllTest.java @@ -0,0 +1,106 @@ +/* + * 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.monitoring.opencensus; + +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import org.apache.ignite.spi.tracing.Scope; +import org.apache.ignite.spi.tracing.TracingConfigurationCoordinates; +import org.apache.ignite.spi.tracing.TracingConfigurationManager; +import org.apache.ignite.spi.tracing.TracingConfigurationParameters; +import org.apache.ignite.spi.tracing.TracingSpi; +import org.apache.ignite.spi.tracing.opencensus.OpenCensusTracingSpi; +import org.junit.Test; + +import static org.apache.ignite.spi.tracing.Scope.TX; + +/** + * Tests for OpenCensus based {@link TracingConfigurationManager#getAll(Scope)}. + */ +public class OpenCensusTracingConfigurationGetAllTest extends AbstractTracingTest { + /** {@inheritDoc} */ + @Override protected TracingSpi getTracingSpi() { + return new OpenCensusTracingSpi(); + } + + /** + * Ensure that getAll() retrieves default transaction configuration. + */ + @Test + public void testThatDefaultConfigurationReturnsIfScopeNotSpecifiedAndCustomConfigurationNotSet() { + assertEquals( + DFLT_CONFIG_MAP, + grid(0).tracingConfiguration().getAll(null)); + } + + /** + * Ensure that getAll(Scope) retrieves default scope specific transaction configuration. + */ + @Test + public void testThatDefaultScopeSpecificConfigurationReturnsIfScopeIsSpecifiedAndCustomConfigurationNotSet() { + assertEquals( + Collections.singletonMap( + TX_SCOPE_SPECIFIC_COORDINATES, + TracingConfigurationManager.DEFAULT_TX_CONFIGURATION), + grid(0).tracingConfiguration().getAll(TX)); + } + + /** + * Update any scope specific configuration and add some label specific one. + * Ensure that getAll() retrieves tracing configuration including updated one. + */ + @Test + public void testThatCustomConfigurationReturnsIfScopeNotSpecifiedAndCustomConfigurationIsSet() { + grid(0).tracingConfiguration().set(TX_SCOPE_SPECIFIC_COORDINATES, SOME_SCOPE_SPECIFIC_PARAMETERS); + + grid(0).tracingConfiguration().set(TX_LABEL_SPECIFIC_COORDINATES, SOME_LABEL_SPECIFIC_PARAMETERS); + + Map expTracingCfg = + new HashMap<>(DFLT_CONFIG_MAP); + + expTracingCfg.put(TX_SCOPE_SPECIFIC_COORDINATES, SOME_SCOPE_SPECIFIC_PARAMETERS); + + expTracingCfg.put(TX_LABEL_SPECIFIC_COORDINATES, SOME_LABEL_SPECIFIC_PARAMETERS); + + assertEquals( + expTracingCfg, + grid(0).tracingConfiguration().getAll(null)); + } + + /** + * Update any scope specific configuration and add some label specific one. + * Ensure that getAll(scope) retrieves updated scope specific configuration. + */ + @Test + public void testThatCustomScopeSpecificConfigurationReturnsIfScopeIsSpecifiedAndCustomConfigurationIsSet() { + grid(0).tracingConfiguration().set(TX_SCOPE_SPECIFIC_COORDINATES, SOME_SCOPE_SPECIFIC_PARAMETERS); + + grid(0).tracingConfiguration().set(TX_LABEL_SPECIFIC_COORDINATES, SOME_LABEL_SPECIFIC_PARAMETERS); + + Map expTracingCfg = new HashMap<>(); + + expTracingCfg.put(TX_SCOPE_SPECIFIC_COORDINATES, SOME_SCOPE_SPECIFIC_PARAMETERS); + + expTracingCfg.put(TX_LABEL_SPECIFIC_COORDINATES, SOME_LABEL_SPECIFIC_PARAMETERS); + + assertEquals( + expTracingCfg, + grid(0).tracingConfiguration().getAll(TX)); + } +} diff --git a/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/OpenCensusTracingConfigurationGetTest.java b/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/OpenCensusTracingConfigurationGetTest.java new file mode 100644 index 0000000000000..88439f8110db9 --- /dev/null +++ b/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/OpenCensusTracingConfigurationGetTest.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.processors.monitoring.opencensus; + +import java.util.Collections; +import org.apache.ignite.spi.tracing.TracingConfigurationCoordinates; +import org.apache.ignite.spi.tracing.TracingConfigurationManager; +import org.apache.ignite.spi.tracing.TracingConfigurationParameters; +import org.apache.ignite.spi.tracing.TracingSpi; +import org.apache.ignite.spi.tracing.opencensus.OpenCensusTracingSpi; +import org.junit.Test; + +import static org.apache.ignite.spi.tracing.Scope.COMMUNICATION; +import static org.apache.ignite.spi.tracing.Scope.TX; + +/** + * Tests for OpenCensus based {@link TracingConfigurationManager#get(TracingConfigurationCoordinates)}. + */ +public class OpenCensusTracingConfigurationGetTest extends AbstractTracingTest { + /** {@inheritDoc} */ + @Override protected TracingSpi getTracingSpi() { + return new OpenCensusTracingSpi(); + } + + /** + * Ensure that label specific configuration get returns default scope specific if there's + * neither corresponding custom label specific nor corresponding custom scope specific. + */ + @Test + public void testThatLabelSpecificConfigurationGetReturnsDefaultIfCustomConfigurationNotSet() { + assertEquals( + TracingConfigurationManager.DEFAULT_TX_CONFIGURATION, + grid(0).tracingConfiguration().get( + new TracingConfigurationCoordinates.Builder(TX).withLabel("label").build())); + } + + /** + * Ensure that label specific configuration get returns custom scope specific if there's no + * corresponding custom label specific one. + */ + @Test + public void testThatLabelSpecificConfigurationGetReturnsCustomScopeSpecificIfLabelSpecificIsNotSet() { + TracingConfigurationCoordinates coords = + new TracingConfigurationCoordinates.Builder(TX).build(); + + TracingConfigurationParameters expScopeSpecificParameters = + new TracingConfigurationParameters.Builder(). + withSamplingRate(0.2). + withIncludedScopes(Collections.singleton(COMMUNICATION)).build(); + + grid(0).tracingConfiguration().set(coords, expScopeSpecificParameters); + + assertEquals( + expScopeSpecificParameters, + grid(0).tracingConfiguration().get( + new TracingConfigurationCoordinates.Builder(TX).withLabel("label").build())); + } + + /** + * Ensure that label specific configuration get returns custom label specific is such one is present. + */ + @Test + public void testThatLabelSpecificConfigurationGetReturnsLabelSpecificOne() { + TracingConfigurationCoordinates coords = + new TracingConfigurationCoordinates.Builder(TX).withLabel("label").build(); + + TracingConfigurationParameters expScopeSpecificParameters = + new TracingConfigurationParameters.Builder(). + withSamplingRate(0.35). + withIncludedScopes(Collections.singleton(COMMUNICATION)).build(); + + grid(0).tracingConfiguration().set(coords, expScopeSpecificParameters); + + assertEquals( + expScopeSpecificParameters, + grid(0).tracingConfiguration().get(coords)); + } + + /** + * Ensure that scope specific configuration get returns default scope specific if there's no corresponding + * custom specific one. + */ + @Test + public void testThatScopeSpecificConfigurationGetReturnsDefaultOneIfCustomConfigurationNotSet() { + assertEquals( + TracingConfigurationManager.DEFAULT_TX_CONFIGURATION, + grid(0).tracingConfiguration().get( + new TracingConfigurationCoordinates.Builder(TX).build())); + } + + /** + * Ensure that scope specific configuration get returns corresponding custom specific one if it's available. + */ + @Test + public void testThatScopeSpecificConfigurationGetReturnsCustomScopeSpecific() { + TracingConfigurationCoordinates coords = + new TracingConfigurationCoordinates.Builder(TX).build(); + + TracingConfigurationParameters expScopeSpecificParameters = + new TracingConfigurationParameters.Builder(). + withSamplingRate(0.2). + withIncludedScopes(Collections.singleton(COMMUNICATION)).build(); + + grid(0).tracingConfiguration().set(coords, expScopeSpecificParameters); + + assertEquals( + expScopeSpecificParameters, + grid(0).tracingConfiguration().get(coords)); + } + + /** + * Ensure that scope specific configuration get returns corresponding custom specific one if it's available + * and ignores label specific one. + */ + @Test + public void testThatScopeSpecificConfigurationGetReturnsScopeSpecificEventIfLabelSpecificIsSet() { + TracingConfigurationCoordinates scopeSpecificCoords = + new TracingConfigurationCoordinates.Builder(TX).build(); + + TracingConfigurationCoordinates lbSpecificCoords = + new TracingConfigurationCoordinates.Builder(TX).withLabel("label").build(); + + TracingConfigurationParameters expScopeSpecificParameters = + new TracingConfigurationParameters.Builder(). + withSamplingRate(0.35). + withIncludedScopes(Collections.singleton(COMMUNICATION)).build(); + + grid(0).tracingConfiguration().set(lbSpecificCoords, expScopeSpecificParameters); + + assertEquals( + TracingConfigurationManager.DEFAULT_TX_CONFIGURATION, + grid(0).tracingConfiguration().get(scopeSpecificCoords)); + } +} diff --git a/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/OpenCensusTracingConfigurationResetAllTest.java b/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/OpenCensusTracingConfigurationResetAllTest.java new file mode 100644 index 0000000000000..c5ac198aad9dd --- /dev/null +++ b/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/OpenCensusTracingConfigurationResetAllTest.java @@ -0,0 +1,98 @@ +/* + * 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.monitoring.opencensus; + +import java.util.HashMap; +import java.util.Map; +import org.apache.ignite.spi.tracing.Scope; +import org.apache.ignite.spi.tracing.TracingConfigurationCoordinates; +import org.apache.ignite.spi.tracing.TracingConfigurationManager; +import org.apache.ignite.spi.tracing.TracingConfigurationParameters; +import org.apache.ignite.spi.tracing.TracingSpi; +import org.apache.ignite.spi.tracing.opencensus.OpenCensusTracingSpi; +import org.junit.Test; + +import static org.apache.ignite.spi.tracing.Scope.TX; + +/** + * Tests for OpenCensus based {@link TracingConfigurationManager#resetAll(Scope)}. + */ +public class OpenCensusTracingConfigurationResetAllTest extends AbstractTracingTest { + /** {@inheritDoc} */ + @Override protected TracingSpi getTracingSpi() { + return new OpenCensusTracingSpi(); + } + + + /** + * Ensure that resetAll() default tracing configuration doesn't effect it. + */ + @Test + public void testThatResetAllDefaultTracingConfigurationDoesNotEffectIt() { + grid(0).tracingConfiguration().resetAll(TX); + + grid(0).tracingConfiguration().resetAll(null); + + assertEquals( + DFLT_CONFIG_MAP, + grid(0).tracingConfiguration().getAll(null)); + } + + /** + * Ensure that resetAll(scope) resets specified scope and only specified scope. + */ + @Test + public void testThatResetAllWithSpecificScopeResetsOnlySpecificScopeBasedConfiguration() { + grid(0).tracingConfiguration().set(TX_SCOPE_SPECIFIC_COORDINATES, SOME_SCOPE_SPECIFIC_PARAMETERS); + + grid(0).tracingConfiguration().set(TX_LABEL_SPECIFIC_COORDINATES, SOME_LABEL_SPECIFIC_PARAMETERS); + + grid(0).tracingConfiguration().set(EXCHANGE_SCOPE_SPECIFIC_COORDINATES, SOME_SCOPE_SPECIFIC_PARAMETERS); + + // Reset scope specific configuration. + grid(0).tracingConfiguration().resetAll(TX); + + Map expTracingCfg = + new HashMap<>(DFLT_CONFIG_MAP); + + expTracingCfg.put(EXCHANGE_SCOPE_SPECIFIC_COORDINATES, SOME_SCOPE_SPECIFIC_PARAMETERS); + + assertEquals( + expTracingCfg, + grid(0).tracingConfiguration().getAll(null)); + } + + /** + * Ensure that resetAll(null) resets configuration of all scopes. + */ + @Test + public void testThatResetAllResetsAllTracingConfigurations() { + grid(0).tracingConfiguration().set(TX_SCOPE_SPECIFIC_COORDINATES, SOME_SCOPE_SPECIFIC_PARAMETERS); + + grid(0).tracingConfiguration().set(TX_LABEL_SPECIFIC_COORDINATES, SOME_LABEL_SPECIFIC_PARAMETERS); + + grid(0).tracingConfiguration().set(EXCHANGE_SCOPE_SPECIFIC_COORDINATES, SOME_SCOPE_SPECIFIC_PARAMETERS); + + // Reset scope specific configuration. + grid(0).tracingConfiguration().resetAll(null); + + assertEquals( + DFLT_CONFIG_MAP, + grid(0).tracingConfiguration().getAll(null)); + } +} diff --git a/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/OpenCensusTracingConfigurationResetTest.java b/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/OpenCensusTracingConfigurationResetTest.java new file mode 100644 index 0000000000000..0a8265ffc5ed2 --- /dev/null +++ b/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/OpenCensusTracingConfigurationResetTest.java @@ -0,0 +1,154 @@ +/* + * 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.monitoring.opencensus; + +import java.util.HashMap; +import java.util.Map; +import org.apache.ignite.spi.tracing.TracingConfigurationCoordinates; +import org.apache.ignite.spi.tracing.TracingConfigurationManager; +import org.apache.ignite.spi.tracing.TracingConfigurationParameters; +import org.apache.ignite.spi.tracing.TracingSpi; +import org.apache.ignite.spi.tracing.opencensus.OpenCensusTracingSpi; +import org.junit.Test; + +/** + * Tests for OpenCensus based {@link TracingConfigurationManager#reset(TracingConfigurationCoordinates)}. + */ +public class OpenCensusTracingConfigurationResetTest extends AbstractTracingTest { + /** {@inheritDoc} */ + @Override protected TracingSpi getTracingSpi() { + return new OpenCensusTracingSpi(); + } + + /** + * Ensure that resetting default tracing configuration doesn't effect it. + */ + @Test + public void testThatResettingDefaultTracingConfigurationDoesNotEffectIt() { + grid(0).tracingConfiguration().reset(TX_SCOPE_SPECIFIC_COORDINATES); + + assertEquals( + DFLT_CONFIG_MAP, + grid(0).tracingConfiguration().getAll(null)); + } + + /** + * Update any scope specific configuration and add some label specific one. + * Reset scope specific configuration and ensure that it was restored to default, + * also ensure that label specific configuration wasn't affected. + */ + @Test + public void testThatResettingScopeSpecificConfigurationWithScopeAndLabelSpecificItemsRestoresOnlyScopeToDefault() { + grid(0).tracingConfiguration().set(TX_SCOPE_SPECIFIC_COORDINATES, SOME_SCOPE_SPECIFIC_PARAMETERS); + + grid(0).tracingConfiguration().set(TX_LABEL_SPECIFIC_COORDINATES, SOME_LABEL_SPECIFIC_PARAMETERS); + + grid(0).tracingConfiguration().set(EXCHANGE_SCOPE_SPECIFIC_COORDINATES, SOME_SCOPE_SPECIFIC_PARAMETERS); + + Map expTracingCfg = + new HashMap<>(DFLT_CONFIG_MAP); + + expTracingCfg.put(TX_SCOPE_SPECIFIC_COORDINATES, SOME_SCOPE_SPECIFIC_PARAMETERS); + + expTracingCfg.put(TX_LABEL_SPECIFIC_COORDINATES, SOME_LABEL_SPECIFIC_PARAMETERS); + + expTracingCfg.put(EXCHANGE_SCOPE_SPECIFIC_COORDINATES, SOME_SCOPE_SPECIFIC_PARAMETERS); + + // Check tracing configuration. Just in case. + assertEquals( + expTracingCfg, + grid(0).tracingConfiguration().getAll(null)); + + // Reset scope specific configuration. + grid(0).tracingConfiguration().reset(TX_SCOPE_SPECIFIC_COORDINATES); + + // Modify expected tracing configuration map to reflect changes after resetting scope specific configuration. + expTracingCfg.put(TX_SCOPE_SPECIFIC_COORDINATES, TracingConfigurationManager.DEFAULT_TX_CONFIGURATION); + + // Check tracing configuration after resetting. + assertEquals( + expTracingCfg, + grid(0).tracingConfiguration().getAll(null)); + + // Just in case, assert with simple get() + assertEquals( + TracingConfigurationManager.DEFAULT_TX_CONFIGURATION, + grid(0).tracingConfiguration().get(TX_SCOPE_SPECIFIC_COORDINATES)); + + assertEquals( + SOME_LABEL_SPECIFIC_PARAMETERS, + grid(0).tracingConfiguration().get(TX_LABEL_SPECIFIC_COORDINATES)); + + assertEquals( + SOME_SCOPE_SPECIFIC_PARAMETERS, + grid(0).tracingConfiguration().get(EXCHANGE_SCOPE_SPECIFIC_COORDINATES)); + } + + /** + * Update any scope specific configuration and add some label specific one. + * Reset label specific configuration and ensure that it was restored to default, + * also ensure that scope specific configuration wasn't affected. + */ + @Test + public void testThatResettingLabelSpecificConfigurationWithScopeAndLabelSpecificItemsRestoresOnlyLabelToDefault() { + grid(0).tracingConfiguration().set(TX_SCOPE_SPECIFIC_COORDINATES, SOME_SCOPE_SPECIFIC_PARAMETERS); + + grid(0).tracingConfiguration().set(TX_LABEL_SPECIFIC_COORDINATES, SOME_LABEL_SPECIFIC_PARAMETERS); + + grid(0).tracingConfiguration().set(EXCHANGE_SCOPE_SPECIFIC_COORDINATES, SOME_SCOPE_SPECIFIC_PARAMETERS); + + Map expTracingCfg = + new HashMap<>(DFLT_CONFIG_MAP); + + expTracingCfg.put(TX_SCOPE_SPECIFIC_COORDINATES, SOME_SCOPE_SPECIFIC_PARAMETERS); + + expTracingCfg.put(TX_LABEL_SPECIFIC_COORDINATES, SOME_LABEL_SPECIFIC_PARAMETERS); + + expTracingCfg.put(EXCHANGE_SCOPE_SPECIFIC_COORDINATES, SOME_SCOPE_SPECIFIC_PARAMETERS); + + // Check tracing configuration. Just in case. + assertEquals( + expTracingCfg, + grid(0).tracingConfiguration().getAll(null)); + + // Reset scope specific configuration. + grid(0).tracingConfiguration().reset(TX_LABEL_SPECIFIC_COORDINATES); + + // Modify expected tracing configuration map to reflect changes after resetting scope specific configuration. + expTracingCfg.remove(TX_LABEL_SPECIFIC_COORDINATES); + + // Check tracing configuration after resetting. + assertEquals( + expTracingCfg, + grid(0).tracingConfiguration().getAll(null)); + + // Just in case, assert with simple get() + assertEquals( + SOME_SCOPE_SPECIFIC_PARAMETERS, + grid(0).tracingConfiguration().get(TX_SCOPE_SPECIFIC_COORDINATES)); + + // Cause there's no label specific configuration after reset, scope specific should be returned. + assertEquals( + SOME_SCOPE_SPECIFIC_PARAMETERS, + grid(0).tracingConfiguration().get(TX_LABEL_SPECIFIC_COORDINATES)); + + assertEquals( + SOME_SCOPE_SPECIFIC_PARAMETERS, + grid(0).tracingConfiguration().get(EXCHANGE_SCOPE_SPECIFIC_COORDINATES)); + } +} diff --git a/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/OpenCensusTracingSpiTest.java b/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/OpenCensusTracingSpiTest.java new file mode 100644 index 0000000000000..0efed98accad9 --- /dev/null +++ b/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/OpenCensusTracingSpiTest.java @@ -0,0 +1,372 @@ +/* + * 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.monitoring.opencensus; + +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; +import io.opencensus.trace.AttributeValue; +import io.opencensus.trace.Status; +import io.opencensus.trace.export.SpanData; +import org.apache.ignite.events.EventType; +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.IgniteFeatures; +import org.apache.ignite.internal.processors.tracing.MTC; +import org.apache.ignite.internal.processors.tracing.SpanTags; +import org.apache.ignite.spi.tracing.Scope; +import org.apache.ignite.spi.tracing.TracingConfigurationCoordinates; +import org.apache.ignite.spi.tracing.TracingConfigurationParameters; +import org.apache.ignite.spi.tracing.TracingSpi; +import org.apache.ignite.spi.tracing.opencensus.OpenCensusTracingSpi; +import org.junit.Assert; +import org.junit.Test; + +import static io.opencensus.trace.AttributeValue.stringAttributeValue; +import static org.apache.ignite.internal.processors.tracing.SpanType.COMMUNICATION_JOB_EXECUTE_REQUEST; +import static org.apache.ignite.internal.processors.tracing.SpanType.COMMUNICATION_JOB_EXECUTE_RESPONSE; +import static org.apache.ignite.internal.processors.tracing.SpanType.COMMUNICATION_REGULAR_PROCESS; +import static org.apache.ignite.internal.processors.tracing.SpanType.COMMUNICATION_SOCKET_READ; +import static org.apache.ignite.internal.processors.tracing.SpanType.COMMUNICATION_SOCKET_WRITE; +import static org.apache.ignite.internal.processors.tracing.SpanType.CUSTOM_JOB_CALL; +import static org.apache.ignite.internal.processors.tracing.SpanType.DISCOVERY_CUSTOM_EVENT; +import static org.apache.ignite.internal.processors.tracing.SpanType.DISCOVERY_NODE_JOIN_ADD; +import static org.apache.ignite.internal.processors.tracing.SpanType.DISCOVERY_NODE_JOIN_FINISH; +import static org.apache.ignite.internal.processors.tracing.SpanType.DISCOVERY_NODE_JOIN_REQUEST; +import static org.apache.ignite.internal.processors.tracing.SpanType.DISCOVERY_NODE_LEFT; +import static org.apache.ignite.internal.processors.tracing.SpanType.EXCHANGE_FUTURE; +import static org.apache.ignite.spi.tracing.TracingConfigurationParameters.SAMPLING_RATE_ALWAYS; + +/** + * Tests to check correctness of OpenCensus Tracing SPI implementation. + */ +public class OpenCensusTracingSpiTest extends AbstractTracingTest { + /** {@inheritDoc} */ + @Override protected TracingSpi getTracingSpi() { + return new OpenCensusTracingSpi(); + } + + /** {@inheritDoc} */ + @Override public void before() throws Exception { + super.before(); + + grid(0).tracingConfiguration().set( + new TracingConfigurationCoordinates.Builder(Scope.DISCOVERY).build(), + new TracingConfigurationParameters.Builder(). + withSamplingRate(SAMPLING_RATE_ALWAYS).build()); + + grid(0).tracingConfiguration().set( + new TracingConfigurationCoordinates.Builder(Scope.COMMUNICATION).build(), + new TracingConfigurationParameters.Builder(). + withSamplingRate(SAMPLING_RATE_ALWAYS).build()); + } + + /** + * Test checks that node join process is traced correctly in positive case. + */ + @Test + public void testNodeJoinTracing() throws Exception { + IgniteEx joinedNode = startGrid(GRID_CNT); + + awaitPartitionMapExchange(); + + // Consistent id is the same with node name. + List clusterNodeNames = grid(0).cluster().nodes() + .stream().map(node -> (String)node.consistentId()).collect(Collectors.toList()); + + handler().flush(); + + String joinedNodeId = joinedNode.localNode().id().toString(); + + // Check existence of Traces.Discovery.NODE_JOIN_REQUEST spans with OK status on all nodes: + Map nodeJoinReqSpans = handler().allSpans() + .filter(span -> DISCOVERY_NODE_JOIN_REQUEST.spanName().equals(span.getName())) + .filter(span -> span.getStatus() == Status.OK) + .filter(span -> stringAttributeValue(joinedNodeId).equals( + span.getAttributes().getAttributeMap().get(SpanTags.tag(SpanTags.EVENT_NODE, SpanTags.ID)))) + .collect(Collectors.toMap( + span -> span.getAttributes().getAttributeMap().get(SpanTags.tag(SpanTags.NODE, SpanTags.NAME)), + span -> span + )); + + // NODE_JOIN_REQUEST must be processed at least on coordinator node. + // For other nodes there is no such guarantee. + int CRD_IDX = 0; + clusterNodeNames.stream().filter( + node -> node.endsWith(String.valueOf(CRD_IDX)) + ).forEach(nodeName -> + Assert.assertTrue( + String.format( + "%s not found on node with name=%s, nodeJoinReqSpans=%s", + DISCOVERY_NODE_JOIN_REQUEST, nodeName, nodeJoinReqSpans), + nodeJoinReqSpans.containsKey(stringAttributeValue(nodeName))) + ); + + // Check existence of Traces.Discovery.NODE_JOIN_ADD spans with OK status on all nodes: + for (int i = 0; i <= GRID_CNT; i++) { + List nodeJoinAddSpans = handler().spansReportedByNode(getTestIgniteInstanceName(i)) + .filter(span -> DISCOVERY_NODE_JOIN_ADD.spanName().equals(span.getName())) + .filter(span -> span.getStatus() == Status.OK) + .filter(span -> stringAttributeValue(joinedNodeId).equals( + span.getAttributes().getAttributeMap().get(SpanTags.tag(SpanTags.EVENT_NODE, SpanTags.ID)))) + .collect(Collectors.toList()); + + Assert.assertTrue( + String.format("%s span not found, nodeId=%d", + DISCOVERY_NODE_JOIN_ADD, i), + !nodeJoinReqSpans.isEmpty() + ); + + nodeJoinAddSpans.forEach(spanData -> { + SpanData parentSpan = handler().spanById(spanData.getParentSpanId()); + + Assert.assertNotNull( + "Parent span doesn't exist for " + spanData, + parentSpan + ); + Assert.assertEquals( + "Parent span name is invalid, parentSpan=" + parentSpan, + DISCOVERY_NODE_JOIN_REQUEST.spanName(), + parentSpan.getName() + ); + Assert.assertEquals( + "Parent span is not related to joined node, parentSpan=" + parentSpan, + stringAttributeValue(joinedNodeId), + parentSpan.getAttributes().getAttributeMap().get(SpanTags.tag(SpanTags.EVENT_NODE, SpanTags.ID)) + ); + }); + } + + // Check existence of Traces.Discovery.NODE_JOIN_FINISH spans with OK status on all nodes: + for (int i = 0; i <= GRID_CNT; i++) { + List nodeJoinAddSpans = handler().spansReportedByNode(getTestIgniteInstanceName(i)) + .filter(span -> DISCOVERY_NODE_JOIN_FINISH.spanName().equals(span.getName())) + .filter(span -> span.getStatus() == Status.OK) + .filter(span -> stringAttributeValue(joinedNodeId).equals( + span.getAttributes().getAttributeMap().get(SpanTags.tag(SpanTags.EVENT_NODE, SpanTags.ID)))) + .collect(Collectors.toList()); + + Assert.assertTrue( + String.format("%s span not found, nodeId=%d", + DISCOVERY_NODE_JOIN_FINISH, i), + !nodeJoinReqSpans.isEmpty() + ); + + nodeJoinAddSpans.forEach(spanData -> { + SpanData parentSpan = handler().spanById(spanData.getParentSpanId()); + + Assert.assertNotNull( + "Parent span doesn't exist for " + spanData, + parentSpan + ); + Assert.assertEquals( + "Parent span name is invalid " + parentSpan, + DISCOVERY_NODE_JOIN_ADD.spanName(), + parentSpan.getName() + ); + Assert.assertEquals( + "Parent span is not related to joined node " + parentSpan, + stringAttributeValue(joinedNodeId), + parentSpan.getAttributes().getAttributeMap().get(SpanTags.tag(SpanTags.EVENT_NODE, SpanTags.ID)) + ); + }); + } + } + + /** + * Test checks that node left process is traced correctly in positive case. + */ + @Test + public void testNodeLeftTracing() throws Exception { + // Consistent id is the same with node name. + List clusterNodeNames = grid(0).cluster().forServers().nodes() + .stream().map(node -> (String)node.consistentId()).collect(Collectors.toList()); + + String leftNodeId = grid(GRID_CNT - 1).localNode().id().toString(); + + stopGrid(GRID_CNT - 1); + + awaitPartitionMapExchange(); + + handler().flush(); + + // Check existence of DISCOVERY_NODE_LEFT spans with OK status on all nodes: + Map nodeLeftSpans = handler().allSpans() + .filter(span -> DISCOVERY_NODE_LEFT.spanName().equals(span.getName())) + .filter(span -> stringAttributeValue(leftNodeId).equals( + span.getAttributes().getAttributeMap().get(SpanTags.tag(SpanTags.EVENT_NODE, SpanTags.ID)))) + .filter(span -> span.getStatus() == Status.OK) + .collect(Collectors.toMap( + span -> span.getAttributes().getAttributeMap().get(SpanTags.tag(SpanTags.NODE, SpanTags.NAME)), + span -> span, + (span1, span2) -> { + throw new AssertionError(String.format( + "More than 1 %s span handled on a node (id can be extracted from span), " + + "existingSpan=%s, extraSpan=%s", + DISCOVERY_NODE_LEFT, span1, span2 + )); + } + )); + + clusterNodeNames.forEach(nodeName -> + Assert.assertTrue( + "Span " + DISCOVERY_NODE_LEFT + " doesn't exist on node with name=" + nodeName, + nodeLeftSpans.containsKey(stringAttributeValue(nodeName))) + ); + } + + /** + * Test checks that PME process in case of node left discovery event is traced correctly in positive case. + */ + @Test + public void testPartitionsMapExchangeTracing() throws Exception { + long curTopVer = grid(0).cluster().topologyVersion(); + + String leftNodeId = grid(GRID_CNT - 1).localNode().id().toString(); + + stopGrid(GRID_CNT - 1); + + awaitPartitionMapExchange(); + + handler().flush(); + + // Check PME for NODE_LEFT event on remaining nodes: + for (int i = 0; i < GRID_CNT - 1; i++) { + List exchFutSpans = handler().spansReportedByNode(getTestIgniteInstanceName(i)) + .filter(span -> EXCHANGE_FUTURE.spanName().equals(span.getName())) + .filter(span -> span.getStatus() == Status.OK) + .filter(span -> AttributeValue.stringAttributeValue(String.valueOf(EventType.EVT_NODE_LEFT)).equals( + span.getAttributes().getAttributeMap().get(SpanTags.tag(SpanTags.EVENT, SpanTags.TYPE)))) + .filter(span -> stringAttributeValue(leftNodeId).equals( + span.getAttributes().getAttributeMap().get(SpanTags.tag(SpanTags.EVENT_NODE, SpanTags.ID)))) + .collect(Collectors.toList()); + + Assert.assertTrue( + String.format("%s span not found (or more than 1), nodeId=%d, exchFutSpans=%s", + EXCHANGE_FUTURE, i, exchFutSpans), + exchFutSpans.size() == 1 + ); + + exchFutSpans.forEach(span -> { + SpanData parentSpan = handler().spanById(span.getParentSpanId()); + + Assert.assertNotNull( + "Parent span doesn't exist for " + span, + parentSpan + ); + Assert.assertEquals( + "Parent span name is invalid " + parentSpan, + DISCOVERY_NODE_LEFT.spanName(), + parentSpan.getName() + ); + Assert.assertEquals( + "Parent span is not related to joined node " + parentSpan, + stringAttributeValue(leftNodeId), + parentSpan.getAttributes().getAttributeMap().get(SpanTags.tag(SpanTags.EVENT_NODE, SpanTags.ID)) + ); + Assert.assertEquals( + "Exchange future major topology version is invalid " + span, + AttributeValue.stringAttributeValue(String.valueOf(curTopVer + 1)), + span.getAttributes().getAttributeMap().get( + SpanTags.tag(SpanTags.RESULT, SpanTags.TOPOLOGY_VERSION, SpanTags.MAJOR)) + ); + Assert.assertEquals( + "Exchange future minor version is invalid " + span, + AttributeValue.stringAttributeValue("0"), + span.getAttributes().getAttributeMap().get( + SpanTags.tag(SpanTags.RESULT, SpanTags.TOPOLOGY_VERSION, SpanTags.MINOR)) + ); + }); + } + } + + /** + * @throws Exception if failed. + */ + @Test + public void testCommunicationMessages() throws Exception { + IgniteEx ignite = grid(0); + IgniteEx ignite1 = grid(1); + + try (MTC.TraceSurroundings ignore = MTC.support(ignite.context().tracing().create(CUSTOM_JOB_CALL))) { + ignite.compute(ignite.cluster().forNode(ignite1.localNode())).withNoFailover().call(() -> ""); + } + + handler().flush(); + + SpanData jobSpan = handler().spanByName(CUSTOM_JOB_CALL.spanName()); + + List data = handler().unrollByParent(jobSpan); + + List nodejobMsgTags = data.stream() + .filter(it -> it.getAttributes().getAttributeMap().containsKey(SpanTags.MESSAGE)) + .map(it -> it.getAttributes().getAttributeMap().get(SpanTags.MESSAGE)) + .collect(Collectors.toList()); + + List nodejobTraces = data.stream() + .map(SpanData::getName) + .collect(Collectors.toList()); + + assertEquals(nodejobTraces.toString(), 7, nodejobTraces.size()); + + assertEquals(1, nodejobTraces.stream().filter(it -> it.contains(CUSTOM_JOB_CALL.spanName())).count()); + + //request + response + assertEquals(2, nodejobTraces.stream().filter(it -> it.contains(COMMUNICATION_SOCKET_WRITE.spanName())).count()); + //request + response + assertEquals(2, nodejobTraces.stream().filter(it -> it.contains(COMMUNICATION_SOCKET_READ.spanName())).count()); + //request + response + assertEquals(2, nodejobTraces.stream().filter(it -> it.contains(COMMUNICATION_REGULAR_PROCESS.spanName())).count()); + + assertTrue(nodejobMsgTags.stream().anyMatch(it -> it.equals(stringAttributeValue(COMMUNICATION_JOB_EXECUTE_REQUEST.spanName())))); + assertTrue(nodejobMsgTags.stream().anyMatch(it -> it.equals(stringAttributeValue(COMMUNICATION_JOB_EXECUTE_RESPONSE.spanName())))); + } + + /** + */ + @Test + public void testTracingFeatureAvailable() { + assertTrue(IgniteFeatures.nodeSupports(IgniteFeatures.allFeatures(), IgniteFeatures.TRACING)); + } + + /** + * Ensure that root discovery.custom.event have message.class with corresponding value. + * + * @throws Exception If failed. + */ + @Test + public void testCustomEventContainsMessageClassTag() throws Exception { + IgniteEx ignite = grid(0); + + startGrid(GRID_CNT).createCache("New cache"); + + handler().flush(); + + // Only root discovery.custom.event spans have message.class tag. + List rootCustomEvtSpans = handler().allSpans(). + filter(spanData -> + DISCOVERY_CUSTOM_EVENT.spanName().equals(spanData.getName()) && + spanData.getParentSpanId() == null). + collect(Collectors.toList()); + + // Check that there's at least one discovery.custom.event span with tag "message.class" + // and value "CacheAffinityChangeMessage" + assertTrue(rootCustomEvtSpans.stream().anyMatch( + span -> "CacheAffinityChangeMessage".equals( + attributeValueToString(span.getAttributes().getAttributeMap().get(SpanTags.MESSAGE_CLASS))))); + } +} diff --git a/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/OpenCensusTxTracingConfigurationTest.java b/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/OpenCensusTxTracingConfigurationTest.java new file mode 100644 index 0000000000000..6581c1ee3b86e --- /dev/null +++ b/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/OpenCensusTxTracingConfigurationTest.java @@ -0,0 +1,294 @@ +/* + * 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.monitoring.opencensus; + +import java.util.Arrays; +import java.util.Collections; +import java.util.Set; +import java.util.stream.Collectors; +import io.opencensus.trace.SpanId; +import io.opencensus.trace.export.SpanData; +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.internal.processors.tracing.SpanType; +import org.apache.ignite.spi.tracing.Scope; +import org.apache.ignite.spi.tracing.TracingConfigurationCoordinates; +import org.apache.ignite.spi.tracing.TracingConfigurationParameters; +import org.apache.ignite.spi.tracing.TracingSpi; +import org.apache.ignite.spi.tracing.opencensus.OpenCensusTracingSpi; +import org.apache.ignite.transactions.Transaction; +import org.junit.Test; + +import static org.apache.ignite.spi.tracing.Scope.TX; +import static org.apache.ignite.spi.tracing.TracingConfigurationParameters.SAMPLING_RATE_ALWAYS; +import static org.apache.ignite.spi.tracing.TracingConfigurationParameters.SAMPLING_RATE_NEVER; +import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC; +import static org.apache.ignite.transactions.TransactionIsolation.SERIALIZABLE; + +/** + * Tests for transaction tracing configuration. + */ +public class OpenCensusTxTracingConfigurationTest extends AbstractTracingTest { + /** {@inheritDoc} */ + @Override protected TracingSpi getTracingSpi() { + return new OpenCensusTracingSpi(); + } + + /** + * Ensure that in case of sampling rate equals to 0.0 (Never) no transactions are traced. + * + * @throws Exception If Failed. + */ + @Test + public void testTxConfigurationSamplingRateNeverPreventsTxTracing() throws Exception { + IgniteEx client = startGrid("client"); + + client.tracingConfiguration().set( + new TracingConfigurationCoordinates.Builder(TX).build(), + new TracingConfigurationParameters.Builder().withSamplingRate(SAMPLING_RATE_NEVER).build()); + + client.transactions().txStart(PESSIMISTIC, SERIALIZABLE).commit(); + + handler().flush(); + + Set unexpectedTxSpanNames = Arrays.stream(SpanType.values()). + filter(spanType -> spanType.scope() == TX). + map(SpanType::spanName). + collect(Collectors.toSet()); + + java.util.List gotSpans = handler().allSpans() + .filter(span -> unexpectedTxSpanNames.contains(span.getName())) + .collect(Collectors.toList()); + + assertTrue(gotSpans.isEmpty()); + } + + /** + * Ensure that in case of sampling rate equals to 1.0 (Always) transactions are successfully traced. + * + * @throws Exception If Failed. + */ + @Test + public void testTxConfigurationSamplingRateAlwaysEnablesTxTracing() throws Exception { + IgniteEx client = startGrid("client"); + + client.tracingConfiguration().set( + new TracingConfigurationCoordinates.Builder(TX).build(), + new TracingConfigurationParameters.Builder().withSamplingRate(SAMPLING_RATE_ALWAYS).build()); + + client.transactions().txStart(PESSIMISTIC, SERIALIZABLE).commit(); + + handler().flush(); + + java.util.List gotSpans = handler().allSpans() + .filter(span -> SpanType.TX.spanName().equals(span.getName())) + .collect(Collectors.toList()); + + assertEquals(1, gotSpans.size()); + } + + /** + * Ensure that specifying 0 < sapling rate < 1 within TX scope will trace some but not all transactions. + * Cause of probability nature of sampling, it's not possible to check that 0.5 sampling rate + * will result in exactly half of the transactions being traced. + * + * @throws Exception If Failed. + */ + @Test + public void testTxConfigurationSamplingRateHalfSamplesSomethingAboutHalfTransactions() throws Exception { + IgniteEx client = startGrid("client"); + + client.tracingConfiguration().set( + new TracingConfigurationCoordinates.Builder(TX).build(), + new TracingConfigurationParameters.Builder().withSamplingRate(0.5).build()); + + final int txAmount = 100; + + for (int i = 0; i < txAmount; i++) + client.transactions().txStart(PESSIMISTIC, SERIALIZABLE).commit(); + + handler().flush(); + + java.util.List gotSpans = handler().allSpans() + .filter(span -> SpanType.TX.spanName().equals(span.getName())) + .collect(Collectors.toList()); + + // Cause of probability nature of sampling, it's not possible to check that 0.5 sampling rate will end with + // 5 sampling transactions out of {@code txAmount}, + // so we just check that some and not all transactions were traced. + assertTrue(!gotSpans.isEmpty() && gotSpans.size() < txAmount); + } + + + /** + * Ensure that TX traces doesn't include COMMUNICATION sub-traces in case of empty set of included scopes. + * + * @throws Exception If Failed. + */ + @Test + public void testTxTraceDoesNotIncludeCommunicationTracesInCaseOfEmptyIncludedScopes() throws Exception { + IgniteEx client = startGrid("client"); + + client.tracingConfiguration().set( + new TracingConfigurationCoordinates.Builder(TX).build(), + new TracingConfigurationParameters.Builder().withSamplingRate(SAMPLING_RATE_ALWAYS).build()); + + Transaction tx = client.transactions().txStart(PESSIMISTIC, SERIALIZABLE); + + client.cache(DEFAULT_CACHE_NAME).put(1, 1); + + tx.commit(); + + handler().flush(); + + SpanId parentSpanId = handler().allSpans() + .filter(span -> SpanType.TX_NEAR_PREPARE.spanName().equals(span.getName())) + .collect(Collectors.toList()).get(0).getContext().getSpanId(); + + java.util.List gotSpans = handler().allSpans() + .filter(span -> parentSpanId.equals(span.getParentSpanId()) && + SpanType.COMMUNICATION_SOCKET_WRITE.spanName().equals(span.getName())) + .collect(Collectors.toList()); + + assertTrue(gotSpans.isEmpty()); + } + + /** + * Ensure that TX trace does include COMMUNICATION sub-traces in case of COMMUNICATION scope within the set + * of included scopes of the corresponding TX tracing configuration. + * + * @throws Exception If Failed. + */ + @Test + public void testTxTraceIncludesCommunicationTracesInCaseOfCommunicationScopeInTxIncludedScopes() throws Exception { + IgniteEx client = startGrid("client"); + + client.tracingConfiguration().set( + new TracingConfigurationCoordinates.Builder(TX).build(), + new TracingConfigurationParameters.Builder(). + withSamplingRate(SAMPLING_RATE_ALWAYS). + withIncludedScopes(Collections.singleton(Scope.COMMUNICATION)). + build()); + + Transaction tx = client.transactions().txStart(PESSIMISTIC, SERIALIZABLE); + + client.cache(DEFAULT_CACHE_NAME).put(1, 1); + + tx.commit(); + + handler().flush(); + + SpanId parentSpanId = handler().allSpans() + .filter(span -> SpanType.TX_NEAR_PREPARE.spanName().equals(span.getName())) + .collect(Collectors.toList()).get(0).getContext().getSpanId(); + + java.util.List gotSpans = handler().allSpans() + .filter(span -> parentSpanId.equals(span.getParentSpanId()) && + SpanType.COMMUNICATION_SOCKET_WRITE.spanName().equals(span.getName())) + .collect(Collectors.toList()); + + assertFalse(gotSpans.isEmpty()); + } + + /** + * Ensure that label specific configuration is used instead of scope specific if it's possible. + * + * @throws Exception If Failed. + */ + @Test + public void testThatLabelSpecificConfigurationIsUsedWheneverPossible() throws Exception { + IgniteEx client = startGrid("client"); + + final String txLbToBeTraced = "label1"; + + final String txLbNotToBeTraced = "label2"; + + client.tracingConfiguration().set( + new TracingConfigurationCoordinates.Builder(TX).withLabel(txLbToBeTraced).build(), + new TracingConfigurationParameters.Builder().withSamplingRate(SAMPLING_RATE_ALWAYS).build()); + + client.transactions().withLabel(txLbToBeTraced).txStart(PESSIMISTIC, SERIALIZABLE).commit(); + + handler().flush(); + + java.util.List gotSpans = handler().allSpans() + .filter(span -> SpanType.TX.spanName().equals(span.getName())) + .collect(Collectors.toList()); + + assertEquals(1, gotSpans.size()); + + // Not to be traced, cause there's neither tracing configuration with given label + // nor scope specific tx configuration. In that case default tx tracing configuration will be used that + // actually disables tracing. + client.transactions().withLabel(txLbNotToBeTraced).txStart(PESSIMISTIC, SERIALIZABLE).commit(); + + handler().flush(); + + gotSpans = handler().allSpans() + .filter(span -> SpanType.TX.spanName().equals(span.getName())) + .collect(Collectors.toList()); + + // Still only one, previously detected, span is expected. + assertEquals(1, gotSpans.size()); + } + + /** + * Ensure that scope specific configuration is used if corresponding label specific not found. + * + * @throws Exception If Failed. + */ + @Test + public void testThatScopeSpecificConfigurationIsUsedIfLabelSpecificNotFound() throws Exception { + IgniteEx client = startGrid("client"); + + client.tracingConfiguration().set( + new TracingConfigurationCoordinates.Builder(TX).build(), + new TracingConfigurationParameters.Builder().withSamplingRate(SAMPLING_RATE_ALWAYS).build()); + + client.transactions().withLabel("label1").txStart(PESSIMISTIC, SERIALIZABLE).commit(); + + handler().flush(); + + java.util.List gotSpans = handler().allSpans() + .filter(span -> SpanType.TX.spanName().equals(span.getName())) + .collect(Collectors.toList()); + + assertEquals(1, gotSpans.size()); + } + + /** + * Ensure that default scope specific configuration is used if there's no neither label specif not custom scope specific ones. + * Also ensure that by default TX tracing is disabled. + * + * @throws Exception If Failed. + */ + @Test + public void testThatDefaultConfigurationIsUsedIfScopeSpecificNotFoundAndThatByDefaultTxTracingIsDisabled() + throws Exception { + IgniteEx client = startGrid("client"); + + client.transactions().withLabel("label1").txStart(PESSIMISTIC, SERIALIZABLE).commit(); + + handler().flush(); + + java.util.List gotSpans = handler().allSpans() + .filter(span -> SpanType.TX.spanName().equals(span.getName())) + .collect(Collectors.toList()); + + assertTrue(gotSpans.isEmpty()); + } +} diff --git a/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/OpenCensusTxTracingTest.java b/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/OpenCensusTxTracingTest.java new file mode 100644 index 0000000000000..7f3ade6c978aa --- /dev/null +++ b/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/OpenCensusTxTracingTest.java @@ -0,0 +1,1108 @@ +/* + * 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.monitoring.opencensus; + +import java.util.List; +import com.google.common.collect.ImmutableMap; +import io.opencensus.trace.SpanId; +import org.apache.ignite.internal.IgniteEx; +import org.apache.ignite.spi.tracing.Scope; +import org.apache.ignite.spi.tracing.TracingConfigurationCoordinates; +import org.apache.ignite.spi.tracing.TracingConfigurationParameters; +import org.apache.ignite.spi.tracing.TracingSpi; +import org.apache.ignite.spi.tracing.opencensus.OpenCensusTracingSpi; +import org.apache.ignite.transactions.Transaction; +import org.junit.Test; + +import static org.apache.ignite.internal.processors.tracing.SpanType.TX; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_CLOSE; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_COLOCATED_LOCK_MAP; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_COMMIT; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_DHT_FINISH; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_DHT_PREPARE; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_NEAR_ENLIST_WRITE; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_NEAR_FINISH; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_NEAR_FINISH_REQ; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_NEAR_FINISH_RESP; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_NEAR_PREPARE; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_NEAR_PREPARE_REQ; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_NEAR_PREPARE_RESP; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_PROCESS_DHT_FINISH_REQ; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_PROCESS_DHT_PREPARE_REQ; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_PROCESS_DHT_PREPARE_RESP; +import static org.apache.ignite.internal.processors.tracing.SpanType.TX_ROLLBACK; +import static org.apache.ignite.spi.tracing.TracingConfigurationParameters.SAMPLING_RATE_ALWAYS; +import static org.apache.ignite.transactions.TransactionConcurrency.OPTIMISTIC; +import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC; +import static org.apache.ignite.transactions.TransactionIsolation.READ_COMMITTED; +import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ; +import static org.apache.ignite.transactions.TransactionIsolation.SERIALIZABLE; + +/** + * Tests to check correctness of OpenCensus Transactions Tracing implementation. + */ +public class OpenCensusTxTracingTest extends AbstractTracingTest { + + /** {@inheritDoc} */ + @Override protected TracingSpi getTracingSpi() { + return new OpenCensusTracingSpi(); + } + + /** {@inheritDoc} */ + @Override public void before() throws Exception { + super.before(); + + grid(0).tracingConfiguration().set( + new TracingConfigurationCoordinates.Builder(Scope.TX).build(), + new TracingConfigurationParameters.Builder(). + withSamplingRate(SAMPLING_RATE_ALWAYS).build()); + } + + /** + *

    + *
  1. Run pessimistic serializable transaction with some label.
  2. + *
  3. Call two puts inside the transaction.
  4. + *
  5. Commit given transaction.
  6. + *
+ * + * Check that got trace is equal to: + * transaction + * transactions.near.enlist.write + * transactions.colocated.lock.map + * transactions.commit + * transactions.near.prepare + * tx.near.process.prepare.request + * transactions.dht.prepare + * tx.dht.process.prepare.req + * tx.dht.process.prepare.response + * tx.dht.process.prepare.req + * tx.dht.process.prepare.response + * tx.near.process.prepare.response + * transactions.near.finish + * tx.near.process.finish.request + * transactions.dht.finish + * tx.dht.process.finish.req + * tx.dht.process.finish.req + * tx.near.process.finish.response + * + *

+ * Also check that root transaction span contains following tags: + *

    + *
  1. node.id
  2. + *
  3. node.consistent.id
  4. + *
  5. node.name
  6. + *
  7. concurrency
  8. + *
  9. isolation
  10. + *
  11. timeout
  12. + *
  13. label
  14. + *
+ * + */ + @Test + public void testPessimisticSerializableTxTracing() throws Exception { + IgniteEx client = startGrid("client"); + + Transaction tx = client.transactions().withLabel("label1").txStart(PESSIMISTIC, SERIALIZABLE); + + client.cache(DEFAULT_CACHE_NAME).put(1, 1); + + tx.commit(); + + handler().flush(); + + List txSpanIds = checkSpan( + TX, + null, + 1, + ImmutableMap.builder() + .put("node.id", client.localNode().id().toString()) + .put("node.consistent.id", client.localNode().consistentId().toString()) + .put("node.name", client.name()) + .put("concurrency", PESSIMISTIC.name()) + .put("isolation", SERIALIZABLE.name()) + .put("timeout", String.valueOf(0)) + .put("label", "label1") + .build() + ); + + checkSpan( + TX_NEAR_ENLIST_WRITE, + txSpanIds.get(0), + 1, + null); + + checkSpan( + TX_COLOCATED_LOCK_MAP, + txSpanIds.get(0), + 1, + null); + + List commitSpanIds = checkSpan( + TX_COMMIT, + txSpanIds.get(0), + 1, + null); + + List txNearPrepareSpanIds = checkSpan( + TX_NEAR_PREPARE, + commitSpanIds.get(0), + 1, + null); + + List txNearPrepareReqSpanIds = checkSpan( + TX_NEAR_PREPARE_REQ, + txNearPrepareSpanIds.get(0), + 1, + null); + + List txDhtPrepareSpanIds = checkSpan( + TX_DHT_PREPARE, + txNearPrepareReqSpanIds.get(0), + 1, + null); + + List txDhtPrepareReqSpanIds = checkSpan( + TX_PROCESS_DHT_PREPARE_REQ, + txDhtPrepareSpanIds.get(0), + 2, + null); + + for (SpanId parentSpanId: txDhtPrepareReqSpanIds) { + checkSpan( + TX_PROCESS_DHT_PREPARE_RESP, + parentSpanId, + 1, + null); + } + + checkSpan( + TX_NEAR_PREPARE_RESP, + txDhtPrepareSpanIds.get(0), + 1, + null); + + List txNearFinishSpanIds = checkSpan( + TX_NEAR_FINISH, + txNearPrepareSpanIds.get(0), + 1, + null); + + List txNearFinishReqSpanIds = checkSpan( + TX_NEAR_FINISH_REQ, + txNearFinishSpanIds.get(0), + 1, + null); + + List txDhtFinishSpanIds = checkSpan( + TX_DHT_FINISH, + txNearFinishReqSpanIds.get(0), + 1, + null); + + checkSpan( + TX_PROCESS_DHT_FINISH_REQ, + txDhtFinishSpanIds.get(0), + 2, + null); + + checkSpan( + TX_NEAR_FINISH_RESP, + txNearFinishReqSpanIds.get(0), + 1, + null); + } + + /** + *
    + *
  1. Run optimistic serializable transaction with some label.
  2. + *
  3. Call two puts inside the transaction.
  4. + *
  5. Commit given transaction.
  6. + *
+ * + * Check that got trace is equal to: + * transaction + * transactions.near.enlist.write + * transactions.commit + * transactions.near.prepare + * tx.near.process.prepare.request + * transactions.dht.prepare + * tx.dht.process.prepare.req + * tx.dht.process.prepare.response + * tx.dht.process.prepare.req + * tx.dht.process.prepare.response + * tx.near.process.prepare.response + * transactions.near.finish + * tx.near.process.finish.request + * transactions.dht.finish + * tx.dht.process.finish.req + * tx.dht.process.finish.req + * tx.near.process.finish.response + * + *

+ * Also check that root transaction span contains following tags: + *

    + *
  1. node.id
  2. + *
  3. node.consistent.id
  4. + *
  5. node.name
  6. + *
  7. concurrency
  8. + *
  9. isolation
  10. + *
  11. timeout
  12. + *
  13. label
  14. + *
+ * + */ + @Test + public void testOptimisticSerializableTxTracing() throws Exception { + IgniteEx client = startGrid("client"); + + Transaction tx = client.transactions().withLabel("label1").txStart(OPTIMISTIC, SERIALIZABLE); + + client.cache(DEFAULT_CACHE_NAME).put(1, 1); + + tx.commit(); + + handler().flush(); + + List txSpanIds = checkSpan( + TX, + null, + 1, + ImmutableMap.builder() + .put("node.id", client.localNode().id().toString()) + .put("node.consistent.id", client.localNode().consistentId().toString()) + .put("node.name", client.name()) + .put("concurrency", OPTIMISTIC.name()) + .put("isolation", SERIALIZABLE.name()) + .put("timeout", String.valueOf(0)) + .put("label", "label1") + .build() + ); + + checkSpan( + TX_NEAR_ENLIST_WRITE, + txSpanIds.get(0), + 1, + null); + + List commitSpanIds = checkSpan( + TX_COMMIT, + txSpanIds.get(0), + 1, + null); + + List txNearPrepareSpanIds = checkSpan( + TX_NEAR_PREPARE, + commitSpanIds.get(0), + 1, + null); + + List txNearPrepareReqSpanIds = checkSpan( + TX_NEAR_PREPARE_REQ, + txNearPrepareSpanIds.get(0), + 1, + null); + + List txDhtPrepareSpanIds = checkSpan( + TX_DHT_PREPARE, + txNearPrepareReqSpanIds.get(0), + 1, + null); + + List txDhtPrepareReqSpanIds = checkSpan( + TX_PROCESS_DHT_PREPARE_REQ, + txDhtPrepareSpanIds.get(0), + 2, + null); + + for (SpanId parentSpanId: txDhtPrepareReqSpanIds) { + checkSpan( + TX_PROCESS_DHT_PREPARE_RESP, + parentSpanId, + 1, + null); + } + + checkSpan( + TX_NEAR_PREPARE_RESP, + txDhtPrepareSpanIds.get(0), + 1, + null); + + List txNearFinishSpanIds = checkSpan( + TX_NEAR_FINISH, + txNearPrepareSpanIds.get(0), + 1, + null); + + List txNearFinishReqSpanIds = checkSpan( + TX_NEAR_FINISH_REQ, + txNearFinishSpanIds.get(0), + 1, + null); + + List txDhtFinishSpanIds = checkSpan( + TX_DHT_FINISH, + txNearFinishReqSpanIds.get(0), + 1, + null); + + checkSpan( + TX_PROCESS_DHT_FINISH_REQ, + txDhtFinishSpanIds.get(0), + 2, + null); + + checkSpan( + TX_NEAR_FINISH_RESP, + txNearFinishReqSpanIds.get(0), + 1, + null); + } + + /** + *
    + *
  1. Run pessimistic read-committed transaction with some label.
  2. + *
  3. Call two puts inside the transaction.
  4. + *
  5. Commit given transaction.
  6. + *
+ * + * Check that got trace is equal to: + * transaction + * transactions.near.enlist.write + * transactions.colocated.lock.map + * transactions.commit + * transactions.near.prepare + * tx.near.process.prepare.request + * transactions.dht.prepare + * tx.dht.process.prepare.req + * tx.dht.process.prepare.response + * tx.dht.process.prepare.req + * tx.dht.process.prepare.response + * tx.near.process.prepare.response + * transactions.near.finish + * tx.near.process.finish.request + * transactions.dht.finish + * tx.dht.process.finish.req + * tx.dht.process.finish.req + * tx.near.process.finish.response + * + *

+ * Also check that root transaction span contains following tags: + *

    + *
  1. node.id
  2. + *
  3. node.consistent.id
  4. + *
  5. node.name
  6. + *
  7. concurrency
  8. + *
  9. isolation
  10. + *
  11. timeout
  12. + *
  13. label
  14. + *
+ * + */ + @Test + public void testPessimisticReadCommittedTxTracing() throws Exception { + IgniteEx client = startGrid("client"); + + Transaction tx = client.transactions().withLabel("label1").txStart(PESSIMISTIC, READ_COMMITTED); + + client.cache(DEFAULT_CACHE_NAME).put(1, 1); + + tx.commit(); + + handler().flush(); + + List txSpanIds = checkSpan( + TX, + null, + 1, + ImmutableMap.builder() + .put("node.id", client.localNode().id().toString()) + .put("node.consistent.id", client.localNode().consistentId().toString()) + .put("node.name", client.name()) + .put("concurrency", PESSIMISTIC.name()) + .put("isolation", READ_COMMITTED.name()) + .put("timeout", String.valueOf(0)) + .put("label", "label1") + .build() + ); + + checkSpan( + TX_NEAR_ENLIST_WRITE, + txSpanIds.get(0), + 1, + null); + + checkSpan( + TX_COLOCATED_LOCK_MAP, + txSpanIds.get(0), + 1, + null); + + List commitSpanIds = checkSpan( + TX_COMMIT, + txSpanIds.get(0), + 1, + null); + + List txNearPrepareSpanIds = checkSpan( + TX_NEAR_PREPARE, + commitSpanIds.get(0), + 1, + null); + + List txNearPrepareReqSpanIds = checkSpan( + TX_NEAR_PREPARE_REQ, + txNearPrepareSpanIds.get(0), + 1, + null); + + List txDhtPrepareSpanIds = checkSpan( + TX_DHT_PREPARE, + txNearPrepareReqSpanIds.get(0), + 1, + null); + + List txDhtPrepareReqSpanIds = checkSpan( + TX_PROCESS_DHT_PREPARE_REQ, + txDhtPrepareSpanIds.get(0), + 2, + null); + + for (SpanId parentSpanId: txDhtPrepareReqSpanIds) { + checkSpan( + TX_PROCESS_DHT_PREPARE_RESP, + parentSpanId, + 1, + null); + } + + checkSpan( + TX_NEAR_PREPARE_RESP, + txDhtPrepareSpanIds.get(0), + 1, + null); + + List txNearFinishSpanIds = checkSpan( + TX_NEAR_FINISH, + txNearPrepareSpanIds.get(0), + 1, + null); + + List txNearFinishReqSpanIds = checkSpan( + TX_NEAR_FINISH_REQ, + txNearFinishSpanIds.get(0), + 1, + null); + + List txDhtFinishSpanIds = checkSpan( + TX_DHT_FINISH, + txNearFinishReqSpanIds.get(0), + 1, + null); + + checkSpan( + TX_PROCESS_DHT_FINISH_REQ, + txDhtFinishSpanIds.get(0), + 2, + null); + + checkSpan( + TX_NEAR_FINISH_RESP, + txNearFinishReqSpanIds.get(0), + 1, + null); + } + + /** + *
    + *
  1. Run optimistic read-committed transaction with some label.
  2. + *
  3. Call two puts inside the transaction.
  4. + *
  5. Commit given transaction.
  6. + *
+ * + * Check that got trace is equal to: + * transaction + * transactions.near.enlist.write + * transactions.commit + * transactions.near.prepare + * tx.near.process.prepare.request + * transactions.dht.prepare + * tx.dht.process.prepare.req + * tx.dht.process.prepare.response + * tx.dht.process.prepare.req + * tx.dht.process.prepare.response + * tx.near.process.prepare.response + * transactions.near.finish + * tx.near.process.finish.request + * transactions.dht.finish + * tx.dht.process.finish.req + * tx.dht.process.finish.req + * tx.near.process.finish.response + * + *

+ * Also check that root transaction span contains following tags: + *

    + *
  1. node.id
  2. + *
  3. node.consistent.id
  4. + *
  5. node.name
  6. + *
  7. concurrency
  8. + *
  9. isolation
  10. + *
  11. timeout
  12. + *
  13. label
  14. + *
+ * + */ + @Test + public void testOptimisticReadCommittedTxTracing() throws Exception { + IgniteEx client = startGrid("client"); + + Transaction tx = client.transactions().withLabel("label1").txStart(OPTIMISTIC, READ_COMMITTED); + + client.cache(DEFAULT_CACHE_NAME).put(1, 1); + + tx.commit(); + + handler().flush(); + + List txSpanIds = checkSpan( + TX, + null, + 1, + ImmutableMap.builder() + .put("node.id", client.localNode().id().toString()) + .put("node.consistent.id", client.localNode().consistentId().toString()) + .put("node.name", client.name()) + .put("concurrency", OPTIMISTIC.name()) + .put("isolation", READ_COMMITTED.name()) + .put("timeout", String.valueOf(0)) + .put("label", "label1") + .build() + ); + + checkSpan( + TX_NEAR_ENLIST_WRITE, + txSpanIds.get(0), + 1, + null); + + List commitSpanIds = checkSpan( + TX_COMMIT, + txSpanIds.get(0), + 1, + null); + + List txNearPrepareSpanIds = checkSpan( + TX_NEAR_PREPARE, + commitSpanIds.get(0), + 1, + null); + + List txNearPrepareReqSpanIds = checkSpan( + TX_NEAR_PREPARE_REQ, + txNearPrepareSpanIds.get(0), + 1, + null); + + List txDhtPrepareSpanIds = checkSpan( + TX_DHT_PREPARE, + txNearPrepareReqSpanIds.get(0), + 1, + null); + + List txDhtPrepareReqSpanIds = checkSpan( + TX_PROCESS_DHT_PREPARE_REQ, + txDhtPrepareSpanIds.get(0), + 2, + null); + + for (SpanId parentSpanId: txDhtPrepareReqSpanIds) { + checkSpan( + TX_PROCESS_DHT_PREPARE_RESP, + parentSpanId, + 1, + null); + } + + checkSpan( + TX_NEAR_PREPARE_RESP, + txDhtPrepareSpanIds.get(0), + 1, + null); + + List txNearFinishSpanIds = checkSpan( + TX_NEAR_FINISH, + txNearPrepareSpanIds.get(0), + 1, + null); + + List txNearFinishReqSpanIds = checkSpan( + TX_NEAR_FINISH_REQ, + txNearFinishSpanIds.get(0), + 1, + null); + + List txDhtFinishSpanIds = checkSpan( + TX_DHT_FINISH, + txNearFinishReqSpanIds.get(0), + 1, + null); + + checkSpan( + TX_PROCESS_DHT_FINISH_REQ, + txDhtFinishSpanIds.get(0), + 2, + null); + + checkSpan( + TX_NEAR_FINISH_RESP, + txNearFinishReqSpanIds.get(0), + 1, + null); + } + + /** + *
    + *
  1. Run pessimistic repeatable-read transaction with some label.
  2. + *
  3. Call two puts inside the transaction.
  4. + *
  5. Commit given transaction.
  6. + *
+ * + * Check that got trace is equal to: + * transaction + * transactions.near.enlist.write + * transactions.colocated.lock.map + * transactions.commit + * transactions.near.prepare + * tx.near.process.prepare.request + * transactions.dht.prepare + * tx.dht.process.prepare.req + * tx.dht.process.prepare.response + * tx.dht.process.prepare.req + * tx.dht.process.prepare.response + * tx.near.process.prepare.response + * transactions.near.finish + * tx.near.process.finish.request + * transactions.dht.finish + * tx.dht.process.finish.req + * tx.dht.process.finish.req + * tx.near.process.finish.response + * + *

+ * Also check that root transaction span contains following tags: + *

    + *
  1. node.id
  2. + *
  3. node.consistent.id
  4. + *
  5. node.name
  6. + *
  7. concurrency
  8. + *
  9. isolation
  10. + *
  11. timeout
  12. + *
  13. label
  14. + *
+ * + */ + @Test + public void testPessimisticRepeatableReadTxTracing() throws Exception { + IgniteEx client = startGrid("client"); + + Transaction tx = client.transactions().withLabel("label1").txStart(PESSIMISTIC, REPEATABLE_READ); + + client.cache(DEFAULT_CACHE_NAME).put(1, 1); + + tx.commit(); + + handler().flush(); + + List txSpanIds = checkSpan( + TX, + null, + 1, + ImmutableMap.builder() + .put("node.id", client.localNode().id().toString()) + .put("node.consistent.id", client.localNode().consistentId().toString()) + .put("node.name", client.name()) + .put("concurrency", PESSIMISTIC.name()) + .put("isolation", REPEATABLE_READ.name()) + .put("timeout", String.valueOf(0)) + .put("label", "label1") + .build() + ); + + checkSpan( + TX_NEAR_ENLIST_WRITE, + txSpanIds.get(0), + 1, + null); + + checkSpan( + TX_COLOCATED_LOCK_MAP, + txSpanIds.get(0), + 1, + null); + + List commitSpanIds = checkSpan( + TX_COMMIT, + txSpanIds.get(0), + 1, + null); + + List txNearPrepareSpanIds = checkSpan( + TX_NEAR_PREPARE, + commitSpanIds.get(0), + 1, + null); + + List txNearPrepareReqSpanIds = checkSpan( + TX_NEAR_PREPARE_REQ, + txNearPrepareSpanIds.get(0), + 1, + null); + + List txDhtPrepareSpanIds = checkSpan( + TX_DHT_PREPARE, + txNearPrepareReqSpanIds.get(0), + 1, + null); + + List txDhtPrepareReqSpanIds = checkSpan( + TX_PROCESS_DHT_PREPARE_REQ, + txDhtPrepareSpanIds.get(0), + 2, + null); + + for (SpanId parentSpanId: txDhtPrepareReqSpanIds) { + checkSpan( + TX_PROCESS_DHT_PREPARE_RESP, + parentSpanId, + 1, + null); + } + + checkSpan( + TX_NEAR_PREPARE_RESP, + txDhtPrepareSpanIds.get(0), + 1, + null); + + List txNearFinishSpanIds = checkSpan( + TX_NEAR_FINISH, + txNearPrepareSpanIds.get(0), + 1, + null); + + List txNearFinishReqSpanIds = checkSpan( + TX_NEAR_FINISH_REQ, + txNearFinishSpanIds.get(0), + 1, + null); + + List txDhtFinishSpanIds = checkSpan( + TX_DHT_FINISH, + txNearFinishReqSpanIds.get(0), + 1, + null); + + checkSpan( + TX_PROCESS_DHT_FINISH_REQ, + txDhtFinishSpanIds.get(0), + 2, + null); + + checkSpan( + TX_NEAR_FINISH_RESP, + txNearFinishReqSpanIds.get(0), + 1, + null); + } + + /** + *
    + *
  1. Run optimistic repeatable-read transaction with some label.
  2. + *
  3. Call two puts inside the transaction.
  4. + *
  5. Commit given transaction.
  6. + *
+ * + * Check that got trace is equal to: + * transaction + * transactions.near.enlist.write + * transactions.commit + * transactions.near.prepare + * tx.near.process.prepare.request + * transactions.dht.prepare + * tx.dht.process.prepare.req + * tx.dht.process.prepare.response + * tx.dht.process.prepare.req + * tx.dht.process.prepare.response + * tx.near.process.prepare.response + * transactions.near.finish + * tx.near.process.finish.request + * transactions.dht.finish + * tx.dht.process.finish.req + * tx.dht.process.finish.req + * tx.near.process.finish.response + * + *

+ * Also check that root transaction span contains following tags: + *

    + *
  1. node.id
  2. + *
  3. node.consistent.id
  4. + *
  5. node.name
  6. + *
  7. concurrency
  8. + *
  9. isolation
  10. + *
  11. timeout
  12. + *
  13. label
  14. + *
+ * + */ + @Test + public void testOptimisticRepeatableReadTxTracing() throws Exception { + IgniteEx client = startGrid("client"); + + Transaction tx = client.transactions().withLabel("label1").txStart(OPTIMISTIC, REPEATABLE_READ); + + client.cache(DEFAULT_CACHE_NAME).put(1, 1); + + tx.commit(); + + handler().flush(); + + List txSpanIds = checkSpan( + TX, + null, + 1, + ImmutableMap.builder() + .put("node.id", client.localNode().id().toString()) + .put("node.consistent.id", client.localNode().consistentId().toString()) + .put("node.name", client.name()) + .put("concurrency", OPTIMISTIC.name()) + .put("isolation", REPEATABLE_READ.name()) + .put("timeout", String.valueOf(0)) + .put("label", "label1") + .build() + ); + + checkSpan( + TX_NEAR_ENLIST_WRITE, + txSpanIds.get(0), + 1, + null); + + List commitSpanIds = checkSpan( + TX_COMMIT, + txSpanIds.get(0), + 1, + null); + + List txNearPrepareSpanIds = checkSpan( + TX_NEAR_PREPARE, + commitSpanIds.get(0), + 1, + null); + + List txNearPrepareReqSpanIds = checkSpan( + TX_NEAR_PREPARE_REQ, + txNearPrepareSpanIds.get(0), + 1, + null); + + List txDhtPrepareSpanIds = checkSpan( + TX_DHT_PREPARE, + txNearPrepareReqSpanIds.get(0), + 1, + null); + + List txDhtPrepareReqSpanIds = checkSpan( + TX_PROCESS_DHT_PREPARE_REQ, + txDhtPrepareSpanIds.get(0), + 2, + null); + + for (SpanId parentSpanId: txDhtPrepareReqSpanIds) { + checkSpan( + TX_PROCESS_DHT_PREPARE_RESP, + parentSpanId, + 1, + null); + } + + checkSpan( + TX_NEAR_PREPARE_RESP, + txDhtPrepareSpanIds.get(0), + 1, + null); + + List txNearFinishSpanIds = checkSpan( + TX_NEAR_FINISH, + txNearPrepareSpanIds.get(0), + 1, + null); + + List txNearFinishReqSpanIds = checkSpan( + TX_NEAR_FINISH_REQ, + txNearFinishSpanIds.get(0), + 1, + null); + + List txDhtFinishSpanIds = checkSpan( + TX_DHT_FINISH, + txNearFinishReqSpanIds.get(0), + 1, + null); + + checkSpan( + TX_PROCESS_DHT_FINISH_REQ, + txDhtFinishSpanIds.get(0), + 2, + null); + + checkSpan( + TX_NEAR_FINISH_RESP, + txNearFinishReqSpanIds.get(0), + 1, + null); + } + + /** + *
    + *
  1. Run some transaction with some label.
  2. + *
  3. Call two puts inside the transaction.
  4. + *
  5. Rollback given transaction.
  6. + *
+ * + * Check that got trace is equal to: + * transaction + * transactions.near.enlist.write + * transactions.rollback + * + *

+ * Also check that root transaction span contains following tags: + *

    + *
  1. node.id
  2. + *
  3. node.consistent.id
  4. + *
  5. node.name
  6. + *
  7. concurrency
  8. + *
  9. isolation
  10. + *
  11. timeout
  12. + *
  13. label
  14. + *
+ * + */ + @Test + public void testRollbackTransaction() throws Exception { + IgniteEx client = startGrid("client"); + + Transaction tx = client.transactions().withLabel("label1").txStart(OPTIMISTIC, REPEATABLE_READ); + + client.cache(DEFAULT_CACHE_NAME).put(1, 1); + + tx.rollback(); + + handler().flush(); + + List txSpanIds = checkSpan( + TX, + null, + 1, + ImmutableMap.builder() + .put("node.id", client.localNode().id().toString()) + .put("node.consistent.id", client.localNode().consistentId().toString()) + .put("node.name", client.name()) + .put("concurrency", OPTIMISTIC.name()) + .put("isolation", REPEATABLE_READ.name()) + .put("timeout", String.valueOf(0)) + .put("label", "label1") + .build() + ); + + checkSpan( + TX_NEAR_ENLIST_WRITE, + txSpanIds.get(0), + 1, + null); + + checkSpan( + TX_ROLLBACK, + txSpanIds.get(0), + 1, + null); + } + + /** + *
    + *
  1. Run some transaction with some label.
  2. + *
  3. Call two puts inside the transaction.
  4. + *
  5. Close given transaction.
  6. + *
+ * + * Check that got trace is equal to: + * transaction + * transactions.near.enlist.write + * transactions.close + * + *

+ * Also check that root transaction span contains following tags: + *

    + *
  1. node.id
  2. + *
  3. node.consistent.id
  4. + *
  5. node.name
  6. + *
  7. concurrency
  8. + *
  9. isolation
  10. + *
  11. timeout
  12. + *
  13. label
  14. + *
+ * + */ + @Test + public void testCloseTransaction() throws Exception { + IgniteEx client = startGrid("client"); + + Transaction tx = client.transactions().withLabel("label1").txStart(OPTIMISTIC, REPEATABLE_READ); + + client.cache(DEFAULT_CACHE_NAME).put(1, 1); + + tx.close(); + + handler().flush(); + + List txSpanIds = checkSpan( + TX, + null, + 1, + ImmutableMap.builder() + .put("node.id", client.localNode().id().toString()) + .put("node.consistent.id", client.localNode().consistentId().toString()) + .put("node.name", client.name()) + .put("concurrency", OPTIMISTIC.name()) + .put("isolation", REPEATABLE_READ.name()) + .put("timeout", String.valueOf(0)) + .put("label", "label1") + .build() + ); + + checkSpan( + TX_NEAR_ENLIST_WRITE, + txSpanIds.get(0), + 1, + null); + + checkSpan( + TX_CLOSE, + txSpanIds.get(0), + 1, + null); + } +} diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Transactions/TransactionsImpl.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Transactions/TransactionsImpl.cs index cdf5641aa91e6..4368fe33e9c4a 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Transactions/TransactionsImpl.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Impl/Transactions/TransactionsImpl.cs @@ -172,7 +172,7 @@ public void ResetMetrics() DoOutInOp(OpResetMetrics); } - /** */ + /** */ public ITransactions WithLabel(string label) { IgniteArgumentCheck.NotNullOrEmpty(label, "label"); @@ -180,6 +180,12 @@ public ITransactions WithLabel(string label) return _ignite.GetTransactionsWithLabel(label); } + /** */ + public ITransactions WithTracing() + { + return this; + } + /** */ public ITransactionCollection GetLocalActiveTransactions() { diff --git a/modules/platforms/dotnet/Apache.Ignite.Core/Transactions/ITransactions.cs b/modules/platforms/dotnet/Apache.Ignite.Core/Transactions/ITransactions.cs index 0760f36182bdf..ee0b0de766219 100644 --- a/modules/platforms/dotnet/Apache.Ignite.Core/Transactions/ITransactions.cs +++ b/modules/platforms/dotnet/Apache.Ignite.Core/Transactions/ITransactions.cs @@ -107,5 +107,11 @@ ITransaction TxStart(TransactionConcurrency concurrency, TransactionIsolation is /// /// Collection of ITransactionCollection GetLocalActiveTransactions(); + + /// + /// Returns instance of Ignite Transactions to enable tracing for a transaction. + /// + /// + ITransactions WithTracing(); } } diff --git a/modules/spring/src/main/java/org/apache/ignite/IgniteSpringBean.java b/modules/spring/src/main/java/org/apache/ignite/IgniteSpringBean.java index 1866706aa7144..d26abed57e6ec 100644 --- a/modules/spring/src/main/java/org/apache/ignite/IgniteSpringBean.java +++ b/modules/spring/src/main/java/org/apache/ignite/IgniteSpringBean.java @@ -30,12 +30,12 @@ import org.apache.ignite.configuration.CollectionConfiguration; import org.apache.ignite.configuration.IgniteConfiguration; import org.apache.ignite.configuration.NearCacheConfiguration; -import org.apache.ignite.spi.tracing.TracingConfigurationManager; import org.apache.ignite.internal.util.typedef.G; import org.apache.ignite.internal.util.typedef.internal.S; import org.apache.ignite.lang.IgniteProductVersion; import org.apache.ignite.plugin.IgnitePlugin; import org.apache.ignite.plugin.PluginNotFoundException; +import org.apache.ignite.spi.tracing.TracingConfigurationManager; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.springframework.beans.BeansException;