IGNITE-14015 Tracing SQL: tracing of SELECT queries causes incorrect span inheritance (#8675)
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/tracing/TraceableIterator.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/tracing/TraceableIterator.java
index 6fed37e..80c8b4e 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/tracing/TraceableIterator.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/tracing/TraceableIterator.java
@@ -18,6 +18,7 @@
package org.apache.ignite.internal.processors.tracing;
import java.util.Iterator;
+import org.apache.ignite.internal.processors.tracing.MTC.TraceSurroundings;
import static org.apache.ignite.internal.processors.tracing.SpanTags.ERROR;
@@ -28,7 +29,7 @@
/** Iterator to which all calls will be delegated. */
private final Iterator<T> iter;
- /** Span that reperesents trace context in which iterator runs. */
+ /** Span that represents trace context in which iterator runs. */
private final Span span;
/**
@@ -41,9 +42,7 @@
/** {@inheritDoc} */
@Override public boolean hasNext() {
- MTC.supportInitial(span);
-
- try {
+ try (TraceSurroundings ignored = MTC.supportContinual(span)) {
return iter.hasNext();
}
catch (Throwable th) {
@@ -55,9 +54,7 @@
/** {@inheritDoc} */
@Override public T next() {
- MTC.supportInitial(span);
-
- try {
+ try (TraceSurroundings ignored = MTC.supportContinual(span)) {
return iter.next();
}
catch (Throwable th) {
diff --git a/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/OpenCensusSqlJdbcTracingTest.java b/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/OpenCensusSqlJdbcTracingTest.java
index a324ada..d8adcaa 100644
--- a/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/OpenCensusSqlJdbcTracingTest.java
+++ b/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/OpenCensusSqlJdbcTracingTest.java
@@ -21,6 +21,7 @@
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
+import java.util.List;
import java.util.Objects;
import io.opencensus.trace.SpanId;
import org.apache.ignite.client.Config;
@@ -30,6 +31,7 @@
import org.junit.Test;
import static java.sql.DriverManager.getConnection;
+import static org.apache.ignite.cache.CacheMode.PARTITIONED;
import static org.apache.ignite.cache.CacheMode.REPLICATED;
import static org.apache.ignite.internal.processors.query.QueryUtils.DFLT_SCHEMA;
import static org.apache.ignite.internal.processors.tracing.SpanTags.SQL_PAGE_ROWS;
@@ -40,6 +42,7 @@
import static org.apache.ignite.internal.processors.tracing.SpanType.SQL_ITER_CLOSE;
import static org.apache.ignite.internal.processors.tracing.SpanType.SQL_ITER_OPEN;
import static org.apache.ignite.internal.processors.tracing.SpanType.SQL_PAGE_FETCH;
+import static org.apache.ignite.internal.processors.tracing.SpanType.SQL_QRY;
import static org.apache.ignite.internal.processors.tracing.SpanType.SQL_QRY_EXECUTE;
import static org.apache.ignite.internal.processors.tracing.SpanType.SQL_QRY_PARSE;
import static org.apache.ignite.internal.util.IgniteUtils.resolveIgnitePath;
@@ -121,6 +124,48 @@
}
/** {@inheritDoc} */
+ @Override public void testSelectQueryUserThreadSpanNotAffected() throws Exception {
+ String prsnTable = createTableAndPopulate(Person.class, PARTITIONED, 1);
+ String orgTable = createTableAndPopulate(Organization.class, PARTITIONED, 1);
+
+ String url = JDBC_URL_PREFIX + Config.SERVER + '/' + TEST_SCHEMA;
+
+ try (
+ Connection prsntConn = getConnection(url);
+ Connection orgConn = getConnection(url);
+
+ PreparedStatement prsntStmt = prsntConn.prepareStatement("SELECT * FROM " + prsnTable);
+ PreparedStatement orgStmt = orgConn.prepareStatement("SELECT * FROM " + orgTable)
+ ) {
+ prsntStmt.executeQuery();
+ orgStmt.executeQuery();
+
+ try (
+ ResultSet prsnResultSet = prsntStmt.getResultSet();
+ ResultSet orgResultSet = orgStmt.getResultSet()
+ ) {
+ while (prsnResultSet.next() && orgResultSet.next()) {
+ // No-op.
+ }
+ }
+ }
+ catch (SQLException e) {
+ throw new RuntimeException(e);
+ }
+
+ handler().flush();
+
+ checkDroppedSpans();
+
+ List<SpanId> rootSpans = findRootSpans(SQL_QRY);
+
+ assertEquals(2, rootSpans.size());
+
+ for (SpanId rootSpan : rootSpans)
+ checkBasicSelectQuerySpanTree(rootSpan, TEST_TABLE_POPULATION);
+ }
+
+ /** {@inheritDoc} */
@SuppressWarnings("StatementWithEmptyBody")
@Override protected void executeQuery(
String sql,
@@ -132,9 +177,11 @@
String url = JDBC_URL_PREFIX + Config.SERVER + '/' + schema +
"?skipReducerOnUpdate=" + skipReduceOnUpdate + "&distributedJoins=" + distributedJoins;
- try (Connection conn = getConnection(url)) {
- PreparedStatement stmt = conn.prepareStatement(sql);
+ try (
+ Connection conn = getConnection(url);
+ PreparedStatement stmt = conn.prepareStatement(sql)
+ ) {
stmt.setFetchSize(PAGE_SIZE);
if (isQry == null)
diff --git a/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/OpenCensusSqlNativeTracingTest.java b/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/OpenCensusSqlNativeTracingTest.java
index 9698329..309b6f7 100644
--- a/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/OpenCensusSqlNativeTracingTest.java
+++ b/modules/opencensus/src/test/java/org/apache/ignite/internal/processors/monitoring/opencensus/OpenCensusSqlNativeTracingTest.java
@@ -18,6 +18,7 @@
package org.apache.ignite.internal.processors.monitoring.opencensus;
import java.util.Arrays;
+import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.UUID;
@@ -33,6 +34,7 @@
import org.apache.ignite.IgniteCheckedException;
import org.apache.ignite.Ignition;
import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.cache.query.FieldsQueryCursor;
import org.apache.ignite.cache.query.SqlFieldsQuery;
import org.apache.ignite.cache.query.annotations.QuerySqlField;
import org.apache.ignite.configuration.CacheConfiguration;
@@ -42,6 +44,8 @@
import org.apache.ignite.internal.TestRecordingCommunicationSpi;
import org.apache.ignite.internal.processors.cache.query.SqlFieldsQueryEx;
import org.apache.ignite.internal.processors.query.h2.twostep.messages.GridQueryNextPageRequest;
+import org.apache.ignite.internal.processors.tracing.MTC;
+import org.apache.ignite.internal.processors.tracing.NoopSpan;
import org.apache.ignite.internal.processors.tracing.SpanType;
import org.apache.ignite.internal.util.typedef.internal.U;
import org.apache.ignite.spi.tracing.TracingConfigurationCoordinates;
@@ -319,7 +323,7 @@
).boxed().collect(Collectors.toSet());
Set<Integer> parts = Arrays.stream(matcher.group(2).split(","))
- .map(s -> Integer.parseInt(s.trim()))
+ .map(s -> parseInt(s.trim()))
.collect(Collectors.toSet());
assertEquals(expParts, parts);
@@ -489,6 +493,77 @@
}
/**
+ * Tests that tracing of multiple SELECT queries produces separate span tree for each query and does not affect
+ * user thread {@link MTC#span()} value during execution and after it.
+ */
+ @Test
+ public void testSelectQueryUserThreadSpanNotAffected() throws Exception {
+ String prsnTable = createTableAndPopulate(Person.class, PARTITIONED, 1);
+ String orgTable = createTableAndPopulate(Organization.class, PARTITIONED, 1);
+
+ try (
+ FieldsQueryCursor<List<?>> prsnQryCursor = reducer().context().query()
+ .querySqlFields(new SqlFieldsQuery("SELECT * FROM " + prsnTable), false);
+
+ FieldsQueryCursor<List<?>> orgQryCursor = reducer().context().query()
+ .querySqlFields(new SqlFieldsQuery("SELECT * FROM " + orgTable), false)
+ ) {
+ Iterator<List<?>> prsnQryIter = prsnQryCursor.iterator();
+ Iterator<List<?>> orgQryIter = orgQryCursor.iterator();
+
+ while (prsnQryIter.hasNext() && orgQryIter.hasNext()) {
+ assertEquals(NoopSpan.INSTANCE, MTC.span());
+
+ prsnQryIter.next();
+
+ assertEquals(NoopSpan.INSTANCE, MTC.span());
+
+ orgQryIter.next();
+
+ assertEquals(NoopSpan.INSTANCE, MTC.span());
+ }
+ }
+
+ assertEquals(NoopSpan.INSTANCE, MTC.span());
+
+ handler().flush();
+
+ checkDroppedSpans();
+
+ List<SpanId> rootSpans = findRootSpans(SQL_QRY);
+
+ assertEquals(2, rootSpans.size());
+
+ for (SpanId rootSpan : rootSpans)
+ checkBasicSelectQuerySpanTree(rootSpan, TEST_TABLE_POPULATION);
+ }
+
+ /**
+ * Checks presence of basic spans that related to SELECT SQL query and are childs of the specfied span.
+ *
+ * @param expRows Number of rows as a result of SELECT query.
+ * @param rootSpan Span which childs will be checked.
+ */
+ protected void checkBasicSelectQuerySpanTree(SpanId rootSpan, int expRows) {
+ int fetchedRows = 0;
+
+ SpanId iterSpan = checkChildSpan(SQL_ITER_OPEN, rootSpan);
+
+ SpanId fetchSpan = checkChildSpan(SQL_PAGE_FETCH, iterSpan);
+
+ fetchedRows += parseInt(getAttribute(fetchSpan, SQL_PAGE_ROWS));
+
+ List<SpanId> pageFetchSpans = findChildSpans(SQL_PAGE_FETCH, rootSpan);
+
+ for (SpanId span : pageFetchSpans)
+ fetchedRows += parseInt(getAttribute(span, SQL_PAGE_ROWS));
+
+ assertEquals(expRows, fetchedRows);
+
+ assertFalse(findChildSpans(SQL_CURSOR_CLOSE, rootSpan).isEmpty());
+ }
+
+ /**
* Executes DML query and checks corresponding span tree.
*
* @param qry SQL query to execute.
@@ -546,6 +621,19 @@
}
/**
+ * Finds root spans with specified type.
+ *
+ * @param type Span type.
+ * @return Ids of the found spans.
+ */
+ protected List<SpanId> findRootSpans(SpanType type) {
+ return handler().allSpans()
+ .filter(span -> span.getParentSpanId() == null && type.spanName().equals(span.getName()))
+ .map(span -> span.getContext().getSpanId())
+ .collect(Collectors.toList());
+ }
+
+ /**
* Obtains string representation of the attribtute from span with specified id.
*
* @param spanId Id of the target span.
@@ -642,7 +730,7 @@
/**
* Checks that no spans were dropped by OpencenCensus due to exporter buffer overflow.
*/
- private void checkDroppedSpans() {
+ protected void checkDroppedSpans() {
Object worker = U.field(Tracing.getExportComponent().getSpanExporter(), "worker");
long droppedSpans = U.field(worker, "droppedSpans");