You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@ignite.apache.org by ni...@apache.org on 2020/09/23 10:24:14 UTC
[ignite] branch master updated: IGNITE-13426 Adds command to print
system view content (#8249)
This is an automated email from the ASF dual-hosted git repository.
nizhikov pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/ignite.git
The following commit(s) were added to refs/heads/master by this push:
new 69b23b8 IGNITE-13426 Adds command to print system view content (#8249)
69b23b8 is described below
commit 69b23b84d23a2fbbf7a4ec9b0c4cf4669cf0e5d1
Author: Mikhail Petrov <32...@users.noreply.github.com>
AuthorDate: Wed Sep 23 13:23:53 2020 +0300
IGNITE-13426 Adds command to print system view content (#8249)
---
.../ignite/internal/commandline/CommandList.java | 6 +-
.../commandline/systemview/SystemViewCommand.java | 218 ++++
.../systemview/SystemViewCommandArg.java | 44 +
.../commandline/CommandHandlerParsingTest.java | 3 +-
.../testsuites/IgniteControlUtilityTestSuite.java | 3 +
.../apache/ignite/util/SystemViewCommandTest.java | 1191 ++++++++++++++++++++
.../processors/metric/impl/MetricUtils.java | 16 +
.../visor/systemview/VisorSystemViewTask.java | 194 ++++
.../visor/systemview/VisorSystemViewTaskArg.java | 64 ++
.../systemview/VisorSystemViewTaskResult.java | 101 ++
.../main/resources/META-INF/classnames.properties | 5 +
...ridCommandHandlerClusterByClassTest_help.output | 7 +
...andHandlerClusterByClassWithSSLTest_help.output | 7 +
.../systemview/FiltrableSystemViewLocal.java | 3 +-
.../managers/systemview/SystemViewLocal.java | 23 +-
.../cache/metric/SqlViewExporterSpiTest.java | 4 +-
16 files changed, 1865 insertions(+), 24 deletions(-)
diff --git a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/CommandList.java b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/CommandList.java
index b6a221b..4b107da 100644
--- a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/CommandList.java
+++ b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/CommandList.java
@@ -24,6 +24,7 @@ import org.apache.ignite.internal.commandline.meta.MetadataCommand;
import org.apache.ignite.internal.commandline.property.PropertyCommand;
import org.apache.ignite.internal.commandline.query.KillCommand;
import org.apache.ignite.internal.commandline.snapshot.SnapshotCommand;
+import org.apache.ignite.internal.commandline.systemview.SystemViewCommand;
/**
* High-level commands.
@@ -81,7 +82,10 @@ public enum CommandList {
WARM_UP("--warm-up", new WarmUpCommand()),
/** Commands to manage distributed properties. */
- PROPERTY("--property", new PropertyCommand());
+ PROPERTY("--property", new PropertyCommand()),
+
+ /** Command for printing system view content. */
+ SYSTEM_VIEW("--system-view", new SystemViewCommand());
/** Private values copy so there's no need in cloning it every time. */
private static final CommandList[] VALUES = CommandList.values();
diff --git a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/systemview/SystemViewCommand.java b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/systemview/SystemViewCommand.java
new file mode 100644
index 0000000..cd792ea
--- /dev/null
+++ b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/systemview/SystemViewCommand.java
@@ -0,0 +1,218 @@
+/*
+ * 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.commandline.systemview;
+
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.List;
+import java.util.ListIterator;
+import java.util.Map;
+import java.util.UUID;
+import java.util.logging.Logger;
+import java.util.stream.Collectors;
+import org.apache.ignite.internal.client.GridClient;
+import org.apache.ignite.internal.client.GridClientConfiguration;
+import org.apache.ignite.internal.commandline.Command;
+import org.apache.ignite.internal.commandline.CommandArgIterator;
+import org.apache.ignite.internal.commandline.CommandLogger;
+import org.apache.ignite.internal.commandline.argument.CommandArgUtils;
+import org.apache.ignite.internal.visor.systemview.VisorSystemViewTask;
+import org.apache.ignite.internal.visor.systemview.VisorSystemViewTask.SimpleAttributeType;
+import org.apache.ignite.internal.visor.systemview.VisorSystemViewTaskArg;
+import org.apache.ignite.internal.visor.systemview.VisorSystemViewTaskResult;
+import org.apache.ignite.spi.systemview.view.SystemView;
+
+import static java.util.Collections.nCopies;
+import static org.apache.ignite.internal.commandline.CommandList.SYSTEM_VIEW;
+import static org.apache.ignite.internal.commandline.CommandLogger.optional;
+import static org.apache.ignite.internal.commandline.TaskExecutor.executeTaskByNameOnNode;
+import static org.apache.ignite.internal.commandline.systemview.SystemViewCommandArg.NODE_ID;
+import static org.apache.ignite.internal.visor.systemview.VisorSystemViewTask.SimpleAttributeType.DATE;
+import static org.apache.ignite.internal.visor.systemview.VisorSystemViewTask.SimpleAttributeType.NUMBER;
+import static org.apache.ignite.internal.visor.systemview.VisorSystemViewTask.SimpleAttributeType.STRING;
+
+/** Represents command for {@link SystemView} content printing. */
+public class SystemViewCommand implements Command<VisorSystemViewTaskArg> {
+ /** Column separator. */
+ public static final String COLUMN_SEPARATOR = " ";
+
+ /**
+ * Argument for the system view content obtainig task.
+ * @see VisorSystemViewTask
+ */
+ private VisorSystemViewTaskArg taskArg;
+
+ /** ID of the node to get the system view content from. */
+ private UUID nodeId;
+
+ /** {@inheritDoc} */
+ @Override public Object execute(GridClientConfiguration clientCfg, Logger log) throws Exception {
+ try {
+ VisorSystemViewTaskResult res;
+
+ try (GridClient client = Command.startClient(clientCfg)) {
+ res = executeTaskByNameOnNode(
+ client,
+ VisorSystemViewTask.class.getName(),
+ taskArg,
+ nodeId,
+ clientCfg
+ );
+ }
+
+ if (res != null)
+ printSystemViewContent(res, log);
+ else
+ log.info("No system view with specified name was found [name=" + taskArg.systemViewName() + "]");
+
+ return res;
+ }
+ catch (Throwable e) {
+ log.severe("Failed to perform operation.");
+ log.severe(CommandLogger.errorMessage(e));
+
+ throw e;
+ }
+ }
+
+ /**
+ * Prints system view content obtained via {@link VisorSystemViewTask} execution.
+ *
+ * @param taskRes Result of {@link VisorSystemViewTask} execution.
+ * @param log Logger.
+ */
+ private void printSystemViewContent(VisorSystemViewTaskResult taskRes, Logger log) {
+ List<String> titles = taskRes.attributes();
+ List<List<?>> viewRows = taskRes.rows();
+
+ List<Integer> colSzs = titles.stream().map(String::length).collect(Collectors.toList());
+
+ List<List<String>> rows = new ArrayList<>(viewRows.size());
+
+ viewRows.forEach(sysViewRow -> {
+ ListIterator<Integer> colSzIter = colSzs.listIterator();
+
+ rows.add(sysViewRow.stream().map(attr -> {
+ String val = String.valueOf(attr);
+
+ colSzIter.set(Math.max(colSzIter.next(), val.length()));
+
+ return val;
+ }).collect(Collectors.toList()));
+ });
+
+ printRow(titles, nCopies(titles.size(), STRING), colSzs, log);
+
+ rows.forEach(row -> printRow(row, taskRes.types(), colSzs, log));
+ }
+
+ /**
+ * Prints row content with respect to column types and colSzs.
+ *
+ * @param row Row which content should be printed.
+ * @param types Column types in sequential order for decent row formatting.
+ * @param colSzs Column colSzs in sequential order for decent row formatting.
+ * @param log Logger.
+ */
+ private void printRow(
+ Collection<String> row,
+ Collection<SimpleAttributeType> types,
+ Collection<Integer> colSzs,
+ Logger log
+ ) {
+ Iterator<SimpleAttributeType> typeIter = types.iterator();
+ Iterator<Integer> lenIter = colSzs.iterator();
+
+ log.info(row.stream().map(colVal -> {
+ SimpleAttributeType colType = typeIter.next();
+
+ int colLen = lenIter.next();
+
+ String format = colType == DATE || colType == NUMBER ?
+ "%" + colLen + "s" :
+ "%-" + colLen + "s";
+
+ return String.format(format, colVal);
+ }).collect(Collectors.joining(COLUMN_SEPARATOR)));
+ }
+
+ /** {@inheritDoc} */
+ @Override public void parseArguments(CommandArgIterator argIter) {
+ nodeId = null;
+
+ String sysViewName = null;
+
+ while (argIter.hasNextSubArg()) {
+ String arg = argIter.nextArg("Failed to read command argument.");
+
+ SystemViewCommandArg cmdArg = CommandArgUtils.of(arg, SystemViewCommandArg.class);
+
+ if (cmdArg == NODE_ID) {
+ String nodeIdArg = argIter.nextArg(
+ "ID of the node from which system view content should be obtained is expected.");
+
+ try {
+ nodeId = UUID.fromString(nodeIdArg);
+ }
+ catch (IllegalArgumentException e) {
+ throw new IllegalArgumentException("Failed to parse " + NODE_ID + " command argument." +
+ " String representation of \"java.util.UUID\" is exepected. For example:" +
+ " 123e4567-e89b-42d3-a456-556642440000", e);
+ }
+ }
+ else {
+ if (sysViewName != null)
+ throw new IllegalArgumentException("Multiple system view names are not supported.");
+
+ sysViewName = arg;
+ }
+ }
+
+ if (sysViewName == null) {
+ throw new IllegalArgumentException(
+ "The name of the system view for which its content should be printed is expected.");
+ }
+
+ taskArg = new VisorSystemViewTaskArg(sysViewName);
+ }
+
+ /** {@inheritDoc} */
+ @Override public VisorSystemViewTaskArg arg() {
+ return taskArg;
+ }
+
+ /** {@inheritDoc} */
+ @Override public void printUsage(Logger log) {
+ Map<String, String> params = new HashMap<>();
+
+ params.put("node_id", "ID of the node to get the system view from. If not set, random node will be chosen.");
+ params.put("system_view_name", "Name of the system view which content should be printed." +
+ " Both \"SQL\" and \"Java\" styles of system view name are supported" +
+ " (e.g. SQL_TABLES and sql.tables will be handled similarly).");
+
+ Command.usage(log, "Print system view content:", SYSTEM_VIEW, params, optional(NODE_ID, "node_id"),
+ "system_view_name");
+ }
+
+ /** {@inheritDoc} */
+ @Override public String name() {
+ return SYSTEM_VIEW.toCommandName();
+ }
+}
diff --git a/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/systemview/SystemViewCommandArg.java b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/systemview/SystemViewCommandArg.java
new file mode 100644
index 0000000..1462eed
--- /dev/null
+++ b/modules/control-utility/src/main/java/org/apache/ignite/internal/commandline/systemview/SystemViewCommandArg.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.commandline.systemview;
+
+import org.apache.ignite.internal.commandline.argument.CommandArg;
+
+/** Represents all possible arguments for {@link SystemViewCommand}. */
+public enum SystemViewCommandArg implements CommandArg {
+ /** Id of the node to get the system view from. */
+ NODE_ID("--node-id");
+
+ /** Name of the argument. */
+ private final String name;
+
+ /** @param name Name of the argument. */
+ SystemViewCommandArg(String name) {
+ this.name = name;
+ }
+
+ /** {@inheritDoc} */
+ @Override public String argName() {
+ return name;
+ }
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return name;
+ }
+}
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 2dade20..97d549a 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
@@ -1031,6 +1031,7 @@ public class CommandHandlerParsingTest {
cmd == CommandList.CLUSTER_CHANGE_TAG ||
cmd == CommandList.METADATA ||
cmd == CommandList.WARM_UP ||
- cmd == CommandList.PROPERTY;
+ cmd == CommandList.PROPERTY ||
+ cmd == CommandList.SYSTEM_VIEW;
}
}
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 f4e8df4..3d8daa2 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
@@ -40,6 +40,7 @@ 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.apache.ignite.util.SystemViewCommandTest;
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
@@ -79,6 +80,8 @@ import org.junit.runners.Suite;
GridCommandHandlerTracingConfigurationTest.class,
GridCommandHandlerPropertiesTest.class,
+
+ SystemViewCommandTest.class
})
public class IgniteControlUtilityTestSuite {
}
diff --git a/modules/control-utility/src/test/java/org/apache/ignite/util/SystemViewCommandTest.java b/modules/control-utility/src/test/java/org/apache/ignite/util/SystemViewCommandTest.java
new file mode 100644
index 0000000..a67ca87
--- /dev/null
+++ b/modules/control-utility/src/test/java/org/apache/ignite/util/SystemViewCommandTest.java
@@ -0,0 +1,1191 @@
+/*
+ * 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.util;
+
+import java.lang.reflect.Field;
+import java.sql.Connection;
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Objects;
+import java.util.Properties;
+import java.util.Set;
+import java.util.UUID;
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.atomic.AtomicInteger;
+import java.util.function.Consumer;
+import java.util.stream.Collectors;
+import org.apache.ignite.Ignite;
+import org.apache.ignite.IgniteCache;
+import org.apache.ignite.IgniteJdbcThinDriver;
+import org.apache.ignite.Ignition;
+import org.apache.ignite.cache.CacheMode;
+import org.apache.ignite.cache.affinity.rendezvous.RendezvousAffinityFunction;
+import org.apache.ignite.cache.query.ContinuousQuery;
+import org.apache.ignite.cache.query.QueryCursor;
+import org.apache.ignite.cache.query.ScanQuery;
+import org.apache.ignite.cache.query.SqlFieldsQuery;
+import org.apache.ignite.client.IgniteClient;
+import org.apache.ignite.configuration.CacheConfiguration;
+import org.apache.ignite.configuration.ClientConfiguration;
+import org.apache.ignite.configuration.DataRegionConfiguration;
+import org.apache.ignite.configuration.DataStorageConfiguration;
+import org.apache.ignite.configuration.IgniteConfiguration;
+import org.apache.ignite.configuration.SqlConfiguration;
+import org.apache.ignite.internal.IgniteEx;
+import org.apache.ignite.internal.binary.mutabletest.GridBinaryTestClasses.TestObjectAllTypes;
+import org.apache.ignite.internal.binary.mutabletest.GridBinaryTestClasses.TestObjectEnum;
+import org.apache.ignite.internal.commandline.CommandList;
+import org.apache.ignite.internal.commandline.systemview.SystemViewCommandArg;
+import org.apache.ignite.internal.metric.SystemViewSelfTest.TestPredicate;
+import org.apache.ignite.internal.metric.SystemViewSelfTest.TestRunnable;
+import org.apache.ignite.internal.metric.SystemViewSelfTest.TestTransformer;
+import org.apache.ignite.internal.processors.affinity.AffinityTopologyVersion;
+import org.apache.ignite.internal.processors.cache.distributed.dht.topology.GridDhtPartitionState;
+import org.apache.ignite.internal.processors.cache.metric.SqlViewExporterSpiTest.TestAffinityFunction;
+import org.apache.ignite.internal.processors.cache.persistence.GridCacheDatabaseSharedManager;
+import org.apache.ignite.internal.processors.cache.persistence.IgniteCacheDatabaseSharedManager;
+import org.apache.ignite.internal.processors.metastorage.DistributedMetaStorage;
+import org.apache.ignite.internal.processors.service.DummyService;
+import org.apache.ignite.internal.util.StripedExecutor;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.internal.visor.systemview.VisorSystemViewTask;
+import org.apache.ignite.services.ServiceConfiguration;
+import org.apache.ignite.spi.systemview.view.SystemView;
+import org.apache.ignite.spi.systemview.view.SystemViewRowAttributeWalker.AttributeVisitor;
+import org.apache.ignite.testframework.GridTestUtils;
+import org.apache.ignite.transactions.Transaction;
+import org.junit.Test;
+
+import static java.lang.Integer.MAX_VALUE;
+import static java.util.Arrays.asList;
+import static java.util.concurrent.TimeUnit.MILLISECONDS;
+import static java.util.regex.Pattern.quote;
+import static org.apache.ignite.cache.CacheAtomicityMode.TRANSACTIONAL;
+import static org.apache.ignite.cluster.ClusterState.ACTIVE;
+import static org.apache.ignite.cluster.ClusterState.INACTIVE;
+import static org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_INVALID_ARGUMENTS;
+import static org.apache.ignite.internal.commandline.CommandHandler.EXIT_CODE_OK;
+import static org.apache.ignite.internal.commandline.CommandList.SYSTEM_VIEW;
+import static org.apache.ignite.internal.commandline.systemview.SystemViewCommand.COLUMN_SEPARATOR;
+import static org.apache.ignite.internal.commandline.systemview.SystemViewCommandArg.NODE_ID;
+import static org.apache.ignite.internal.managers.systemview.GridSystemViewManager.STREAM_POOL_QUEUE_VIEW;
+import static org.apache.ignite.internal.managers.systemview.GridSystemViewManager.SYS_POOL_QUEUE_VIEW;
+import static org.apache.ignite.internal.managers.systemview.ScanQuerySystemView.SCAN_QRY_SYS_VIEW;
+import static org.apache.ignite.internal.metric.SystemViewSelfTest.TEST_PREDICATE;
+import static org.apache.ignite.internal.metric.SystemViewSelfTest.TEST_TRANSFORMER;
+import static org.apache.ignite.internal.processors.cache.ClusterCachesInfo.CACHES_VIEW;
+import static org.apache.ignite.internal.processors.cache.ClusterCachesInfo.CACHE_GRPS_VIEW;
+import static org.apache.ignite.internal.processors.cache.GridCacheProcessor.CACHE_GRP_PAGE_LIST_VIEW;
+import static org.apache.ignite.internal.processors.cache.GridCacheProcessor.PART_STATES_VIEW;
+import static org.apache.ignite.internal.processors.cache.GridCacheUtils.cacheGroupId;
+import static org.apache.ignite.internal.processors.cache.GridCacheUtils.cacheId;
+import static org.apache.ignite.internal.processors.cache.binary.CacheObjectBinaryProcessorImpl.BINARY_METADATA_VIEW;
+import static org.apache.ignite.internal.processors.cache.index.AbstractSchemaSelfTest.queryProcessor;
+import static org.apache.ignite.internal.processors.cache.persistence.GridCacheDatabaseSharedManager.METASTORE_VIEW;
+import static org.apache.ignite.internal.processors.cache.persistence.IgniteCacheDatabaseSharedManager.DATA_REGION_PAGE_LIST_VIEW;
+import static org.apache.ignite.internal.processors.cache.transactions.IgniteTxManager.TXS_MON_LIST;
+import static org.apache.ignite.internal.processors.continuous.GridContinuousProcessor.CQ_SYS_VIEW;
+import static org.apache.ignite.internal.processors.metastorage.persistence.DistributedMetaStorageImpl.DISTRIBUTED_METASTORE_VIEW;
+import static org.apache.ignite.internal.processors.metric.impl.MetricUtils.toSqlName;
+import static org.apache.ignite.internal.processors.odbc.ClientListenerProcessor.CLI_CONN_VIEW;
+import static org.apache.ignite.internal.processors.query.QueryUtils.DFLT_SCHEMA;
+import static org.apache.ignite.internal.processors.query.QueryUtils.SCHEMA_SYS;
+import static org.apache.ignite.internal.processors.query.h2.SchemaManager.SQL_SCHEMA_VIEW;
+import static org.apache.ignite.internal.processors.query.h2.SchemaManager.SQL_TBLS_VIEW;
+import static org.apache.ignite.internal.processors.query.h2.SchemaManager.SQL_TBL_COLS_VIEW;
+import static org.apache.ignite.internal.processors.query.h2.SchemaManager.SQL_VIEWS_VIEW;
+import static org.apache.ignite.internal.processors.query.h2.SchemaManager.SQL_VIEW_COLS_VIEW;
+import static org.apache.ignite.internal.processors.service.IgniteServiceProcessor.SVCS_VIEW;
+import static org.apache.ignite.internal.processors.task.GridTaskProcessor.TASKS_VIEW;
+import static org.apache.ignite.internal.util.IgniteUtils.toStringSafe;
+import static org.apache.ignite.testframework.GridTestUtils.assertContains;
+import static org.apache.ignite.testframework.GridTestUtils.waitForCondition;
+import static org.apache.ignite.transactions.TransactionConcurrency.OPTIMISTIC;
+import static org.apache.ignite.transactions.TransactionConcurrency.PESSIMISTIC;
+import static org.apache.ignite.transactions.TransactionIsolation.REPEATABLE_READ;
+import static org.apache.ignite.transactions.TransactionIsolation.SERIALIZABLE;
+
+/** Tests output of {@link CommandList#SYSTEM_VIEW} command. */
+public class SystemViewCommandTest extends GridCommandHandlerClusterByClassAbstractTest {
+ /** Command line argument for printing content of a system view. */
+ private static final String CMD_SYS_VIEW = SYSTEM_VIEW.text();
+
+ /** Latch that is used to unblock all compute jobs. */
+ private static final CountDownLatch COMPUTE_JOB_UNBLOCK_LATCH = new CountDownLatch(1);
+
+ /** Latch that indicates number of compute jobs to be blocked.*/
+ private static final CountDownLatch COMPUTE_JOB_BLOCK_LATCH = new CountDownLatch(5);
+
+ /** Name of the test data region. */
+ private static final String DATA_REGION_NAME = "in-memory";
+
+ /** Test node with 0 index. */
+ private IgniteEx ignite0;
+
+ /** Test node with 1 index. */
+ private IgniteEx ignite1;
+
+ /** {@inheritDoc} */
+ @Override protected IgniteConfiguration getConfiguration(String igniteInstanceName) throws Exception {
+ IgniteConfiguration cfg = super.getConfiguration(igniteInstanceName);
+
+ cfg.setDataStorageConfiguration(new DataStorageConfiguration()
+ .setDataRegionConfigurations(new DataRegionConfiguration()
+ .setName(DATA_REGION_NAME)
+ .setMaxSize(100L * 1024 * 1024))
+ .setDefaultDataRegionConfiguration(new DataRegionConfiguration()
+ .setPersistenceEnabled(true)));
+
+ return cfg;
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void beforeTest() throws Exception {
+ super.beforeTest();
+
+ injectTestSystemOut();
+
+ autoConfirmation = false;
+
+ ignite0 = ignite(0);
+ ignite1 = ignite(1);
+ }
+
+ /** Tests command error output in case of mandatory system view name is omitted. */
+ @Test
+ public void testSystemViewNameMissedFailure() {
+ assertContains(log, executeCommand(EXIT_CODE_INVALID_ARGUMENTS, CMD_SYS_VIEW),
+ "The name of the system view for which its content should be printed is expected.");
+ }
+
+ /** Tests command error output in case value of {@link SystemViewCommandArg#NODE_ID} argument is omitted. */
+ @Test
+ public void testNodeIdMissedFailure() {
+ assertContains(log, executeCommand(EXIT_CODE_INVALID_ARGUMENTS, CMD_SYS_VIEW, SVCS_VIEW, NODE_ID.argName()),
+ "ID of the node from which system view content should be obtained is expected.");
+ }
+
+ /** Tests command error output in case value of {@link SystemViewCommandArg#NODE_ID} argument is invalid.*/
+ @Test
+ public void testInvalidNodeIdFailure() {
+ assertContains(log,
+ executeCommand(EXIT_CODE_INVALID_ARGUMENTS, CMD_SYS_VIEW, SVCS_VIEW, NODE_ID.argName(), "invalid_node_id"),
+ "Failed to parse " + NODE_ID.argName() +
+ " command argument. String representation of \"java.util.UUID\" is exepected." +
+ " For example: 123e4567-e89b-42d3-a456-556642440000"
+ );
+ }
+
+ /** Tests command error output in case multiple system view names are specified. */
+ @Test
+ public void testMultipleSystemViewNamesFailure() {
+ assertContains(log,
+ executeCommand(EXIT_CODE_INVALID_ARGUMENTS, CMD_SYS_VIEW, SVCS_VIEW, CACHE_GRP_PAGE_LIST_VIEW),
+ "Multiple system view names are not supported.");
+ }
+
+ /**
+ * Tests command error output in case {@link SystemViewCommandArg#NODE_ID} argument value refers to nonexistent
+ * node.
+ */
+ @Test
+ public void testNonExistentNodeIdFailure() {
+ String incorrectNodeId = UUID.randomUUID().toString();
+
+ assertContains(log,
+ executeCommand(EXIT_CODE_INVALID_ARGUMENTS, CMD_SYS_VIEW, "--node-id", incorrectNodeId, CACHES_VIEW),
+ "Failed to perform operation.\nNode with id=" + incorrectNodeId + " not found");
+ }
+
+ /** Tests command output in case nonexistent system view names is specified. */
+ @Test
+ public void testNonExistentSystemView() {
+ assertContains(log, executeCommand(EXIT_CODE_OK, CMD_SYS_VIEW, "non_existent_system_view"),
+ "No system view with specified name was found [name=non_existent_system_view]");
+ }
+
+ /** */
+ @Test
+ public void testCachesView() {
+ Set<String> cacheNames = new HashSet<>(asList("cache-1", "cache-2"));
+
+ cacheNames.forEach(cacheName -> ignite0.createCache(cacheName));
+
+ List<List<String>> cachesView = systemView(ignite0, CACHES_VIEW);
+
+ assertEquals(ignite0.context().cache().cacheDescriptors().size(), cachesView.size());
+
+ cachesView.forEach(row -> cacheNames.remove(row.get(0)));
+
+ assertTrue(cacheNames.isEmpty());
+ }
+
+ /** */
+ @Test
+ public void testCacheGroupsView() {
+ Set<String> grpNames = new HashSet<>(asList("grp-1", "grp-2"));
+
+ for (String grpName : grpNames)
+ ignite0.createCache(new CacheConfiguration<>("cache-" + grpName).setGroupName(grpName));
+
+ List<List<String>> cacheGrpsView = systemView(ignite0, CACHE_GRPS_VIEW);
+
+ assertEquals(ignite0.context().cache().cacheGroupDescriptors().size(), cacheGrpsView.size());
+
+ cacheGrpsView.forEach(row -> grpNames.remove(row.get(0)));
+
+ assertTrue(grpNames.toString(), grpNames.isEmpty());
+ }
+
+ /** */
+ @Test
+ public void testComputeBroadcast() throws Exception {
+ long tasksCnt = COMPUTE_JOB_BLOCK_LATCH.getCount();
+
+ try {
+ for (int i = 0; i < tasksCnt; i++) {
+ ignite0.compute().broadcastAsync(() -> {
+ try {
+ COMPUTE_JOB_BLOCK_LATCH.countDown();
+ COMPUTE_JOB_UNBLOCK_LATCH.await();
+ }
+ catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ });
+ }
+
+ COMPUTE_JOB_BLOCK_LATCH.await();
+
+ List<List<String>> tasksView = systemView(ignite0, TASKS_VIEW).stream()
+ .filter(row -> !VisorSystemViewTask.class.getName().equals(row.get(3)))
+ .collect(Collectors.toList());
+
+ assertEquals(tasksCnt, tasksView.size());
+
+ tasksView.forEach(row -> {
+ assertEquals("false", row.get(10)); //internal
+ assertEquals("null", row.get(6)); // affinityCacheName
+ assertEquals("-1", row.get(5)); // affinityPartitionId
+ assertTrue(row.get(4).startsWith(getClass().getName())); // taskClassName
+ assertTrue(row.get(3).startsWith(getClass().getName())); // taskName
+ assertEquals(ignite0.localNode().id().toString(), row.get(2)); // taskNodeId
+ assertEquals("0", row.get(12)); // userVersion
+ });
+ }
+ finally {
+ COMPUTE_JOB_UNBLOCK_LATCH.countDown();
+ }
+ }
+
+ /** */
+ @Test
+ public void testServices() {
+ ServiceConfiguration srvcCfg = new ServiceConfiguration();
+
+ srvcCfg.setName("service");
+ srvcCfg.setMaxPerNodeCount(1);
+ srvcCfg.setService(new DummyService());
+
+ ignite0.services().deploy(srvcCfg);
+
+ List<List<String>> srvsView = systemView(ignite0, SVCS_VIEW);
+
+ assertEquals(1, srvsView.size());
+
+ List<String> sysView = srvsView.get(0);
+
+ assertEquals(srvcCfg.getName(), sysView.get(1)); // name
+ assertEquals(DummyService.class.getName(), sysView.get(2)); // serviceClass
+ assertEquals(Integer.toString(srvcCfg.getMaxPerNodeCount()), sysView.get(6)); // maxPerNodeCount
+ }
+
+ /** */
+ @Test
+ public void testClientsConnections() throws Exception {
+ String host = ignite0.configuration().getClientConnectorConfiguration().getHost();
+
+ if (host == null)
+ host = ignite0.configuration().getLocalHost();
+
+ int port = ignite0.configuration().getClientConnectorConfiguration().getPort();
+
+ try (
+ IgniteClient ignored1 = Ignition.startClient(new ClientConfiguration().setAddresses(host + ":" + port));
+ Connection ignored2 = new IgniteJdbcThinDriver().connect("jdbc:ignite:thin://" + host, new Properties())
+ ) {
+ assertEquals(2, systemView(ignite0, CLI_CONN_VIEW).size());
+ }
+ }
+
+ /** */
+ @Test
+ public void testTransactions() throws Exception {
+ IgniteCache<Integer, Integer> cache = ignite0.createCache(
+ new CacheConfiguration<Integer, Integer>("test-cache").setAtomicityMode(TRANSACTIONAL));
+
+ assertTrue(systemView(ignite0, TXS_MON_LIST).isEmpty());
+
+ CountDownLatch txBlockLatch = new CountDownLatch(10);
+ CountDownLatch txUnblockLatch = new CountDownLatch(1);
+
+ try {
+ AtomicInteger cntr = new AtomicInteger();
+
+ GridTestUtils.runMultiThreadedAsync(() -> {
+ try (
+ Transaction ignored = ignite0.transactions().withLabel("test")
+ .txStart(PESSIMISTIC, REPEATABLE_READ)
+ ) {
+ cache.put(cntr.incrementAndGet(), cntr.incrementAndGet());
+ cache.put(cntr.incrementAndGet(), cntr.incrementAndGet());
+
+ txBlockLatch.countDown();
+ txUnblockLatch.await();
+ }
+ catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }, 5, "sys-view-cmd-tx-test-1");
+
+ GridTestUtils.runMultiThreadedAsync(() -> {
+ try (Transaction ignored = ignite0.transactions().txStart(OPTIMISTIC, SERIALIZABLE)) {
+ cache.put(cntr.incrementAndGet(), cntr.incrementAndGet());
+ cache.put(cntr.incrementAndGet(), cntr.incrementAndGet());
+
+ txBlockLatch.countDown();
+ txUnblockLatch.await();
+ }
+ catch (InterruptedException e) {
+ throw new RuntimeException(e);
+ }
+ }, 5, "sys-view-cmd-tx-test-2");
+
+ txBlockLatch.await(getTestTimeout(), MILLISECONDS);
+
+ List<List<String>> txsView = systemView(ignite0, TXS_MON_LIST);
+
+ assertEquals(10, txsView.size());
+ }
+ finally {
+ txUnblockLatch.countDown();
+ }
+
+ assertTrue(waitForCondition(() -> systemView(ignite0, TXS_MON_LIST).isEmpty(), getTestTimeout()));
+ }
+
+ /** */
+ @Test
+ public void testSchemas() throws Exception {
+ try (
+ IgniteEx g = startGrid(getConfiguration(getTestIgniteInstanceName(3))
+ .setSqlConfiguration(new SqlConfiguration().setSqlSchemas("MY_SCHEMA", "ANOTHER_SCHEMA")))
+ ) {
+ Set<String> schemaNames = new HashSet<>();
+
+ HashSet<String> expSchemas = new HashSet<>(asList("MY_SCHEMA", "ANOTHER_SCHEMA", "SYS", "PUBLIC"));
+
+ List<List<String>> sqlSchemaView = systemView(g, SQL_SCHEMA_VIEW);
+
+ sqlSchemaView.forEach(row -> schemaNames.add(row.get(0))); // name
+
+ assertEquals(schemaNames, expSchemas);
+ }
+ }
+
+ /** */
+ @Test
+ public void testViews() {
+ Set<String> expViewNames = new HashSet<>(asList(
+ "METRICS",
+ "VIEWS",
+ "SERVICES",
+ "CACHE_GROUPS",
+ "CACHES",
+ "TASKS",
+ "JOBS",
+ "SQL_QUERIES_HISTORY",
+ "NODES",
+ "SCHEMAS",
+ "NODE_METRICS",
+ "BASELINE_NODES",
+ "INDEXES",
+ "LOCAL_CACHE_GROUPS_IO",
+ "SQL_QUERIES",
+ "SCAN_QUERIES",
+ "NODE_ATTRIBUTES",
+ "TABLES",
+ "CLIENT_CONNECTIONS",
+ "TABLE_COLUMNS",
+ "VIEW_COLUMNS",
+ "TRANSACTIONS",
+ "CONTINUOUS_QUERIES",
+ "STRIPED_THREADPOOL_QUEUE",
+ "DATASTREAM_THREADPOOL_QUEUE",
+ "DATA_REGION_PAGE_LISTS",
+ "CACHE_GROUP_PAGE_LISTS",
+ "PARTITION_STATES",
+ "BINARY_METADATA",
+ "METASTORAGE",
+ "DISTRIBUTED_METASTORAGE"
+ ));
+
+ Set<String> viewNames = new HashSet<>();
+
+ List<List<String>> sqlViewsView = systemView(ignite0, SQL_VIEWS_VIEW);
+
+ sqlViewsView.forEach(row -> viewNames.add(row.get(0))); // name
+
+ assertEquals(expViewNames, viewNames);
+ }
+
+ /** */
+ @Test
+ public void testTable() {
+ assertTrue(systemView(ignite0, SQL_TBLS_VIEW).isEmpty());
+
+ executeSql(ignite0, "CREATE TABLE T1(ID LONG PRIMARY KEY, NAME VARCHAR)");
+
+ List<List<String>> sqlTablesView = systemView(ignite0, SQL_TBLS_VIEW);
+
+ assertEquals(1, sqlTablesView.size());
+
+ List<String> row = sqlTablesView.get(0);
+
+ assertEquals("T1", row.get(0)); // TABLE_NAME
+ assertEquals(DFLT_SCHEMA, row.get(1)); // SCHEMA_NAME
+ assertEquals("SQL_PUBLIC_T1", row.get(2)); // CACHE_NAME
+ assertEquals(Integer.toString(cacheId("SQL_PUBLIC_T1")), row.get(3)); // CACHE_ID
+ assertEquals("null", row.get(4)); // AFFINITY_KEY_COLUMN
+ assertEquals("ID", row.get(5)); // KEY_ALIAS
+ assertEquals("null", row.get(6)); // VALUE_ALIAS
+ assertEquals("java.lang.Long", row.get(7)); // KEY_TYPE_NAME
+ assertFalse("null".equals(row.get(8))); // VALUE_TYPE_NAME
+
+ executeSql(ignite0, "CREATE TABLE T2(ID LONG PRIMARY KEY, NAME VARCHAR)");
+
+ assertEquals(2, systemView(ignite0, SQL_TBLS_VIEW).size());
+
+ executeSql(ignite0, "DROP TABLE T1");
+ executeSql(ignite0, "DROP TABLE T2");
+
+ assertTrue(systemView(ignite0, SQL_TBLS_VIEW).isEmpty());
+ }
+
+ /** */
+ @Test
+ public void testTableColumns() {
+ assertTrue(systemView(ignite0, SQL_TBL_COLS_VIEW).isEmpty());
+
+ executeSql(ignite0, "CREATE TABLE T1(ID LONG PRIMARY KEY, NAME VARCHAR(40))");
+
+ Set<?> actCols = systemView(ignite0, SQL_TBL_COLS_VIEW).stream()
+ .map(row -> row.get(0)) // columnName
+ .collect(Collectors.toSet());
+
+ assertEquals(new HashSet<>(asList("ID", "NAME", "_KEY", "_VAL")), actCols);
+
+ executeSql(ignite0, "CREATE TABLE T2(ID LONG PRIMARY KEY, NAME VARCHAR(50))");
+
+ Set<List<String>> expSqlTableColumnsView = new HashSet<>(asList(
+ asList("ID", "T1", "PUBLIC", "false", "false", "null", "true", "true", "-1", "-1", Long.class.getName()),
+ asList("NAME", "T1", "PUBLIC", "false", "false", "null", "true", "false", "40", "-1", String.class.getName()),
+ asList("_KEY", "T1", "PUBLIC", "true", "false", "null", "false", "true", "-1", "-1", "null"),
+ asList("_VAL", "T1", "PUBLIC", "false", "false", "null", "true", "false", "-1", "-1", "null"),
+ asList("ID", "T2", "PUBLIC", "false", "false", "null", "true", "true", "-1", "-1", Long.class.getName()),
+ asList("NAME", "T2", "PUBLIC", "false", "false", "null", "true", "false", "50", "-1", String.class.getName()),
+ asList("_KEY", "T2", "PUBLIC", "true", "false", "null", "false", "true", "-1", "-1", "null"),
+ asList("_VAL", "T2", "PUBLIC", "false", "false", "null", "true", "false", "-1", "-1", "null")
+ ));
+
+ Set<List<String>> sqlTableColumnsView = new HashSet<>(systemView(ignite0, SQL_TBL_COLS_VIEW));
+
+ assertEquals(expSqlTableColumnsView, sqlTableColumnsView);
+
+ executeSql(ignite0, "DROP TABLE T1");
+ executeSql(ignite0, "DROP TABLE T2");
+
+ assertTrue(systemView(ignite0, SQL_TBL_COLS_VIEW).isEmpty());
+ }
+
+ /** */
+ @Test
+ public void testViewColumns() {
+ Set<List<String>> expsqlViewColumnsView = new HashSet<>(asList(
+ asList("CONNECTION_ID", "CLIENT_CONNECTIONS", SCHEMA_SYS, "null", "true", "19", "0", Long.class.getName()),
+ asList("LOCAL_ADDRESS", "CLIENT_CONNECTIONS", SCHEMA_SYS, "null", "true", Integer.toString(MAX_VALUE), "0",
+ String.class.getName()),
+ asList("REMOTE_ADDRESS", "CLIENT_CONNECTIONS", SCHEMA_SYS, "null", "true", Integer.toString(MAX_VALUE), "0",
+ String.class.getName()),
+ asList("TYPE", "CLIENT_CONNECTIONS", SCHEMA_SYS, "null", "true", Integer.toString(MAX_VALUE), "0",
+ String.class.getName()),
+ asList("USER", "CLIENT_CONNECTIONS", SCHEMA_SYS, "null", "true", Integer.toString(MAX_VALUE), "0",
+ String.class.getName()),
+ asList("VERSION", "CLIENT_CONNECTIONS", SCHEMA_SYS, "null", "true", Integer.toString(MAX_VALUE), "0",
+ String.class.getName())
+ ));
+
+ Set<List<String>> sqlViewColumnsView = systemView(ignite0, SQL_VIEW_COLS_VIEW).stream()
+ .filter(row -> "CLIENT_CONNECTIONS".equals(row.get(1))) // viewName
+ .collect(Collectors.toSet());
+
+ assertEquals(expsqlViewColumnsView, sqlViewColumnsView);
+ }
+
+ /** */
+ @Test
+ public void testContinuousQuery() throws Exception {
+ IgniteCache<Integer, Integer> cache = ignite0.createCache("test-cache");
+
+ assertTrue(systemView(ignite0, CQ_SYS_VIEW).isEmpty());
+ assertTrue(systemView(ignite1, CQ_SYS_VIEW).isEmpty());
+
+ try (QueryCursor<?> ignored = cache.query(new ContinuousQuery<>()
+ .setInitialQuery(new ScanQuery<>())
+ .setPageSize(100)
+ .setTimeInterval(1000)
+ .setLocalListener(evts -> {
+ // No-op.
+ })
+ .setRemoteFilterFactory(() -> evt -> true)
+ )) {
+ for (int i = 0; i < 100; i++)
+ cache.put(i, i);
+
+ checkContinuouQueryView(ignite0, true);
+ checkContinuouQueryView(ignite1, false);
+ }
+
+ assertTrue(systemView(ignite0, CQ_SYS_VIEW).isEmpty());
+ assertTrue(waitForCondition(() -> systemView(ignite1, CQ_SYS_VIEW).isEmpty(), getTestTimeout()));
+ }
+
+ /** */
+ private void checkContinuouQueryView(IgniteEx node, boolean loc) {
+ List<List<String>> cqSysView = systemView(node, CQ_SYS_VIEW);
+
+ assertEquals(1, cqSysView.size());
+
+ List<String> row = cqSysView.get(0);
+
+ assertEquals("test-cache", row.get(0)); //cacheName
+ assertEquals("100", row.get(7)); // bufferSize
+ assertEquals("1000", row.get(9)); // interval
+ assertEquals(ignite0.localNode().id().toString(), row.get(14)); // nodeId
+
+ if (loc)
+ assertTrue(row.get(1).startsWith(getClass().getName())); // localListener
+ else
+ assertEquals("null", row.get(1)); // localListener
+
+ assertTrue(row.get(2).startsWith(getClass().getName())); // remoteFilter
+ assertEquals("null", row.get(4)); // localTransformedListener
+ assertEquals("null", row.get(3)); // remoteTransformer
+ }
+
+ /** */
+ @Test
+ public void testLocalScanQuery() throws Exception {
+ IgniteCache<Integer, Integer> cache1 = ignite0.createCache(
+ new CacheConfiguration<Integer, Integer>("cache1").setGroupName("group1"));
+
+ int part = ignite0.affinity("cache1").primaryPartitions(ignite0.localNode())[0];
+
+ List<Integer> partKeys = partitionKeys(cache1, part, 11, 0);
+
+ partKeys.forEach(key -> cache1.put(key, key));
+
+ assertTrue(systemView(ignite0, SCAN_QRY_SYS_VIEW).isEmpty());
+
+ try (
+ QueryCursor<Integer> qryRes1 = cache1.query(
+ new ScanQuery<Integer, Integer>()
+ .setFilter(new TestPredicate())
+ .setLocal(true)
+ .setPartition(part)
+ .setPageSize(10),
+ new TestTransformer())
+ ) {
+ assertTrue(qryRes1.iterator().hasNext());
+
+ assertTrue(waitForCondition(() -> !systemView(ignite0, SCAN_QRY_SYS_VIEW).isEmpty(), getTestTimeout()));
+
+ List<String> view = systemView(ignite0, SCAN_QRY_SYS_VIEW).get(0);
+
+ assertEquals(ignite0.localNode().id().toString(), view.get(0)); // originNodeId
+ assertEquals("0", view.get(1)); // queryId
+ assertEquals("cache1", view.get(2)); // cacheName
+ assertEquals(Integer.toString(cacheId("cache1")), view.get(3)); // cacheId
+ assertEquals(Integer.toString(cacheGroupId("cache1", "group1")), view.get(4)); // cacheGroupId
+ assertEquals("group1", view.get(5)); // cacheGroupName
+ assertTrue(Long.parseLong(view.get(6)) <= System.currentTimeMillis()); // startTime
+ assertTrue(Long.parseLong(view.get(7)) >= 0); // duration
+ assertFalse(Boolean.parseBoolean(view.get(8))); // canceled
+ assertEquals(TEST_PREDICATE, view.get(9)); // filter
+ assertTrue(Boolean.parseBoolean(view.get(11))); // local
+ assertEquals(part, Integer.parseInt(view.get(13))); // partition
+ assertEquals(toStringSafe(ignite0.context().discovery().topologyVersionEx()), view.get(16)); // topology
+ assertEquals(TEST_TRANSFORMER, view.get(17)); // transformer
+ assertFalse(Boolean.parseBoolean(view.get(10))); // keepBinary
+ assertEquals("null", view.get(14)); // subjectId
+ assertEquals("null", view.get(15)); // taskName
+ }
+
+ assertTrue(waitForCondition(() -> systemView(ignite0, SCAN_QRY_SYS_VIEW).isEmpty(), getTestTimeout()));
+ }
+
+ /** */
+ @Test
+ public void testScanQuery() throws Exception {
+ try (
+ IgniteEx client1 = startClientGrid("client-1");
+ IgniteEx client2 = startClientGrid("client-2")
+ ) {
+ IgniteCache<Integer, Integer> cache1 = client1.createCache(
+ new CacheConfiguration<Integer, Integer>("cache1").setGroupName("group1"));
+
+ IgniteCache<Integer, Integer> cache2 = client2.createCache("cache2");
+
+ for (int i = 0; i < 100; i++) {
+ cache1.put(i, i);
+ cache2.put(i, i);
+ }
+
+ assertTrue(systemView(ignite0, SCAN_QRY_SYS_VIEW).isEmpty());
+ assertTrue(systemView(ignite1, SCAN_QRY_SYS_VIEW).isEmpty());
+
+ try (
+ QueryCursor<Integer> qryRes1 = cache1.query(
+ new ScanQuery<Integer, Integer>()
+ .setFilter(new TestPredicate())
+ .setPageSize(10),
+ new TestTransformer());
+
+ QueryCursor<?> qryRes2 = cache2.withKeepBinary().query(new ScanQuery<>().setPageSize(20))
+ ) {
+ assertTrue(qryRes1.iterator().hasNext());
+ assertTrue(qryRes2.iterator().hasNext());
+
+ checkScanQueryView(client1, client2, ignite0);
+ checkScanQueryView(client1, client2, ignite1);
+ }
+
+ assertTrue(waitForCondition(() ->
+ systemView(ignite0, SCAN_QRY_SYS_VIEW).isEmpty() && systemView(ignite1, SCAN_QRY_SYS_VIEW).isEmpty(),
+ getTestTimeout()));
+ }
+ }
+
+ /** */
+ private void checkScanQueryView(IgniteEx client1, IgniteEx client2, IgniteEx node) throws Exception {
+ assertTrue(waitForCondition(() -> systemView(ignite0, SCAN_QRY_SYS_VIEW).size() > 1, getTestTimeout()));
+
+ Consumer<List<String>> cache1checker = view -> {
+ assertEquals(client1.localNode().id().toString(), view.get(0));
+ assertTrue(Long.parseLong(view.get(1)) != 0);
+ assertEquals("cache1", view.get(2));
+ assertEquals(Integer.toString(cacheId("cache1")), view.get(3));
+ assertEquals(Integer.toString(cacheGroupId("cache1", "group1")), view.get(4));
+ assertEquals("group1", view.get(5));
+ assertTrue(Long.parseLong(view.get(6)) <= System.currentTimeMillis());
+ assertTrue(Long.parseLong(view.get(7)) >= 0);
+ assertFalse(Boolean.parseBoolean(view.get(8)));
+ assertEquals(TEST_PREDICATE, view.get(9));
+ assertFalse(Boolean.parseBoolean(view.get(11)));
+ assertEquals("-1", view.get(13));
+ assertEquals(toStringSafe(client1.context().discovery().topologyVersionEx()), view.get(16));
+ assertEquals(TEST_TRANSFORMER, view.get(17));
+ assertFalse(Boolean.parseBoolean(view.get(10)));
+ assertEquals("null", view.get(14));
+ assertEquals("null", view.get(15));
+ assertEquals("10", view.get(12));
+ };
+
+ Consumer<List<String>> cache2checker = view -> {
+ assertEquals(client2.localNode().id().toString(), view.get(0));
+ assertTrue(Long.parseLong(view.get(1)) != 0);
+ assertEquals("cache2", view.get(2));
+ assertEquals(Integer.toString(cacheId("cache2")), view.get(3));
+ assertEquals(Integer.toString(cacheGroupId("cache2", null)), view.get(4));
+ assertEquals("cache2", view.get(5));
+ assertTrue(Long.parseLong(view.get(6)) <= System.currentTimeMillis());
+ assertTrue(Long.parseLong(view.get(7)) >= 0);
+ assertFalse(Boolean.parseBoolean(view.get(8)));
+ assertEquals("null", view.get(9));
+ assertFalse(Boolean.parseBoolean(view.get(11)));
+ assertEquals("-1", view.get(13));
+ assertEquals(toStringSafe(client2.context().discovery().topologyVersionEx()), view.get(16));
+ assertEquals("null", view.get(17));
+ assertTrue(Boolean.parseBoolean(view.get(10)));
+ assertEquals("null", view.get(14));
+ assertEquals("null", view.get(15));
+ assertEquals("20", view.get(12));
+ };
+
+ boolean found1 = false;
+ boolean found2 = false;
+
+ for (List<String> row : systemView(node, SCAN_QRY_SYS_VIEW)) {
+ if ("cache2".equals(row.get(2))) {
+ cache2checker.accept(row);
+ found1 = true;
+ }
+ else {
+ cache1checker.accept(row);
+ found2 = true;
+ }
+ }
+
+ assertTrue(found1 && found2);
+ }
+
+ /** */
+ @Test
+ public void testStripedExecutor() throws Exception {
+ checkStripeExecutorView(ignite0.context().getStripedExecutorService(),
+ SYS_POOL_QUEUE_VIEW,
+ "sys");
+ }
+
+ /** */
+ @Test
+ public void testStreamerExecutor() throws Exception {
+ checkStripeExecutorView(ignite0.context().getDataStreamerExecutorService(),
+ STREAM_POOL_QUEUE_VIEW,
+ "data-streamer");
+ }
+
+ /**
+ * Checks striped executor system view.
+ *
+ * @param execSvc Striped executor.
+ * @param view System view name.
+ * @param poolName Executor name.
+ */
+ private void checkStripeExecutorView(StripedExecutor execSvc, String view, String poolName) throws Exception {
+ CountDownLatch latch = new CountDownLatch(1);
+
+ execSvc.execute(0, new TestRunnable(latch, 0));
+ execSvc.execute(0, new TestRunnable(latch, 1));
+ execSvc.execute(1, new TestRunnable(latch, 2));
+ execSvc.execute(1, new TestRunnable(latch, 3));
+
+ try {
+ assertTrue(waitForCondition(() -> systemView(ignite0, view).size() == 2, getTestTimeout()));
+
+ List<List<String>> stripedQueue = systemView(ignite0, view);
+
+ List<String> row0 = stripedQueue.get(0);
+
+ assertEquals("0", row0.get(0));
+ assertEquals(TestRunnable.class.getSimpleName() + '1', row0.get(1));
+ assertEquals(poolName + "-stripe-0", row0.get(2));
+ assertEquals(TestRunnable.class.getName(), row0.get(3));
+
+ List<String> row1 = stripedQueue.get(1);
+
+ assertEquals("1", row1.get(0));
+ assertEquals(TestRunnable.class.getSimpleName() + '3', row1.get(1));
+ assertEquals(poolName + "-stripe-1", row1.get(2));
+ assertEquals(TestRunnable.class.getName(), row1.get(3));
+ }
+ finally {
+ latch.countDown();
+ }
+ }
+
+ /** */
+ @Test
+ public void testPagesList() throws Exception {
+ String cacheName = "cacheFL";
+
+ IgniteCache<Integer, byte[]> cache = ignite0.getOrCreateCache(new CacheConfiguration<Integer, byte[]>()
+ .setName(cacheName)
+ .setAffinity(new RendezvousAffinityFunction()
+ .setPartitions(1)));
+
+ GridCacheDatabaseSharedManager dbMgr = (GridCacheDatabaseSharedManager)ignite0.context().cache().context()
+ .database();
+
+ int pageSize = dbMgr.pageSize();
+
+ try {
+ dbMgr.enableCheckpoints(false).get();
+
+ int key = 0;
+
+ // Fill up different free-list buckets.
+ for (int j = 0; j < pageSize / 2; j++)
+ cache.put(key++, new byte[j + 1]);
+
+ // Put some pages to one bucket to overflow pages cache.
+ for (int j = 0; j < 1000; j++)
+ cache.put(key++, new byte[pageSize / 2]);
+
+ List<List<String>> cacheGrpView = systemView(ignite0, CACHE_GRP_PAGE_LIST_VIEW);
+
+ List<List<String>> dataRegionView = systemView(ignite0, DATA_REGION_PAGE_LIST_VIEW);
+
+ String cacheId = Integer.toString(cacheId(cacheName));
+
+ // Test filtering by 3 columns.
+ assertFalse(cacheGrpView.stream().noneMatch(row ->
+ cacheId.equals(row.get(0)) &&
+ "0".equals(row.get(1)) &&
+ "0".equals(row.get(3))));
+
+ // Test filtering with invalid cache group id.
+ assertTrue(cacheGrpView.stream().noneMatch(row -> "-1".equals(row.get(0))));
+
+ // Test filtering with invalid partition id.
+ assertTrue(cacheGrpView.stream().noneMatch(row -> "-1".equals(row.get(1))));
+
+ // Test filtering with invalid bucket number.
+ assertTrue(cacheGrpView.stream().noneMatch(row -> "-1".equals(row.get(3))));
+
+ assertFalse(cacheGrpView.stream().noneMatch(row ->
+ Integer.parseInt(row.get(4)) > 0 && cacheId.equals(row.get(0))));
+
+ assertFalse(cacheGrpView.stream().noneMatch(row ->
+ Integer.parseInt(row.get(5)) > 0 && cacheId.equals(row.get(0))));
+
+ assertFalse(cacheGrpView.stream().noneMatch(row ->
+ Integer.parseInt(row.get(6)) > 0 && cacheId.equals(row.get(0))));
+
+ assertFalse(dataRegionView.stream().noneMatch(row -> row.get(0).startsWith(DATA_REGION_NAME)));
+
+ assertTrue(dataRegionView.stream().noneMatch(row ->
+ row.get(0).startsWith(DATA_REGION_NAME) && Integer.parseInt(row.get(4)) > 0));
+ }
+ finally {
+ dbMgr.enableCheckpoints(true).get();
+ }
+
+ ignite0.cluster().state(INACTIVE);
+
+ ignite0.cluster().state(ACTIVE);
+
+ IgniteCache<Integer, Integer> cacheInMemory = ignite0.getOrCreateCache(
+ new CacheConfiguration<Integer, Integer>()
+ .setName("cacheFLInMemory")
+ .setDataRegionName(DATA_REGION_NAME));
+
+ cacheInMemory.put(0, 0);
+
+ // After activation/deactivation new view for data region pages lists should be created, check that new view
+ // correctly reflects changes in free-lists.
+ assertTrue(systemView(ignite0, DATA_REGION_PAGE_LIST_VIEW).stream().noneMatch(row ->
+ row.get(0).startsWith(DATA_REGION_NAME) && Integer.parseInt(row.get(4)) > 0));
+ }
+
+ /** */
+ @Test
+ public void testPartitionStates() throws Exception {
+ String nodeName0 = getTestIgniteInstanceName(0);
+ String nodeName1 = getTestIgniteInstanceName(1);
+ String nodeName2 = getTestIgniteInstanceName(2);
+
+ IgniteCache<Integer, Integer> cache1 = ignite0.createCache(new CacheConfiguration<Integer, Integer>()
+ .setName("cache1")
+ .setCacheMode(CacheMode.PARTITIONED)
+ .setAffinity(new TestAffinityFunction(new String[][] {{nodeName0, nodeName1}, {nodeName1, nodeName2},
+ {nodeName2, nodeName0}})));
+
+ IgniteCache<Integer, Integer> cache2 = ignite0.createCache(new CacheConfiguration<Integer, Integer>()
+ .setName("cache2")
+ .setCacheMode(CacheMode.PARTITIONED)
+ .setAffinity(new TestAffinityFunction(new String[][] {{nodeName0, nodeName1, nodeName2}, {nodeName1}})));
+
+ for (int i = 0; i < 100; i++) {
+ cache1.put(i, i);
+ cache2.put(i, i);
+ }
+
+ try (IgniteEx ignite2 = startGrid(nodeName2)) {
+ ignite2.rebalanceEnabled(false);
+
+ ignite0.cluster().setBaselineTopology(ignite0.cluster().topologyVersion());
+
+ String nodeId0 = ignite0.cluster().localNode().id().toString();
+ String nodeId1 = ignite(1).cluster().localNode().id().toString();
+ String nodeId2 = ignite2.cluster().localNode().id().toString();
+
+ String cacheGrpId1 = Integer.toString(ignite0.cachex("cache1").context().groupId());
+ String cacheGrpId2 = Integer.toString(ignite0.cachex("cache2").context().groupId());
+
+ String owningState = GridDhtPartitionState.OWNING.name();
+ String movingState = GridDhtPartitionState.MOVING.name();
+
+ for (int i = 0; i < 3; i++) {
+ List<List<String>> partStatesView = systemView(ignite(i), PART_STATES_VIEW);
+
+ // Check partitions for cache1.
+ checkPartitionStatesView(partStatesView, owningState, true, cacheGrpId1, nodeId0, 0);
+ checkPartitionStatesView(partStatesView, owningState, false, cacheGrpId1, nodeId1, 0);
+ checkPartitionStatesView(partStatesView, owningState, true, cacheGrpId1, nodeId1, 1);
+ checkPartitionStatesView(partStatesView, movingState, false, cacheGrpId1, nodeId2, 1);
+ checkPartitionStatesView(partStatesView, owningState, true, cacheGrpId1, nodeId0, 2);
+ checkPartitionStatesView(partStatesView, movingState, false, cacheGrpId1, nodeId2, 2);
+
+ checkPartitionStatesView(partStatesView, owningState, true, cacheGrpId2, nodeId0, 0);
+ checkPartitionStatesView(partStatesView, owningState, false, cacheGrpId2, nodeId1, 0);
+ checkPartitionStatesView(partStatesView, movingState, false, cacheGrpId2, nodeId2, 0);
+ checkPartitionStatesView(partStatesView, owningState, true, cacheGrpId2, nodeId1, 1);
+ }
+
+ AffinityTopologyVersion topVer = ignite0.context().discovery().topologyVersionEx();
+
+ ignite2.rebalanceEnabled(true);
+
+ // Wait until rebalance complete.
+ assertTrue(waitForCondition(() ->
+ ignite0.context().discovery().topologyVersionEx().compareTo(topVer) > 0, getTestTimeout()));
+
+ for (int i = 0; i < 3; i++) {
+ List<List<String>> rows = systemView(ignite(i), PART_STATES_VIEW);
+
+ assertEquals(10, rows.stream().filter(row ->
+ (cacheGrpId1.equals(row.get(0)) || cacheGrpId2.equals(row.get(0))) && owningState.equals(row.get(3))).count());
+
+ assertTrue(rows.stream().noneMatch(row ->
+ (cacheGrpId1.equals(row.get(0)) || cacheGrpId2.equals(row.get(0))) && movingState.equals(row.get(3))));
+ }
+
+ // Check that assignment is now changed to ideal.
+ for (int i = 0; i < 3; i++) {
+ List<List<String>> rows = systemView(ignite(i), PART_STATES_VIEW);
+
+ checkPartitionStatesView(rows, owningState, false, cacheGrpId1, nodeId0, 2);
+ checkPartitionStatesView(rows, owningState, true, cacheGrpId1, nodeId2, 2);
+ }
+ }
+ finally {
+ ignite0.cluster().setBaselineTopology(ignite0.cluster().topologyVersion());
+ }
+ }
+
+ /**
+ * Checks that partitions stated view contains row with specified parameters.
+ *
+ * @param partStatesView Partition states view rows.
+ * @param state Partition state.
+ * @param isPrimary Primary falg.
+ * @param cacheGrpId Cache group id.
+ * @param nodeId Node id.
+ * @param partitionId partition id.
+ */
+ private void checkPartitionStatesView(
+ List<List<String>> partStatesView,
+ String state,
+ boolean isPrimary,
+ String cacheGrpId,
+ String nodeId,
+ int partitionId
+ ) {
+ assertEquals(1, partStatesView.stream().filter(row ->
+ cacheGrpId.equals(row.get(0)) &&
+ nodeId.equals(row.get(1)) &&
+ Integer.toString(partitionId).equals(row.get(2)) &&
+ state.equals(row.get(3)) &&
+ Boolean.toString(isPrimary).equals(row.get(4))
+ ).count());
+ }
+
+ /** */
+ @Test
+ public void testBinaryMeta() {
+ IgniteCache<Integer, TestObjectAllTypes> c1 = ignite0.createCache("test-cache");
+ IgniteCache<Integer, TestObjectEnum> c2 = ignite0.createCache("test-enum-cache");
+
+ executeSql(ignite0, "CREATE TABLE T1(ID LONG PRIMARY KEY, NAME VARCHAR(40), ACCOUNT BIGINT)");
+ executeSql(ignite0, "INSERT INTO T1(ID, NAME, ACCOUNT) VALUES(1, 'test', 1)");
+
+ c1.put(1, new TestObjectAllTypes());
+ c2.put(1, TestObjectEnum.A);
+
+ List<List<String>> binaryMetaView = systemView(ignite0, BINARY_METADATA_VIEW);
+
+ assertEquals(3, binaryMetaView.size());
+
+ for (List<String> row : binaryMetaView) {
+ if (Objects.equals(TestObjectEnum.class.getName(), row.get(1))) {
+ assertTrue(Boolean.parseBoolean(row.get(6)));
+
+ assertEquals("0", row.get(3));
+ }
+ else if (Objects.equals(TestObjectAllTypes.class.getName(), row.get(1))) {
+ assertFalse(Boolean.parseBoolean(row.get(6)));
+
+ Field[] fields = TestObjectAllTypes.class.getDeclaredFields();
+
+ assertEquals(Integer.toString(fields.length), row.get(3));
+
+ for (Field field : fields)
+ assertTrue(row.get(4).contains(field.getName()));
+ }
+ else {
+ assertFalse(Boolean.parseBoolean(row.get(6)));
+
+ assertEquals("2", row.get(3));
+
+ assertTrue(row.get(4).contains("NAME"));
+ assertTrue(row.get(4).contains("ACCOUNT"));
+ }
+ }
+ }
+
+ /** */
+ @Test
+ public void testMetastorage() throws Exception {
+ IgniteCacheDatabaseSharedManager db = ignite0.context().cache().context().database();
+
+ String name = "test-key";
+ String val = "test-value";
+
+ db.checkpointReadLock();
+
+ try {
+ db.metaStorage().write(name, val);
+ }
+ finally {
+ db.checkpointReadUnlock();
+ }
+
+ assertEquals(1, systemView(ignite0, METASTORE_VIEW).stream()
+ .filter(row -> name.equals(row.get(0)) && val.equals(row.get(1)))
+ .count());
+ }
+
+ /** */
+ @Test
+ public void testDistributedMetastorage() throws Exception {
+ DistributedMetaStorage dms = ignite0.context().distributedMetastorage();
+
+ String name = "test-distributed-key";
+ String val = "test-distributed-value";
+
+ dms.write(name, val);
+
+ assertEquals(1, systemView(ignite0, DISTRIBUTED_METASTORE_VIEW).stream()
+ .filter(row -> name.equals(row.get(0)) && val.equals(row.get(1)))
+ .count());
+
+ assertTrue(waitForCondition(() -> systemView(ignite1, DISTRIBUTED_METASTORE_VIEW).stream()
+ .filter(row -> name.equals(row.get(0)) && val.equals(row.get(1)))
+ .count() == 1,
+ getTestTimeout()));
+ }
+
+ /**
+ * Execute query on given node.
+ *
+ * @param node Node.
+ * @param sql Statement.
+ */
+ private List<List<?>> executeSql(Ignite node, String sql, Object... args) {
+ SqlFieldsQuery qry = new SqlFieldsQuery(sql)
+ .setArgs(args)
+ .setSchema("PUBLIC");
+
+ return queryProcessor(node).querySqlFields(qry, true).getAll();
+ }
+
+ /**
+ * Gets system view content via control utility from specified node. Here we also check if attributes names
+ * returned by the command match the real ones. And that both "SQL" and "Java" command names styles are supported.
+ *
+ * @param node The node to obtain system view from.
+ * @param sysViewName Name of the system view which content is required.
+ * @return Content of the requested system view.
+ */
+ private List<List<String>> systemView(IgniteEx node, String sysViewName) {
+ List<String> attrNames = new ArrayList<>();
+
+ SystemView<?> sysView = node.context().systemView().view(sysViewName);
+
+ sysView.walker().visitAll(new AttributeVisitor() {
+ @Override public <T> void accept(int idx, String name, Class<T> clazz) {
+ attrNames.add(name);
+ }
+ });
+
+ String nodeId = node.context().discovery().localNode().id().toString();
+
+ List<List<String>> rows = parseSystemViewCommandOutput(
+ executeCommand(EXIT_CODE_OK, CMD_SYS_VIEW, toSqlName(sysViewName), NODE_ID.argName(), nodeId));
+
+ assertEquals(attrNames, rows.get(0));
+
+ rows = parseSystemViewCommandOutput(
+ executeCommand(EXIT_CODE_OK, CMD_SYS_VIEW, toSqlName(sysViewName).toLowerCase(), NODE_ID.argName(), nodeId));
+
+ assertEquals(attrNames, rows.get(0));
+
+ rows = parseSystemViewCommandOutput(
+ executeCommand(EXIT_CODE_OK, CMD_SYS_VIEW, sysViewName, NODE_ID.argName(), nodeId));
+
+ assertEquals(attrNames, rows.remove(0));
+
+ int attrsCnt = sysView.walker().count();
+
+ rows.forEach(row -> assertEquals(attrsCnt, row.size()));
+
+ return rows;
+ }
+
+ /**
+ * Obtains system view values for each row from command output.
+ *
+ * @param out Command output to parse.
+ * @return System view values.
+ */
+ private List<List<String>> parseSystemViewCommandOutput(String out) {
+ String outStart = "--------------------------------------------------------------------------------";
+
+ String outEnd = "Command [" + SYSTEM_VIEW.toCommandName() + "] finished with code: " + EXIT_CODE_OK;
+
+ List<String> rows = Arrays.asList(out.substring(
+ out.indexOf(outStart) + outStart.length() + 1,
+ out.indexOf(outEnd) - 1
+ ).split(U.nl()));
+
+ return rows.stream().map(row ->
+ Arrays.stream(row.split(quote(COLUMN_SEPARATOR)))
+ .map(String::trim)
+ .filter(str -> !str.isEmpty())
+ .collect(Collectors.toList()))
+ .collect(Collectors.toList());
+ }
+
+ /**
+ * Executes command and checks its exit code.
+ *
+ * @param expExitCode Expected exit code.
+ * @param args Command lines arguments.
+ * @return Result of command execution.
+ */
+ private String executeCommand(int expExitCode, String... args) {
+ int res = execute(args);
+
+ assertEquals(expExitCode, res);
+
+ return testOut.toString();
+ }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/impl/MetricUtils.java b/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/impl/MetricUtils.java
index ab64a47..0ec8d6b 100644
--- a/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/impl/MetricUtils.java
+++ b/modules/core/src/main/java/org/apache/ignite/internal/processors/metric/impl/MetricUtils.java
@@ -163,4 +163,20 @@ public class MetricUtils {
return names;
}
+
+ /**
+ * Build SQL-like name from Java code style name.
+ * Some examples:
+ *
+ * cacheName -> CACHE_NAME.
+ * affinitiKeyName -> AFFINITY_KEY_NAME.
+ *
+ * @param name Name to convert.
+ * @return SQL compatible name.
+ */
+ public static String toSqlName(String name) {
+ return name
+ .replaceAll("([A-Z])", "_$1")
+ .replaceAll('\\' + SEPARATOR, "_").toUpperCase();
+ }
}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/systemview/VisorSystemViewTask.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/systemview/VisorSystemViewTask.java
new file mode 100644
index 0000000..84ca9b5
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/systemview/VisorSystemViewTask.java
@@ -0,0 +1,194 @@
+/*
+ * 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.visor.systemview;
+
+import java.io.Serializable;
+import java.util.ArrayList;
+import java.util.Date;
+import java.util.List;
+import java.util.UUID;
+import org.apache.ignite.IgniteException;
+import org.apache.ignite.internal.managers.systemview.GridSystemViewManager;
+import org.apache.ignite.internal.processors.task.GridInternal;
+import org.apache.ignite.internal.processors.task.GridVisorManagementTask;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.internal.visor.VisorJob;
+import org.apache.ignite.internal.visor.VisorOneNodeTask;
+import org.apache.ignite.lang.IgniteUuid;
+import org.apache.ignite.spi.systemview.view.SystemView;
+import org.apache.ignite.spi.systemview.view.SystemViewRowAttributeWalker;
+import org.apache.ignite.spi.systemview.view.SystemViewRowAttributeWalker.AttributeWithValueVisitor;
+import org.jetbrains.annotations.Nullable;
+
+import static org.apache.ignite.internal.processors.metric.impl.MetricUtils.toSqlName;
+import static org.apache.ignite.internal.visor.systemview.VisorSystemViewTask.SimpleAttributeType.DATE;
+import static org.apache.ignite.internal.visor.systemview.VisorSystemViewTask.SimpleAttributeType.NUMBER;
+import static org.apache.ignite.internal.visor.systemview.VisorSystemViewTask.SimpleAttributeType.STRING;
+
+/** Reperesents visor task for obtaining system view content. */
+@GridInternal
+@GridVisorManagementTask
+public class VisorSystemViewTask extends VisorOneNodeTask<VisorSystemViewTaskArg, VisorSystemViewTaskResult> {
+ /** */
+ private static final long serialVersionUID = 0L;
+
+ /** {@inheritDoc} */
+ @Override protected VisorJob<VisorSystemViewTaskArg, VisorSystemViewTaskResult> job(VisorSystemViewTaskArg arg) {
+ return new VisorSystemViewJob(arg, false);
+ }
+
+ /** */
+ private static class VisorSystemViewJob extends VisorJob<VisorSystemViewTaskArg, VisorSystemViewTaskResult> {
+ /** */
+ private static final long serialVersionUID = 0L;
+
+ /**
+ * Create job with specified argument.
+ *
+ * @param arg Job argument.
+ * @param debug Flag indicating whether debug information should be printed into node log.
+ */
+ protected VisorSystemViewJob(@Nullable VisorSystemViewTaskArg arg, boolean debug) {
+ super(arg, debug);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected VisorSystemViewTaskResult run(@Nullable VisorSystemViewTaskArg arg) throws IgniteException {
+ SystemView<?> sysView = systemView(arg.systemViewName());
+
+ if (sysView == null)
+ return null;
+
+ List<String> attrNames = new ArrayList<>();
+ List<SimpleAttributeType> attrTypes = new ArrayList<>();
+
+ sysView.walker().visitAll(new SystemViewRowAttributeWalker.AttributeVisitor() {
+ @Override public <T> void accept(int idx, String name, Class<T> clazz) {
+ attrNames.add(name);
+
+ Class<?> wrapperCls = U.box(clazz);
+
+ if (Number.class.isAssignableFrom(wrapperCls))
+ attrTypes.add(NUMBER);
+ else if (Date.class.isAssignableFrom(wrapperCls))
+ attrTypes.add(DATE);
+ else
+ attrTypes.add(STRING);
+ }
+ });
+
+ List<List<?>> rows = new ArrayList<>();
+
+ for (Object row : sysView) {
+ List<Serializable> attrVals = new ArrayList<>();
+
+ ((SystemView<Object>)sysView).walker().visitAll(row, new AttributeWithValueVisitor() {
+ @Override public <T> void accept(int idx, String name, Class<T> clazz, T val) {
+ if (clazz.isEnum())
+ attrVals.add(val == null ? null : ((Enum<?>)val).name());
+ else if (Class.class.isAssignableFrom(clazz))
+ attrVals.add(val == null ? null : ((Class<?>)val).getName());
+ else if (
+ Date.class.isAssignableFrom(clazz) ||
+ UUID.class.isAssignableFrom(clazz) ||
+ IgniteUuid.class.isAssignableFrom(clazz)
+ )
+ attrVals.add((Serializable)val);
+ else
+ attrVals.add(String.valueOf(val));
+ }
+
+ @Override public void acceptBoolean(int idx, String name, boolean val) {
+ attrVals.add(val);
+ }
+
+ @Override public void acceptChar(int idx, String name, char val) {
+ attrVals.add(val);
+ }
+
+ @Override public void acceptByte(int idx, String name, byte val) {
+ attrVals.add(val);
+ }
+
+ @Override public void acceptShort(int idx, String name, short val) {
+ attrVals.add(val);
+ }
+
+ @Override public void acceptInt(int idx, String name, int val) {
+ attrVals.add(val);
+ }
+
+ @Override public void acceptLong(int idx, String name, long val) {
+ attrVals.add(val);
+ }
+
+ @Override public void acceptFloat(int idx, String name, float val) {
+ attrVals.add(val);
+ }
+
+ @Override public void acceptDouble(int idx, String name, double val) {
+ attrVals.add(val);
+ }
+ });
+
+ rows.add(attrVals);
+ }
+
+ return new VisorSystemViewTaskResult(attrNames, attrTypes, rows);
+ }
+
+ /**
+ * Gets system view with specified name.
+ *
+ * @param name Name of system view. Both "SQL" and "Java" styles of name are suppurted.
+ * @return System view.
+ */
+ private SystemView<?> systemView(String name) {
+ GridSystemViewManager sysViewMgr = ignite.context().systemView();
+
+ SystemView<?> res = sysViewMgr.view(name);
+
+ if (res == null) { // In this case we assume that the requested system view name is in SQL format.
+ for (SystemView<?> sysView : sysViewMgr) {
+ if (toSqlName(sysView.name()).toLowerCase().equals(name.toLowerCase())) {
+ res = sysView;
+
+ break;
+ }
+ }
+ }
+
+ return res;
+ }
+ }
+
+ /**
+ * Represents simple types of system view attributes. It helps task initiator to determine type of each
+ * column for received system view rows.
+ */
+ public enum SimpleAttributeType {
+ /** Date. */
+ DATE,
+
+ /** Number. */
+ NUMBER,
+
+ /** String. */
+ STRING
+ }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/systemview/VisorSystemViewTaskArg.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/systemview/VisorSystemViewTaskArg.java
new file mode 100644
index 0000000..c0e9e3c
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/systemview/VisorSystemViewTaskArg.java
@@ -0,0 +1,64 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.ignite.internal.visor.systemview;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import org.apache.ignite.internal.dto.IgniteDataTransferObject;
+import org.apache.ignite.internal.util.typedef.internal.S;
+import org.apache.ignite.internal.util.typedef.internal.U;
+
+/** */
+public class VisorSystemViewTaskArg extends IgniteDataTransferObject {
+ /** */
+ private static final long serialVersionUID = 0L;
+
+ /** Name of the system view which attributes are to be printed. */
+ private String sysViewName;
+
+ /** Default constructor. */
+ public VisorSystemViewTaskArg() {
+ // No-op.
+ }
+
+ /** @param sysViewName Name of the system view which attributes are to be printed. */
+ public VisorSystemViewTaskArg(String sysViewName) {
+ this.sysViewName = sysViewName;
+ }
+
+ /** @return Name of the system view which attributes are requested. */
+ public String systemViewName() {
+ return sysViewName;
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void writeExternalData(ObjectOutput out) throws IOException {
+ U.writeString(out, sysViewName);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void readExternalData(byte protoVer, ObjectInput in) throws IOException, ClassNotFoundException {
+ sysViewName = U.readString(in);
+ }
+
+ /** {@inheritDoc} */
+ @Override public String toString() {
+ return S.toString(VisorSystemViewTaskArg.class, this);
+ }
+}
diff --git a/modules/core/src/main/java/org/apache/ignite/internal/visor/systemview/VisorSystemViewTaskResult.java b/modules/core/src/main/java/org/apache/ignite/internal/visor/systemview/VisorSystemViewTaskResult.java
new file mode 100644
index 0000000..2516c8e
--- /dev/null
+++ b/modules/core/src/main/java/org/apache/ignite/internal/visor/systemview/VisorSystemViewTaskResult.java
@@ -0,0 +1,101 @@
+/*
+ * 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.visor.systemview;
+
+import java.io.IOException;
+import java.io.ObjectInput;
+import java.io.ObjectOutput;
+import java.util.ArrayList;
+import java.util.List;
+import org.apache.ignite.internal.dto.IgniteDataTransferObject;
+import org.apache.ignite.internal.util.typedef.internal.U;
+import org.apache.ignite.internal.visor.systemview.VisorSystemViewTask.SimpleAttributeType;
+
+/** Reperesents result of {@link VisorSystemViewTask}. */
+public class VisorSystemViewTaskResult extends IgniteDataTransferObject {
+ /** */
+ private static final long serialVersionUID = 0L;
+
+ /** Attribute values for each row of the system view. */
+ private List<List<?>> rows;
+
+ /** Names of the system view attributes. */
+ private List<String> attrs;
+
+ /** Types of the system view attributes. */
+ List<SimpleAttributeType> types;
+
+ /** Default constructor. */
+ public VisorSystemViewTaskResult() {
+ // No-op.
+ }
+
+ /**
+ * @param attrs Names of system view attributes.
+ * @param types Types of the system view attributes.
+ * @param rows Attribute values for each row of the system view.
+ */
+ public VisorSystemViewTaskResult(List<String> attrs, List<SimpleAttributeType> types, List<List<?>> rows) {
+ this.attrs = attrs;
+ this.types = types;
+ this.rows = rows;
+ }
+
+ /** @return Names of the system view attributes. */
+ public List<String> attributes() {
+ return attrs;
+ }
+
+ /** @return Attribute values for each row of the system view. */
+ public List<List<?>> rows() {
+ return rows;
+ }
+
+ /** @return Types of the system view attributes. */
+ public List<SimpleAttributeType> types() {
+ return types;
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void writeExternalData(ObjectOutput out) throws IOException {
+ U.writeCollection(out, attrs);
+
+ U.writeCollection(out, types);
+
+ out.writeInt(rows.size());
+
+ for (List<?> row : rows)
+ U.writeCollection(out, row);
+ }
+
+ /** {@inheritDoc} */
+ @Override protected void readExternalData(byte protoVer, ObjectInput in) throws IOException, ClassNotFoundException {
+ attrs = U.readList(in);
+
+ types = U.readList(in);
+
+ int rowsCnt = in.readInt();
+
+ List<List<?>> rows = new ArrayList<>(rowsCnt);
+
+ for (int i = 0; i < rowsCnt; i++)
+ rows.add(U.readList(in));
+
+ this.rows = rows;
+ }
+}
diff --git a/modules/core/src/main/resources/META-INF/classnames.properties b/modules/core/src/main/resources/META-INF/classnames.properties
index a7fc780..20a984a 100644
--- a/modules/core/src/main/resources/META-INF/classnames.properties
+++ b/modules/core/src/main/resources/META-INF/classnames.properties
@@ -2367,6 +2367,11 @@ org.apache.ignite.internal.visor.verify.VisorViewCacheTask
org.apache.ignite.internal.visor.verify.VisorViewCacheTask$VisorViewCacheJob
org.apache.ignite.internal.visor.verify.VisorViewCacheTaskArg
org.apache.ignite.internal.visor.verify.VisorViewCacheTaskResult
+org.apache.ignite.internal.visor.systemview.VisorSystemViewTask
+org.apache.ignite.internal.visor.systemview.VisorSystemViewTaskArg
+org.apache.ignite.internal.visor.systemview.VisorSystemViewTaskResult
+org.apache.ignite.internal.visor.systemview.VisorSystemViewTask$VisorSystemViewJob
+org.apache.ignite.internal.visor.systemview.VisorSystemViewTask$SimpleAttributeType
org.apache.ignite.internal.websession.WebSessionAttributeProcessor
org.apache.ignite.internal.websession.WebSessionEntity
org.apache.ignite.lang.IgniteBiClosure
diff --git a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_help.output b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_help.output
index ca726a5..2c972c3 100644
--- a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_help.output
+++ b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassTest_help.output
@@ -180,6 +180,13 @@ If the file name isn't specified the output file name is: '<typeId>.bin'
Set the property value
control.(sh|bat) --property set --name <property_name> --val <property_value>
+ Print system view content:
+ control.(sh|bat) --system-view [--node-id node_id] system_view_name
+
+ Parameters:
+ system_view_name - Name of the system view which content should be printed. Both "SQL" and "Java" styles of system view name are supported (e.g. SQL_TABLES and sql.tables will be handled similarly).
+ node_id - ID of the node to get the system view from. If not set, random node will be chosen.
+
By default commands affecting the cluster require interactive confirmation.
Use --yes option to disable it.
diff --git a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_help.output b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_help.output
index ca726a5..2c972c3 100644
--- a/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_help.output
+++ b/modules/core/src/test/resources/org.apache.ignite.util/GridCommandHandlerClusterByClassWithSSLTest_help.output
@@ -180,6 +180,13 @@ If the file name isn't specified the output file name is: '<typeId>.bin'
Set the property value
control.(sh|bat) --property set --name <property_name> --val <property_value>
+ Print system view content:
+ control.(sh|bat) --system-view [--node-id node_id] system_view_name
+
+ Parameters:
+ system_view_name - Name of the system view which content should be printed. Both "SQL" and "Java" styles of system view name are supported (e.g. SQL_TABLES and sql.tables will be handled similarly).
+ node_id - ID of the node to get the system view from. If not set, random node will be chosen.
+
By default commands affecting the cluster require interactive confirmation.
Use --yes option to disable it.
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/managers/systemview/FiltrableSystemViewLocal.java b/modules/indexing/src/main/java/org/apache/ignite/internal/managers/systemview/FiltrableSystemViewLocal.java
index 9ade894..ba7f2d0 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/managers/systemview/FiltrableSystemViewLocal.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/managers/systemview/FiltrableSystemViewLocal.java
@@ -23,6 +23,7 @@ import java.util.Map;
import java.util.stream.Collectors;
import org.apache.ignite.internal.GridKernalContext;
import org.apache.ignite.internal.processors.cache.query.IgniteQueryErrorCode;
+import org.apache.ignite.internal.processors.metric.impl.MetricUtils;
import org.apache.ignite.internal.processors.query.IgniteSQLException;
import org.apache.ignite.internal.processors.query.h2.sys.view.SqlSystemViewColumnCondition;
import org.apache.ignite.internal.util.typedef.internal.U;
@@ -92,7 +93,7 @@ class FiltrableSystemViewLocal<R> extends SystemViewLocal<R> {
* @return Indexes array for {@code sysView}.
*/
private static String[] indexes(SystemView<?> sysView) {
- return new String[] {sysView.walker().filtrableAttributes().stream().map(SystemViewLocal::sqlName)
+ return new String[] {sysView.walker().filtrableAttributes().stream().map(MetricUtils::toSqlName)
.collect(Collectors.joining(","))};
}
}
diff --git a/modules/indexing/src/main/java/org/apache/ignite/internal/managers/systemview/SystemViewLocal.java b/modules/indexing/src/main/java/org/apache/ignite/internal/managers/systemview/SystemViewLocal.java
index c18c253..d8e4e53 100644
--- a/modules/indexing/src/main/java/org/apache/ignite/internal/managers/systemview/SystemViewLocal.java
+++ b/modules/indexing/src/main/java/org/apache/ignite/internal/managers/systemview/SystemViewLocal.java
@@ -29,7 +29,6 @@ import java.util.UUID;
import java.util.function.Function;
import org.apache.ignite.internal.GridKernalContext;
-import org.apache.ignite.internal.processors.metric.impl.MetricUtils;
import org.apache.ignite.internal.processors.query.h2.sys.view.SqlAbstractLocalSystemView;
import org.apache.ignite.lang.IgniteUuid;
import org.apache.ignite.spi.systemview.view.SystemView;
@@ -53,6 +52,8 @@ import org.h2.value.ValueString;
import org.h2.value.ValueTimestamp;
import org.h2.value.ValueUuid;
+import static org.apache.ignite.internal.processors.metric.impl.MetricUtils.toSqlName;
+
/**
* SQL system view to export {@link SystemView} data.
*/
@@ -119,7 +120,7 @@ class SystemViewLocal<R> extends SqlAbstractLocalSystemView {
* @param indexes Indexed fields.
*/
protected SystemViewLocal(GridKernalContext ctx, SystemView<R> sysView, String[] indexes) {
- super(sqlName(sysView.name()), sysView.description(), ctx, indexes, columnsList(sysView));
+ super(toSqlName(sysView.name()), sysView.description(), ctx, indexes, columnsList(sysView));
this.sysView = sysView;
}
@@ -213,7 +214,7 @@ class SystemViewLocal<R> extends SqlAbstractLocalSystemView {
@Override public <T> void accept(int idx, String name, Class<T> clazz) {
int type = CLS_TO_VAL_TYPE.getOrDefault(clazz, Value.STRING);
- cols[idx] = newColumn(sqlName(name), type);
+ cols[idx] = newColumn(toSqlName(name), type);
}
});
@@ -236,20 +237,4 @@ class SystemViewLocal<R> extends SqlAbstractLocalSystemView {
@Override public boolean canGetRowCount() {
return true;
}
-
- /**
- * Build SQL-like name from Java code style name.
- * Some examples:
- *
- * cacheName -> CACHE_NAME.
- * affinitiKeyName -> AFFINITY_KEY_NAME.
- *
- * @param name Name to convert.
- * @return SQL compatible name.
- */
- protected static String sqlName(String name) {
- return name
- .replaceAll("([A-Z])", "_$1")
- .replaceAll('\\' + MetricUtils.SEPARATOR, "_").toUpperCase();
- }
}
diff --git a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/metric/SqlViewExporterSpiTest.java b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/metric/SqlViewExporterSpiTest.java
index e1e132b..d93afe1 100644
--- a/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/metric/SqlViewExporterSpiTest.java
+++ b/modules/indexing/src/test/java/org/apache/ignite/internal/processors/cache/metric/SqlViewExporterSpiTest.java
@@ -1164,14 +1164,14 @@ public class SqlViewExporterSpiTest extends AbstractExporterSpiTest {
/**
* Affinity function with fixed partition allocation.
*/
- private static class TestAffinityFunction implements AffinityFunction {
+ public static class TestAffinityFunction implements AffinityFunction {
/** Partitions to nodes map. */
private final String[][] partMap;
/**
* @param partMap Parition allocation map, contains nodes consistent ids for each partition.
*/
- private TestAffinityFunction(String[][] partMap) {
+ public TestAffinityFunction(String[][] partMap) {
this.partMap = partMap;
}