diff --git a/example/pipe-count-point-processor/src/main/java/org/apache/iotdb/CountPointProcessor.java b/example/pipe-count-point-processor/src/main/java/org/apache/iotdb/CountPointProcessor.java index 61a888d4eca23..a8c71d0fa59fc 100644 --- a/example/pipe-count-point-processor/src/main/java/org/apache/iotdb/CountPointProcessor.java +++ b/example/pipe-count-point-processor/src/main/java/org/apache/iotdb/CountPointProcessor.java @@ -44,26 +44,28 @@ public class CountPointProcessor implements PipeProcessor { private PartialPath aggregateSeries; @Override - public void validate(PipeParameterValidator validator) { + public void validate(final PipeParameterValidator validator) { validator.validateRequiredAttribute(AGGREGATE_SERIES_KEY); } @Override - public void customize(PipeParameters parameters, PipeProcessorRuntimeConfiguration configuration) + public void customize( + final PipeParameters parameters, final PipeProcessorRuntimeConfiguration configuration) throws Exception { this.aggregateSeries = new PartialPath(parameters.getString(AGGREGATE_SERIES_KEY)); } @Override - public void process(TabletInsertionEvent tabletInsertionEvent, EventCollector eventCollector) { + public void process( + final TabletInsertionEvent tabletInsertionEvent, final EventCollector eventCollector) { tabletInsertionEvent.processTablet( (tablet, rowCollector) -> writePointCount.addAndGet(tablet.rowSize)); } @Override - public void process(Event event, EventCollector eventCollector) throws Exception { + public void process(final Event event, final EventCollector eventCollector) throws Exception { if (event instanceof PipeHeartbeatEvent) { - Tablet tablet = + final Tablet tablet = new Tablet( aggregateSeries.getIDeviceID().toString(), Collections.singletonList( @@ -73,7 +75,7 @@ public void process(Event event, EventCollector eventCollector) throws Exception tablet.addTimestamp(0, System.currentTimeMillis()); tablet.addValue(aggregateSeries.getMeasurement(), 0, writePointCount.get()); eventCollector.collect( - new PipeRawTabletInsertionEvent(tablet, false, null, null, null, false)); + new PipeRawTabletInsertionEvent(tablet, false, null, 0, null, null, false)); } } diff --git a/example/schema/pom.xml b/example/schema/pom.xml index 07c3085767967..54246f9c8064a 100644 --- a/example/schema/pom.xml +++ b/example/schema/pom.xml @@ -32,7 +32,6 @@ ch.qos.logback logback-classic - 1.3.13 org.apache.tsfile diff --git a/example/session/src/main/java/org/apache/iotdb/SubscriptionSessionExample.java b/example/session/src/main/java/org/apache/iotdb/SubscriptionSessionExample.java index 62c869e02bf0a..3c3ae618ce3ec 100644 --- a/example/session/src/main/java/org/apache/iotdb/SubscriptionSessionExample.java +++ b/example/session/src/main/java/org/apache/iotdb/SubscriptionSessionExample.java @@ -25,14 +25,23 @@ import org.apache.iotdb.rpc.subscription.config.TopicConstant; import org.apache.iotdb.session.Session; import org.apache.iotdb.session.subscription.SubscriptionSession; +import org.apache.iotdb.session.subscription.consumer.AckStrategy; +import org.apache.iotdb.session.subscription.consumer.ConsumeResult; import org.apache.iotdb.session.subscription.consumer.SubscriptionPullConsumer; +import org.apache.iotdb.session.subscription.consumer.SubscriptionPushConsumer; import org.apache.iotdb.session.subscription.payload.SubscriptionMessage; import org.apache.iotdb.session.subscription.payload.SubscriptionSessionDataSet; +import org.apache.iotdb.session.subscription.payload.SubscriptionTsFileHandler; import org.apache.tsfile.read.TsFileReader; +import org.apache.tsfile.read.common.Path; +import org.apache.tsfile.read.expression.QueryExpression; +import org.apache.tsfile.read.query.dataset.QueryDataSet; import java.io.IOException; +import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Properties; @@ -46,11 +55,14 @@ public class SubscriptionSessionExample { private static final int PORT = 6667; private static final String TOPIC_1 = "topic1"; - private static final String TOPIC_2 = "`topic2`"; + private static final String TOPIC_2 = "`'topic2'`"; + private static final String TOPIC_3 = "`\"topic3\"`"; + private static final String TOPIC_4 = "`\"top \\.i.c4\"`"; - public static final long SLEEP_NS = 1_000_000_000L; - public static final long POLL_TIMEOUT_MS = 10_000L; + private static final long SLEEP_NS = 1_000_000_000L; + private static final long POLL_TIMEOUT_MS = 10_000L; private static final int MAX_RETRY_TIMES = 3; + private static final int PARALLELISM = 8; private static void prepareData() throws Exception { // Open session @@ -66,13 +78,13 @@ private static void prepareData() throws Exception { // Insert some historical data final long currentTime = System.currentTimeMillis(); - for (int i = 0; i < 10000; ++i) { + for (int i = 0; i < 100; ++i) { session.executeNonQueryStatement( String.format("insert into root.db.d1(time, s1, s2) values (%s, 1, 2)", i)); session.executeNonQueryStatement( - String.format("insert into root.db.d2(time, s3, s4) values (%s, 3, 4)", currentTime + i)); + String.format("insert into root.db.d2(time, s1, s2) values (%s, 3, 4)", currentTime + i)); session.executeNonQueryStatement( - String.format("insert into root.sg.d3(time, s5) values (%s, 5)", currentTime + 2 * i)); + String.format("insert into root.sg.d3(time, s1) values (%s, 5)", currentTime + 2 * i)); } session.executeNonQueryStatement("flush"); @@ -104,11 +116,16 @@ private static void dataQuery() throws Exception { session = null; } - private static void subscriptionExample1() throws Exception { + /** single pull consumer subscribe topic with path and time range */ + private static void dataSubscription1() throws Exception { // Create topics try (final SubscriptionSession subscriptionSession = new SubscriptionSession(HOST, PORT)) { subscriptionSession.open(); - subscriptionSession.createTopic(TOPIC_1); + final Properties config = new Properties(); + config.put(TopicConstant.PATH_KEY, "root.db.d1.s1"); + config.put(TopicConstant.START_TIME_KEY, 25); + config.put(TopicConstant.END_TIME_KEY, 75); + subscriptionSession.createTopic(TOPIC_1, config); } int retryCount = 0; @@ -151,7 +168,8 @@ private static void subscriptionExample1() throws Exception { consumer1.close(); } - private static void subscriptionExample2() throws Exception { + /** multi pull consumer subscribe topic with tsfile format */ + private static void dataSubscription2() throws Exception { try (final SubscriptionSession subscriptionSession = new SubscriptionSession(HOST, PORT)) { subscriptionSession.open(); final Properties config = new Properties(); @@ -160,7 +178,7 @@ private static void subscriptionExample2() throws Exception { } final List threads = new ArrayList<>(); - for (int i = 0; i < 8; ++i) { + for (int i = 0; i < PARALLELISM; ++i) { final int idx = i; final Thread thread = new Thread( @@ -187,7 +205,16 @@ private static void subscriptionExample2() throws Exception { } for (final SubscriptionMessage message : messages) { try (final TsFileReader reader = message.getTsFileHandler().openReader()) { - // do something... + final QueryDataSet dataSet = + reader.query( + QueryExpression.create( + Arrays.asList( + new Path("root.db.d2", "s2", true), + new Path("root.db.d3", "s1", true)), + null)); + while (dataSet.hasNext()) { + System.out.println(dataSet.next()); + } } } consumer2.commitSync(messages); @@ -206,10 +233,109 @@ private static void subscriptionExample2() throws Exception { } } + /** multi push consumer subscribe topic with tsfile format and query mode */ + private static void dataSubscription3() throws Exception { + try (final SubscriptionSession subscriptionSession = new SubscriptionSession(HOST, PORT)) { + subscriptionSession.open(); + final Properties config = new Properties(); + config.put(TopicConstant.FORMAT_KEY, TopicConstant.FORMAT_TS_FILE_HANDLER_VALUE); + config.put(TopicConstant.MODE_KEY, TopicConstant.MODE_QUERY_VALUE); + subscriptionSession.createTopic(TOPIC_3, config); + } + + final List threads = new ArrayList<>(); + for (int i = 0; i < PARALLELISM; ++i) { + final int idx = i; + final Thread thread = + new Thread( + () -> { + // Subscription: builder-style ctor + try (final SubscriptionPushConsumer consumer3 = + new SubscriptionPushConsumer.Builder() + .consumerId("c" + idx) + .consumerGroupId("cg3") + .ackStrategy(AckStrategy.AFTER_CONSUME) + .consumeListener( + message -> { + // do something for SubscriptionTsFileHandler + System.out.println( + message.getTsFileHandler().getFile().getAbsolutePath()); + return ConsumeResult.SUCCESS; + }) + .buildPushConsumer()) { + consumer3.open(); + consumer3.subscribe(TOPIC_3); + while (consumer3.hasMoreData()) { + LockSupport.parkNanos(SLEEP_NS); // wait some time + } + } + }); + thread.start(); + threads.add(thread); + } + + for (final Thread thread : threads) { + thread.join(); + } + } + + /** multi pull consumer subscribe topic with tsfile format and query mode */ + private static void dataSubscription4() throws Exception { + try (final SubscriptionSession subscriptionSession = new SubscriptionSession(HOST, PORT)) { + subscriptionSession.open(); + final Properties config = new Properties(); + config.put(TopicConstant.FORMAT_KEY, TopicConstant.FORMAT_TS_FILE_HANDLER_VALUE); + config.put(TopicConstant.MODE_KEY, TopicConstant.MODE_QUERY_VALUE); + subscriptionSession.createTopic(TOPIC_4, config); + } + + final List threads = new ArrayList<>(); + for (int i = 0; i < PARALLELISM; ++i) { + final int idx = i; + final Thread thread = + new Thread( + () -> { + // Subscription: builder-style ctor + try (final SubscriptionPullConsumer consumer4 = + new SubscriptionPullConsumer.Builder() + .consumerId("c" + idx) + .consumerGroupId("cg4") + .autoCommit(true) + .fileSaveFsync(true) + .buildPullConsumer()) { + consumer4.open(); + consumer4.subscribe(TOPIC_4); + while (true) { + LockSupport.parkNanos(SLEEP_NS); // wait some time + if (!consumer4.hasMoreData()) { + break; + } + for (final SubscriptionMessage message : consumer4.poll(POLL_TIMEOUT_MS)) { + final SubscriptionTsFileHandler handler = message.getTsFileHandler(); + handler.moveFile( + Paths.get(System.getProperty("user.dir"), "new-subscription-dir") + .resolve(handler.getPath().getFileName())); + } + } + } catch (final IOException e) { + throw new RuntimeException(e); + } + }); + thread.start(); + threads.add(thread); + } + + for (final Thread thread : threads) { + thread.join(); + } + } + public static void main(final String[] args) throws Exception { prepareData(); - dataQuery(); - subscriptionExample1(); - subscriptionExample2(); + // dataQuery(); + // dataSubscription1(); + // dataSubscription2(); + // dataSubscription3(); + dataSubscription4(); } } diff --git a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/ClusterConstant.java b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/ClusterConstant.java index d688f2169d5d1..12af0d025f75c 100644 --- a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/ClusterConstant.java +++ b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/ClusterConstant.java @@ -120,9 +120,6 @@ public class ClusterConstant { public static final String COMMON_PROPERTIES_FILE = "iotdb-common.properties"; public static final String IOTDB_SYSTEM_PROPERTIES_FILE = "iotdb-system.properties"; - public static final String SYSTEM_PROPERTIES_FILE = "system.properties"; - public static final String CONFIG_NODE_SYSTEM_PROPERTIES_FILE = "confignode-system.properties"; - // Properties' keys // Common public static final String CONFIG_NODE_CONSENSUS_PROTOCOL_CLASS = diff --git a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/EnvUtils.java b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/EnvUtils.java index 6ecb87c3f0420..f3c9527e5952f 100644 --- a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/EnvUtils.java +++ b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/EnvUtils.java @@ -31,8 +31,8 @@ import java.util.stream.IntStream; import static org.apache.iotdb.consensus.ConsensusFactory.FAST_IOT_CONSENSUS; -import static org.apache.iotdb.consensus.ConsensusFactory.IOTV2_CONSENSUS; import static org.apache.iotdb.consensus.ConsensusFactory.IOT_CONSENSUS; +import static org.apache.iotdb.consensus.ConsensusFactory.IOT_CONSENSUS_V2; import static org.apache.iotdb.consensus.ConsensusFactory.RATIS_CONSENSUS; import static org.apache.iotdb.consensus.ConsensusFactory.REAL_PIPE_CONSENSUS; import static org.apache.iotdb.consensus.ConsensusFactory.SIMPLE_CONSENSUS; @@ -224,7 +224,7 @@ public static String fromConsensusFullNameToAbbr(String consensus) { return IOT_CONSENSUS_STR; case REAL_PIPE_CONSENSUS: return PIPE_CONSENSUS_STR; - case IOTV2_CONSENSUS: + case IOT_CONSENSUS_V2: return STREAM_CONSENSUS_STR; case FAST_IOT_CONSENSUS: return BATCH_CONSENSUS_STR; @@ -244,7 +244,7 @@ public static String fromConsensusAbbrToFullName(String consensus) { case PIPE_CONSENSUS_STR: return REAL_PIPE_CONSENSUS; case STREAM_CONSENSUS_STR: - return IOTV2_CONSENSUS; + return IOT_CONSENSUS_V2; case BATCH_CONSENSUS_STR: return FAST_IOT_CONSENSUS; default: diff --git a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/config/MppCommonConfig.java b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/config/MppCommonConfig.java index 95fed66d08b21..095562db5a51f 100644 --- a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/config/MppCommonConfig.java +++ b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/config/MppCommonConfig.java @@ -438,6 +438,32 @@ public CommonConfig setCnConnectionTimeoutMs(int connectionTimeoutMs) { return this; } + @Override + public CommonConfig setPipeHeartbeatIntervalSecondsForCollectingPipeMeta( + int pipeHeartbeatIntervalSecondsForCollectingPipeMeta) { + setProperty( + "pipe_heartbeat_interval_seconds_for_collecting_pipe_meta", + String.valueOf(pipeHeartbeatIntervalSecondsForCollectingPipeMeta)); + return this; + } + + @Override + public CommonConfig setPipeMetaSyncerInitialSyncDelayMinutes( + long pipeMetaSyncerInitialSyncDelayMinutes) { + setProperty( + "pipe_meta_syncer_initial_sync_delay_minutes", + String.valueOf(pipeMetaSyncerInitialSyncDelayMinutes)); + return this; + } + + @Override + public CommonConfig setPipeMetaSyncerSyncIntervalMinutes(long pipeMetaSyncerSyncIntervalMinutes) { + setProperty( + "pipe_meta_syncer_sync_interval_minutes", + String.valueOf(pipeMetaSyncerSyncIntervalMinutes)); + return this; + } + // For part of the log directory public String getClusterConfigStr() { return fromConsensusFullNameToAbbr(properties.getProperty(CONFIG_NODE_CONSENSUS_PROTOCOL_CLASS)) diff --git a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/config/MppSharedCommonConfig.java b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/config/MppSharedCommonConfig.java index 1851590dd411e..7724bcf09c0af 100644 --- a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/config/MppSharedCommonConfig.java +++ b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/config/MppSharedCommonConfig.java @@ -445,4 +445,29 @@ public CommonConfig setCnConnectionTimeoutMs(int connectionTimeoutMs) { cnConfig.setCnConnectionTimeoutMs(connectionTimeoutMs); return this; } + + @Override + public CommonConfig setPipeHeartbeatIntervalSecondsForCollectingPipeMeta( + int pipeHeartbeatIntervalSecondsForCollectingPipeMeta) { + dnConfig.setPipeHeartbeatIntervalSecondsForCollectingPipeMeta( + pipeHeartbeatIntervalSecondsForCollectingPipeMeta); + cnConfig.setPipeHeartbeatIntervalSecondsForCollectingPipeMeta( + pipeHeartbeatIntervalSecondsForCollectingPipeMeta); + return this; + } + + @Override + public CommonConfig setPipeMetaSyncerInitialSyncDelayMinutes( + long pipeMetaSyncerInitialSyncDelayMinutes) { + dnConfig.setPipeMetaSyncerInitialSyncDelayMinutes(pipeMetaSyncerInitialSyncDelayMinutes); + cnConfig.setPipeMetaSyncerInitialSyncDelayMinutes(pipeMetaSyncerInitialSyncDelayMinutes); + return this; + } + + @Override + public CommonConfig setPipeMetaSyncerSyncIntervalMinutes(long pipeMetaSyncerSyncIntervalMinutes) { + dnConfig.setPipeMetaSyncerSyncIntervalMinutes(pipeMetaSyncerSyncIntervalMinutes); + cnConfig.setPipeMetaSyncerSyncIntervalMinutes(pipeMetaSyncerSyncIntervalMinutes); + return this; + } } diff --git a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/env/AbstractEnv.java b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/env/AbstractEnv.java index 84425f298d74c..2fd68b5bbf621 100644 --- a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/env/AbstractEnv.java +++ b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/env/AbstractEnv.java @@ -640,10 +640,10 @@ public void setTestMethodName(String testMethodName) { @Override public void dumpTestJVMSnapshot() { for (ConfigNodeWrapper configNodeWrapper : configNodeWrapperList) { - configNodeWrapper.dumpJVMSnapshot(testMethodName); + configNodeWrapper.executeJstack(testMethodName); } for (DataNodeWrapper dataNodeWrapper : dataNodeWrapperList) { - dataNodeWrapper.dumpJVMSnapshot(testMethodName); + dataNodeWrapper.executeJstack(testMethodName); } } diff --git a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/node/AbstractNodeWrapper.java b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/node/AbstractNodeWrapper.java index fa5447bc5b071..942b6a9e01242 100644 --- a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/node/AbstractNodeWrapper.java +++ b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/node/AbstractNodeWrapper.java @@ -38,11 +38,14 @@ import javax.management.remote.JMXConnectorFactory; import javax.management.remote.JMXServiceURL; +import java.io.BufferedReader; import java.io.File; import java.io.IOException; +import java.io.InputStreamReader; import java.io.PrintWriter; import java.lang.management.ManagementFactory; import java.lang.management.MonitorInfo; +import java.lang.management.RuntimeMXBean; import java.lang.management.ThreadInfo; import java.lang.management.ThreadMXBean; import java.net.MalformedURLException; @@ -61,6 +64,7 @@ import java.util.Map; import java.util.Properties; import java.util.concurrent.TimeUnit; +import java.util.function.Consumer; import java.util.stream.Stream; import static org.apache.iotdb.it.env.cluster.ClusterConstant.CLUSTER_CONFIGURATIONS; @@ -566,7 +570,6 @@ public String getNodePath() { return System.getProperty(USER_DIR) + File.separator + TARGET + File.separator + getId(); } - @Override public void dumpJVMSnapshot(String testCaseName) { JMXServiceURL url; try { @@ -675,4 +678,72 @@ private String getKillPoints() { public abstract String getSystemPropertiesPath(); protected abstract MppJVMConfig initVMConfig(); + + @Override + public void executeJstack() { + executeJstack(logger::info); + } + + @Override + public void executeJstack(final String testCaseName) { + final String fileName = + getLogDirPath() + File.separator + testCaseName + "_" + getId() + "-threads.jstack"; + try (final PrintWriter output = new PrintWriter(fileName)) { + executeJstack(output::println); + } catch (final IOException e) { + logger.warn("IOException occurred when executing Jstack for {}", this.getId(), e); + } + logger.info("Jstack execution output can be found at {}", fileName); + } + + private void executeJstack(final Consumer consumer) { + final long pid = this.getPid(); + if (pid == -1) { + logger.warn("Failed to get pid for {} before executing Jstack", this.getId()); + return; + } + final String command = "jstack -l " + pid; + logger.info("Executing command {} for {}", command, this.getId()); + try { + final Process process = Runtime.getRuntime().exec(command); + try (final BufferedReader reader = + new BufferedReader(new InputStreamReader(process.getInputStream()))) { + String line; + while ((line = reader.readLine()) != null) { + consumer.accept(line); + } + } + final int exitCode = process.waitFor(); + logger.info("Command {} exited with code {}", command, exitCode); + } catch (final IOException e) { + logger.warn("IOException occurred when executing Jstack for {}", this.getId(), e); + } catch (final InterruptedException e) { + Thread.currentThread().interrupt(); + logger.warn("InterruptedException occurred when executing Jstack for {}", this.getId(), e); + } + } + + /** + * @return The native process ID of the process, -1 if failure. + */ + @Override + public long getPid() { + final JMXServiceURL url; + try { + url = + new JMXServiceURL( + String.format("service:jmx:rmi:///jndi/rmi://127.0.0.1:%d/jmxrmi", jmxPort)); + } catch (final MalformedURLException ignored) { + return -1; + } + try (final JMXConnector connector = JMXConnectorFactory.connect(url)) { + final MBeanServerConnection mbsc = connector.getMBeanServerConnection(); + final RuntimeMXBean rmbean = + ManagementFactory.newPlatformMXBeanProxy( + mbsc, ManagementFactory.RUNTIME_MXBEAN_NAME, RuntimeMXBean.class); + return Long.parseLong(rmbean.getName().split("@")[0]); + } catch (final Throwable ignored) { + return -1; + } + } } diff --git a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/node/ConfigNodeWrapper.java b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/node/ConfigNodeWrapper.java index a457149f5985e..a93c54c52b82a 100644 --- a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/node/ConfigNodeWrapper.java +++ b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/node/ConfigNodeWrapper.java @@ -20,6 +20,7 @@ package org.apache.iotdb.it.env.cluster.node; import org.apache.iotdb.commons.conf.IoTDBConstant; +import org.apache.iotdb.confignode.conf.ConfigNodeConstant; import org.apache.iotdb.it.env.cluster.EnvUtils; import org.apache.iotdb.it.env.cluster.config.MppBaseConfig; import org.apache.iotdb.it.env.cluster.config.MppJVMConfig; @@ -37,7 +38,6 @@ import static org.apache.iotdb.it.env.cluster.ClusterConstant.CONFIG_NODE_INIT_HEAP_SIZE; import static org.apache.iotdb.it.env.cluster.ClusterConstant.CONFIG_NODE_MAX_DIRECT_MEMORY_SIZE; import static org.apache.iotdb.it.env.cluster.ClusterConstant.CONFIG_NODE_MAX_HEAP_SIZE; -import static org.apache.iotdb.it.env.cluster.ClusterConstant.CONFIG_NODE_SYSTEM_PROPERTIES_FILE; import static org.apache.iotdb.it.env.cluster.ClusterConstant.DATA_REGION_CONSENSUS_PROTOCOL_CLASS; import static org.apache.iotdb.it.env.cluster.ClusterConstant.DATA_REPLICATION_FACTOR; import static org.apache.iotdb.it.env.cluster.ClusterConstant.DEFAULT_CONFIG_NODE_COMMON_PROPERTIES; @@ -105,7 +105,7 @@ protected String getDefaultCommonConfigPath() { @Override public String getSystemPropertiesPath() { - return workDirFilePath("data/confignode/system", CONFIG_NODE_SYSTEM_PROPERTIES_FILE); + return workDirFilePath("data/confignode/system", ConfigNodeConstant.SYSTEM_FILE_NAME); } @Override diff --git a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/node/DataNodeWrapper.java b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/node/DataNodeWrapper.java index 1135f5cd055c6..647bd9b9fa003 100644 --- a/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/node/DataNodeWrapper.java +++ b/integration-test/src/main/java/org/apache/iotdb/it/env/cluster/node/DataNodeWrapper.java @@ -20,6 +20,7 @@ package org.apache.iotdb.it.env.cluster.node; import org.apache.iotdb.commons.conf.IoTDBConstant; +import org.apache.iotdb.db.conf.IoTDBStartCheck; import org.apache.iotdb.it.env.cluster.EnvUtils; import org.apache.iotdb.it.env.cluster.config.MppBaseConfig; import org.apache.iotdb.it.env.cluster.config.MppJVMConfig; @@ -61,7 +62,6 @@ import static org.apache.iotdb.it.env.cluster.ClusterConstant.REST_SERVICE_PORT; import static org.apache.iotdb.it.env.cluster.ClusterConstant.SCHEMA_REGION_CONSENSUS_PROTOCOL_CLASS; import static org.apache.iotdb.it.env.cluster.ClusterConstant.SCHEMA_REPLICATION_FACTOR; -import static org.apache.iotdb.it.env.cluster.ClusterConstant.SYSTEM_PROPERTIES_FILE; import static org.apache.iotdb.it.env.cluster.ClusterConstant.TARGET; import static org.apache.iotdb.it.env.cluster.ClusterConstant.USER_DIR; @@ -139,7 +139,7 @@ protected String getDefaultCommonConfigPath() { @Override public String getSystemPropertiesPath() { - return workDirFilePath("data/datanode/system/schema", SYSTEM_PROPERTIES_FILE); + return workDirFilePath("data/datanode/system/schema", IoTDBStartCheck.PROPERTIES_FILE_NAME); } @Override diff --git a/integration-test/src/main/java/org/apache/iotdb/it/env/remote/config/RemoteCommonConfig.java b/integration-test/src/main/java/org/apache/iotdb/it/env/remote/config/RemoteCommonConfig.java index 0ac82fc871373..36675e646865d 100644 --- a/integration-test/src/main/java/org/apache/iotdb/it/env/remote/config/RemoteCommonConfig.java +++ b/integration-test/src/main/java/org/apache/iotdb/it/env/remote/config/RemoteCommonConfig.java @@ -313,4 +313,21 @@ public CommonConfig setTagAttributeTotalSize(int tagAttributeTotalSize) { public CommonConfig setCnConnectionTimeoutMs(int connectionTimeoutMs) { return this; } + + @Override + public CommonConfig setPipeHeartbeatIntervalSecondsForCollectingPipeMeta( + int pipeHeartbeatIntervalSecondsForCollectingPipeMeta) { + return this; + } + + @Override + public CommonConfig setPipeMetaSyncerInitialSyncDelayMinutes( + long pipeMetaSyncerInitialSyncDelayMinutes) { + return this; + } + + @Override + public CommonConfig setPipeMetaSyncerSyncIntervalMinutes(long pipeMetaSyncerSyncIntervalMinutes) { + return this; + } } diff --git a/integration-test/src/main/java/org/apache/iotdb/it/utils/TsFileGenerator.java b/integration-test/src/main/java/org/apache/iotdb/it/utils/TsFileGenerator.java index bf1ec811f8589..e907cf17455a9 100644 --- a/integration-test/src/main/java/org/apache/iotdb/it/utils/TsFileGenerator.java +++ b/integration-test/src/main/java/org/apache/iotdb/it/utils/TsFileGenerator.java @@ -37,6 +37,7 @@ import java.io.File; import java.io.IOException; +import java.time.LocalDate; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -52,7 +53,7 @@ public class TsFileGenerator implements AutoCloseable { private final Map> device2MeasurementSchema; private Random random; - public TsFileGenerator(File tsFile) throws IOException { + public TsFileGenerator(final File tsFile) throws IOException { this.tsFile = tsFile; this.writer = new TsFileWriter(tsFile); this.device2TimeSet = new HashMap<>(); @@ -64,11 +65,12 @@ public void resetRandom() { random = new Random(); } - public void resetRandom(long seed) { + public void resetRandom(final long seed) { random = new Random(seed); } - public void registerTimeseries(String path, List measurementSchemaList) { + public void registerTimeseries( + final String path, final List measurementSchemaList) { if (device2MeasurementSchema.containsKey(path)) { LOGGER.error("Register same device {}.", path); return; @@ -78,7 +80,8 @@ public void registerTimeseries(String path, List measurement device2MeasurementSchema.put(path, measurementSchemaList); } - public void registerAlignedTimeseries(String path, List measurementSchemaList) + public void registerAlignedTimeseries( + final String path, final List measurementSchemaList) throws WriteProcessException { if (device2MeasurementSchema.containsKey(path)) { LOGGER.error("Register same device {}.", path); @@ -89,14 +92,15 @@ public void registerAlignedTimeseries(String path, List meas device2MeasurementSchema.put(path, measurementSchemaList); } - public void generateData(String device, int number, long timeGap, boolean isAligned) + public void generateData( + final String device, final int number, final long timeGap, final boolean isAligned) throws IOException, WriteProcessException { - List schemas = device2MeasurementSchema.get(device); - TreeSet timeSet = device2TimeSet.get(device); - Tablet tablet = new Tablet(device, schemas); - long[] timestamps = tablet.timestamps; - Object[] values = tablet.values; - long sensorNum = schemas.size(); + final List schemas = device2MeasurementSchema.get(device); + final TreeSet timeSet = device2TimeSet.get(device); + final Tablet tablet = new Tablet(device, schemas); + final long[] timestamps = tablet.timestamps; + final Object[] values = tablet.values; + final long sensorNum = schemas.size(); long startTime = timeSet.isEmpty() ? 0L : timeSet.last(); for (long r = 0; r < number; r++) { @@ -131,18 +135,22 @@ public void generateData(String device, int number, long timeGap, boolean isAlig } public void generateData( - String device, int number, long timeGap, boolean isAligned, long startTimestamp) + final String device, + final int number, + final long timeGap, + final boolean isAligned, + final long startTimestamp) throws IOException, WriteProcessException { - List schemas = device2MeasurementSchema.get(device); - TreeSet timeSet = device2TimeSet.get(device); - Tablet tablet = new Tablet(device, schemas); - long[] timestamps = tablet.timestamps; - Object[] values = tablet.values; - long sensorNum = schemas.size(); + final List schemas = device2MeasurementSchema.get(device); + final TreeSet timeSet = device2TimeSet.get(device); + final Tablet tablet = new Tablet(device, schemas); + final long[] timestamps = tablet.timestamps; + final Object[] values = tablet.values; + final long sensorNum = schemas.size(); long startTime = startTimestamp; for (long r = 0; r < number; r++) { - int row = tablet.rowSize++; + final int row = tablet.rowSize++; startTime += timeGap; timestamps[row] = startTime; timeSet.add(startTime); @@ -172,12 +180,16 @@ public void generateData( LOGGER.info("Write {} points into device {}", number, device); } - private void generateDataPoint(Object obj, int row, IMeasurementSchema schema) { + private void generateDataPoint(final Object obj, final int row, final IMeasurementSchema schema) { switch (schema.getType()) { case INT32: generateINT32(obj, row); break; + case DATE: + generateDATE(obj, row); + break; case INT64: + case TIMESTAMP: generateINT64(obj, row); break; case FLOAT: @@ -190,6 +202,8 @@ private void generateDataPoint(Object obj, int row, IMeasurementSchema schema) { generateBOOLEAN(obj, row); break; case TEXT: + case BLOB: + case STRING: generateTEXT(obj, row); break; default: @@ -197,53 +211,60 @@ private void generateDataPoint(Object obj, int row, IMeasurementSchema schema) { } } - private void generateINT32(Object obj, int row) { - int[] ints = (int[]) obj; + private void generateINT32(final Object obj, final int row) { + final int[] ints = (int[]) obj; ints[row] = random.nextInt(); } - private void generateINT64(Object obj, int row) { - long[] longs = (long[]) obj; + private void generateDATE(final Object obj, final int row) { + final LocalDate[] dates = (LocalDate[]) obj; + dates[row] = + LocalDate.of(1000 + random.nextInt(9000), 1 + random.nextInt(12), 1 + random.nextInt(28)); + } + + private void generateINT64(final Object obj, final int row) { + final long[] longs = (long[]) obj; longs[row] = random.nextLong(); } - private void generateFLOAT(Object obj, int row) { - float[] floats = (float[]) obj; + private void generateFLOAT(final Object obj, final int row) { + final float[] floats = (float[]) obj; floats[row] = random.nextFloat(); } - private void generateDOUBLE(Object obj, int row) { - double[] doubles = (double[]) obj; + private void generateDOUBLE(final Object obj, final int row) { + final double[] doubles = (double[]) obj; doubles[row] = random.nextDouble(); } - private void generateBOOLEAN(Object obj, int row) { - boolean[] booleans = (boolean[]) obj; + private void generateBOOLEAN(final Object obj, final int row) { + final boolean[] booleans = (boolean[]) obj; booleans[row] = random.nextBoolean(); } - private void generateTEXT(Object obj, int row) { - Binary[] binaries = (Binary[]) obj; + private void generateTEXT(final Object obj, final int row) { + final Binary[] binaries = (Binary[]) obj; binaries[row] = new Binary(String.format("test point %d", random.nextInt()), TSFileConfig.STRING_CHARSET); } - public void generateDeletion(String device, int number) throws IOException, IllegalPathException { - try (ModificationFile modificationFile = + public void generateDeletion(final String device, final int number) + throws IOException, IllegalPathException { + try (final ModificationFile modificationFile = new ModificationFile(tsFile.getAbsolutePath() + ModificationFile.FILE_SUFFIX)) { writer.flushAllChunkGroups(); - TreeSet timeSet = device2TimeSet.get(device); + final TreeSet timeSet = device2TimeSet.get(device); if (timeSet.isEmpty()) { return; } - long fileOffset = tsFile.length(); - long maxTime = timeSet.last() - 1; + final long fileOffset = tsFile.length(); + final long maxTime = timeSet.last() - 1; for (int i = 0; i < number; i++) { - int endTime = random.nextInt((int) (maxTime)) + 1; - int startTime = random.nextInt(endTime); - for (IMeasurementSchema measurementSchema : device2MeasurementSchema.get(device)) { - Deletion deletion = + final int endTime = random.nextInt((int) (maxTime)) + 1; + final int startTime = random.nextInt(endTime); + for (final IMeasurementSchema measurementSchema : device2MeasurementSchema.get(device)) { + final Deletion deletion = new Deletion( new PartialPath( device diff --git a/integration-test/src/main/java/org/apache/iotdb/itbase/env/BaseNodeWrapper.java b/integration-test/src/main/java/org/apache/iotdb/itbase/env/BaseNodeWrapper.java index cd0eb86bde18c..b0ce0d4a22147 100644 --- a/integration-test/src/main/java/org/apache/iotdb/itbase/env/BaseNodeWrapper.java +++ b/integration-test/src/main/java/org/apache/iotdb/itbase/env/BaseNodeWrapper.java @@ -45,5 +45,19 @@ public interface BaseNodeWrapper { String getIpAndPortString(); - void dumpJVMSnapshot(String testCaseName); + /** + * Perform jstack on the process corresponding to the wrapper, and use logger to output the + * results. + */ + void executeJstack(); + + /** + * Perform jstack on the process corresponding to the wrapper, and output the results to a file in + * the log directory. + * + * @param testCaseName the name of test case + */ + void executeJstack(final String testCaseName); + + long getPid(); } diff --git a/integration-test/src/main/java/org/apache/iotdb/itbase/env/CommonConfig.java b/integration-test/src/main/java/org/apache/iotdb/itbase/env/CommonConfig.java index af47c8254e532..c06c45ddcd42d 100644 --- a/integration-test/src/main/java/org/apache/iotdb/itbase/env/CommonConfig.java +++ b/integration-test/src/main/java/org/apache/iotdb/itbase/env/CommonConfig.java @@ -139,4 +139,11 @@ CommonConfig setEnableAutoLeaderBalanceForIoTConsensus( CommonConfig setTagAttributeTotalSize(int tagAttributeTotalSize); CommonConfig setCnConnectionTimeoutMs(int connectionTimeoutMs); + + CommonConfig setPipeHeartbeatIntervalSecondsForCollectingPipeMeta( + int pipeHeartbeatIntervalSecondsForCollectingPipeMeta); + + CommonConfig setPipeMetaSyncerInitialSyncDelayMinutes(long pipeMetaSyncerInitialSyncDelayMinutes); + + CommonConfig setPipeMetaSyncerSyncIntervalMinutes(long pipeMetaSyncerSyncIntervalMinutes); } diff --git a/integration-test/src/main/java/org/apache/iotdb/itbase/runtime/RequestDelegate.java b/integration-test/src/main/java/org/apache/iotdb/itbase/runtime/RequestDelegate.java index bc32c31e7932e..47f31004e6f28 100644 --- a/integration-test/src/main/java/org/apache/iotdb/itbase/runtime/RequestDelegate.java +++ b/integration-test/src/main/java/org/apache/iotdb/itbase/runtime/RequestDelegate.java @@ -76,14 +76,10 @@ public final void addRequest(Callable request) { */ public final T requestAllAndCompare() throws SQLException { List results = requestAll(); - T data = results.get(0); - for (int i = 1; i < results.size(); i++) { - T anotherData = results.get(i); - if (!compare(data, anotherData)) { - throw new InconsistentDataException(results, endpoints); - } + if (!results.stream().allMatch(result -> compare(results.get(0), result))) { + throw new InconsistentDataException(results, endpoints); } - return data; + return results.get(0); } private boolean compare(T data, T anotherData) { diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/IOTDBLoadTsFileIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBLoadTsFileIT.java similarity index 65% rename from integration-test/src/test/java/org/apache/iotdb/db/it/IOTDBLoadTsFileIT.java rename to integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBLoadTsFileIT.java index 58bfb125147e4..115ba4bfc9035 100644 --- a/integration-test/src/test/java/org/apache/iotdb/db/it/IOTDBLoadTsFileIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBLoadTsFileIT.java @@ -65,8 +65,8 @@ @RunWith(IoTDBTestRunner.class) @Category({LocalStandaloneIT.class, ClusterIT.class}) -public class IOTDBLoadTsFileIT { - private static final Logger LOGGER = LoggerFactory.getLogger(IOTDBLoadTsFileIT.class); +public class IoTDBLoadTsFileIT { + private static final Logger LOGGER = LoggerFactory.getLogger(IoTDBLoadTsFileIT.class); private static final long PARTITION_INTERVAL = 10 * 1000L; private static final int connectionTimeoutInMS = (int) TimeUnit.SECONDS.toMillis(300); private static final long loadTsFileAnalyzeSchemaMemorySizeInBytes = 10 * 1024L; @@ -96,8 +96,8 @@ public void tearDown() throws Exception { } private void registerSchema() throws SQLException { - try (Connection connection = EnvFactory.getEnv().getConnection(); - Statement statement = connection.createStatement()) { + try (final Connection connection = EnvFactory.getEnv().getConnection(); + final Statement statement = connection.createStatement()) { statement.execute("CREATE DATABASE " + SchemaConfig.STORAGE_GROUP_0); statement.execute("CREATE DATABASE " + SchemaConfig.STORAGE_GROUP_1); @@ -114,19 +114,24 @@ private void registerSchema() throws SQLException { SchemaConfig.MEASUREMENT_10, SchemaConfig.MEASUREMENT_11, SchemaConfig.MEASUREMENT_12, - SchemaConfig.MEASUREMENT_13))); + SchemaConfig.MEASUREMENT_13, + SchemaConfig.MEASUREMENT_14, + SchemaConfig.MEASUREMENT_15, + SchemaConfig.MEASUREMENT_16, + SchemaConfig.MEASUREMENT_17))); statement.execute(convert2SQL(SchemaConfig.DEVICE_2, SchemaConfig.MEASUREMENT_20)); statement.execute(convert2SQL(SchemaConfig.DEVICE_3, SchemaConfig.MEASUREMENT_30)); statement.execute( - convert2AlignedSQL(SchemaConfig.DEVICE_4, Arrays.asList(SchemaConfig.MEASUREMENT_40))); + convert2AlignedSQL( + SchemaConfig.DEVICE_4, Collections.singletonList(SchemaConfig.MEASUREMENT_40))); } } - private String convert2SQL(String device, MeasurementSchema schema) { - String sql = + private String convert2SQL(final String device, final MeasurementSchema schema) { + final String sql = String.format( "create timeseries %s %s", new Path(device, schema.getMeasurementId(), true).getFullPath(), @@ -135,10 +140,10 @@ private String convert2SQL(String device, MeasurementSchema schema) { return sql; } - private String convert2AlignedSQL(String device, List schemas) { + private String convert2AlignedSQL(final String device, final List schemas) { String sql = String.format("create aligned timeseries %s(", device); for (int i = 0; i < schemas.size(); i++) { - IMeasurementSchema schema = schemas.get(i); + final IMeasurementSchema schema = schemas.get(i); sql += (String.format("%s %s", schema.getMeasurementId(), schema.getType().name())); sql += (i == schemas.size() - 1 ? ")" : ","); } @@ -147,17 +152,17 @@ private String convert2AlignedSQL(String device, List schema } private void deleteSG() throws SQLException { - try (Connection connection = EnvFactory.getEnv().getConnection(); - Statement statement = connection.createStatement()) { + try (final Connection connection = EnvFactory.getEnv().getConnection(); + final Statement statement = connection.createStatement()) { statement.execute(String.format("delete database %s", SchemaConfig.STORAGE_GROUP_0)); statement.execute(String.format("delete database %s", SchemaConfig.STORAGE_GROUP_1)); - } catch (IoTDBSQLException ignored) { + } catch (final IoTDBSQLException ignored) { } } private boolean deleteDir() { - for (File file : tmpDir.listFiles()) { + for (final File file : tmpDir.listFiles()) { if (!file.delete()) { return false; } @@ -169,49 +174,59 @@ private boolean deleteDir() { public void testLoad() throws Exception { registerSchema(); - long writtenPoint1 = 0; + final long writtenPoint1; // device 0, device 1, sg 0 - try (TsFileGenerator generator = new TsFileGenerator(new File(tmpDir, "1-0-0-0.tsfile"))) { + try (final TsFileGenerator generator = + new TsFileGenerator(new File(tmpDir, "1-0-0-0.tsfile"))) { generator.registerTimeseries( SchemaConfig.DEVICE_0, Arrays.asList( SchemaConfig.MEASUREMENT_00, SchemaConfig.MEASUREMENT_01, SchemaConfig.MEASUREMENT_02, - SchemaConfig.MEASUREMENT_03)); + SchemaConfig.MEASUREMENT_03, + SchemaConfig.MEASUREMENT_04, + SchemaConfig.MEASUREMENT_05, + SchemaConfig.MEASUREMENT_06, + SchemaConfig.MEASUREMENT_07)); generator.registerAlignedTimeseries( SchemaConfig.DEVICE_1, Arrays.asList( SchemaConfig.MEASUREMENT_10, SchemaConfig.MEASUREMENT_11, SchemaConfig.MEASUREMENT_12, - SchemaConfig.MEASUREMENT_13)); + SchemaConfig.MEASUREMENT_13, + SchemaConfig.MEASUREMENT_14, + SchemaConfig.MEASUREMENT_15, + SchemaConfig.MEASUREMENT_16, + SchemaConfig.MEASUREMENT_17)); generator.generateData(SchemaConfig.DEVICE_0, 100000, PARTITION_INTERVAL / 10_000, false); generator.generateData(SchemaConfig.DEVICE_1, 100000, PARTITION_INTERVAL / 10_000, true); writtenPoint1 = generator.getTotalNumber(); } - long writtenPoint2 = 0; + final long writtenPoint2; // device 2, device 3, device4, sg 1 - try (TsFileGenerator generator = new TsFileGenerator(new File(tmpDir, "2-0-0-0.tsfile"))) { + try (final TsFileGenerator generator = + new TsFileGenerator(new File(tmpDir, "2-0-0-0.tsfile"))) { generator.registerTimeseries( - SchemaConfig.DEVICE_2, Arrays.asList(SchemaConfig.MEASUREMENT_20)); + SchemaConfig.DEVICE_2, Collections.singletonList(SchemaConfig.MEASUREMENT_20)); generator.registerTimeseries( - SchemaConfig.DEVICE_3, Arrays.asList(SchemaConfig.MEASUREMENT_30)); + SchemaConfig.DEVICE_3, Collections.singletonList(SchemaConfig.MEASUREMENT_30)); generator.registerAlignedTimeseries( - SchemaConfig.DEVICE_4, Arrays.asList(SchemaConfig.MEASUREMENT_40)); + SchemaConfig.DEVICE_4, Collections.singletonList(SchemaConfig.MEASUREMENT_40)); generator.generateData(SchemaConfig.DEVICE_2, 10000, PARTITION_INTERVAL / 10_000, false); generator.generateData(SchemaConfig.DEVICE_3, 10000, PARTITION_INTERVAL / 10_000, false); generator.generateData(SchemaConfig.DEVICE_4, 10000, PARTITION_INTERVAL / 10_000, true); writtenPoint2 = generator.getTotalNumber(); } - try (Connection connection = EnvFactory.getEnv().getConnection(); - Statement statement = connection.createStatement()) { + try (final Connection connection = EnvFactory.getEnv().getConnection(); + final Statement statement = connection.createStatement()) { statement.execute(String.format("load \"%s\" sglevel=2", tmpDir.getAbsolutePath())); - try (ResultSet resultSet = + try (final ResultSet resultSet = statement.executeQuery("select count(*) from root.** group by level=1,2")) { if (resultSet.next()) { long sg1Count = resultSet.getLong("count(root.sg.test_0.*.*)"); @@ -224,9 +239,9 @@ public void testLoad() throws Exception { } } - // try delete after loading. Expect no deadlock - try (Connection connection = EnvFactory.getEnv().getConnection(); - Statement statement = connection.createStatement()) { + // Try to delete after loading. Expect no deadlock + try (final Connection connection = EnvFactory.getEnv().getConnection(); + final Statement statement = connection.createStatement()) { statement.execute( String.format( "delete timeseries %s.%s", @@ -236,29 +251,38 @@ public void testLoad() throws Exception { @Test public void testLoadWithExtendTemplate() throws Exception { - long writtenPoint1 = 0; + final long writtenPoint1; // device 0, device 1, sg 0 - try (TsFileGenerator generator = new TsFileGenerator(new File(tmpDir, "1-0-0-0.tsfile"))) { + try (final TsFileGenerator generator = + new TsFileGenerator(new File(tmpDir, "1-0-0-0.tsfile"))) { generator.registerTimeseries( SchemaConfig.DEVICE_0, Arrays.asList( SchemaConfig.MEASUREMENT_00, SchemaConfig.MEASUREMENT_01, SchemaConfig.MEASUREMENT_02, - SchemaConfig.MEASUREMENT_03)); + SchemaConfig.MEASUREMENT_03, + SchemaConfig.MEASUREMENT_04, + SchemaConfig.MEASUREMENT_05, + SchemaConfig.MEASUREMENT_06, + SchemaConfig.MEASUREMENT_07)); generator.registerAlignedTimeseries( SchemaConfig.DEVICE_1, Arrays.asList( SchemaConfig.MEASUREMENT_10, SchemaConfig.MEASUREMENT_11, SchemaConfig.MEASUREMENT_12, - SchemaConfig.MEASUREMENT_13)); + SchemaConfig.MEASUREMENT_13, + SchemaConfig.MEASUREMENT_14, + SchemaConfig.MEASUREMENT_15, + SchemaConfig.MEASUREMENT_16, + SchemaConfig.MEASUREMENT_17)); generator.generateData(SchemaConfig.DEVICE_0, 10000, PARTITION_INTERVAL / 10_000, false); generator.generateData(SchemaConfig.DEVICE_1, 10000, PARTITION_INTERVAL / 10_000, true); writtenPoint1 = generator.getTotalNumber(); } - try (Connection connection = EnvFactory.getEnv().getConnection(); - Statement statement = connection.createStatement()) { + try (final Connection connection = EnvFactory.getEnv().getConnection(); + final Statement statement = connection.createStatement()) { statement.execute("create database root.sg.test_0"); statement.execute( @@ -267,17 +291,17 @@ public void testLoadWithExtendTemplate() throws Exception { statement.execute(String.format("load \"%s\" sglevel=2", tmpDir.getAbsolutePath())); - try (ResultSet resultSet = + try (final ResultSet resultSet = statement.executeQuery("select count(*) from root.** group by level=1,2")) { if (resultSet.next()) { - long sg1Count = resultSet.getLong("count(root.sg.test_0.*.*)"); + final long sg1Count = resultSet.getLong("count(root.sg.test_0.*.*)"); Assert.assertEquals(writtenPoint1, sg1Count); } else { Assert.fail("This ResultSet is empty."); } } - Set nodes = + final Set nodes = new HashSet<>( Arrays.asList( "lat", @@ -285,14 +309,18 @@ public void testLoadWithExtendTemplate() throws Exception { SchemaConfig.MEASUREMENT_00.getMeasurementId(), SchemaConfig.MEASUREMENT_01.getMeasurementId(), SchemaConfig.MEASUREMENT_02.getMeasurementId(), - SchemaConfig.MEASUREMENT_03.getMeasurementId())); - try (ResultSet resultSet = statement.executeQuery("show nodes in schema template t1")) { + SchemaConfig.MEASUREMENT_03.getMeasurementId(), + SchemaConfig.MEASUREMENT_04.getMeasurementId(), + SchemaConfig.MEASUREMENT_05.getMeasurementId(), + SchemaConfig.MEASUREMENT_06.getMeasurementId(), + SchemaConfig.MEASUREMENT_07.getMeasurementId())); + try (final ResultSet resultSet = statement.executeQuery("show nodes in schema template t1")) { while (resultSet.next()) { String device = resultSet.getString(ColumnHeaderConstant.CHILD_NODES); Assert.assertTrue(nodes.remove(device)); } Assert.assertTrue(nodes.isEmpty()); - } catch (Exception e) { + } catch (final Exception e) { e.printStackTrace(); Assert.fail("Parse result set error."); } @@ -301,67 +329,77 @@ public void testLoadWithExtendTemplate() throws Exception { @Test public void testLoadWithAutoRegister() throws Exception { - long writtenPoint1 = 0; + final long writtenPoint1; // device 0, device 1, sg 0 - try (TsFileGenerator generator = new TsFileGenerator(new File(tmpDir, "1-0-0-0.tsfile"))) { + try (final TsFileGenerator generator = + new TsFileGenerator(new File(tmpDir, "1-0-0-0.tsfile"))) { generator.registerTimeseries( SchemaConfig.DEVICE_0, Arrays.asList( SchemaConfig.MEASUREMENT_00, SchemaConfig.MEASUREMENT_01, SchemaConfig.MEASUREMENT_02, - SchemaConfig.MEASUREMENT_03)); + SchemaConfig.MEASUREMENT_03, + SchemaConfig.MEASUREMENT_04, + SchemaConfig.MEASUREMENT_05, + SchemaConfig.MEASUREMENT_06, + SchemaConfig.MEASUREMENT_07)); generator.registerAlignedTimeseries( SchemaConfig.DEVICE_1, Arrays.asList( SchemaConfig.MEASUREMENT_10, SchemaConfig.MEASUREMENT_11, SchemaConfig.MEASUREMENT_12, - SchemaConfig.MEASUREMENT_13)); + SchemaConfig.MEASUREMENT_13, + SchemaConfig.MEASUREMENT_14, + SchemaConfig.MEASUREMENT_15, + SchemaConfig.MEASUREMENT_16, + SchemaConfig.MEASUREMENT_17)); generator.generateData(SchemaConfig.DEVICE_0, 10000, PARTITION_INTERVAL / 10_000, false); generator.generateData(SchemaConfig.DEVICE_1, 10000, PARTITION_INTERVAL / 10_000, true); writtenPoint1 = generator.getTotalNumber(); } - long writtenPoint2 = 0; + final long writtenPoint2; // device 2, device 3, device4, sg 1 - try (TsFileGenerator generator = new TsFileGenerator(new File(tmpDir, "2-0-0-0.tsfile"))) { + try (final TsFileGenerator generator = + new TsFileGenerator(new File(tmpDir, "2-0-0-0.tsfile"))) { generator.registerTimeseries( - SchemaConfig.DEVICE_2, Arrays.asList(SchemaConfig.MEASUREMENT_20)); + SchemaConfig.DEVICE_2, Collections.singletonList(SchemaConfig.MEASUREMENT_20)); generator.registerTimeseries( - SchemaConfig.DEVICE_3, Arrays.asList(SchemaConfig.MEASUREMENT_30)); + SchemaConfig.DEVICE_3, Collections.singletonList(SchemaConfig.MEASUREMENT_30)); generator.registerAlignedTimeseries( - SchemaConfig.DEVICE_4, Arrays.asList(SchemaConfig.MEASUREMENT_40)); + SchemaConfig.DEVICE_4, Collections.singletonList(SchemaConfig.MEASUREMENT_40)); generator.generateData(SchemaConfig.DEVICE_2, 10000, PARTITION_INTERVAL / 10_000, false); generator.generateData(SchemaConfig.DEVICE_3, 10000, PARTITION_INTERVAL / 10_000, false); generator.generateData(SchemaConfig.DEVICE_4, 10000, PARTITION_INTERVAL / 10_000, true); writtenPoint2 = generator.getTotalNumber(); } - try (Connection connection = EnvFactory.getEnv().getConnection(); - Statement statement = connection.createStatement()) { + try (final Connection connection = EnvFactory.getEnv().getConnection(); + final Statement statement = connection.createStatement()) { statement.execute(String.format("load \"%s\" sglevel=2", tmpDir.getAbsolutePath())); - try (ResultSet resultSet = + try (final ResultSet resultSet = statement.executeQuery("select count(*) from root.** group by level=1,2")) { if (resultSet.next()) { - long sg1Count = resultSet.getLong("count(root.sg.test_0.*.*)"); + final long sg1Count = resultSet.getLong("count(root.sg.test_0.*.*)"); Assert.assertEquals(writtenPoint1, sg1Count); - long sg2Count = resultSet.getLong("count(root.sg.test_1.*.*)"); + final long sg2Count = resultSet.getLong("count(root.sg.test_1.*.*)"); Assert.assertEquals(writtenPoint2, sg2Count); } else { Assert.fail("This ResultSet is empty."); } } - Map isAligned = new HashMap<>(); + final Map isAligned = new HashMap<>(); isAligned.put(SchemaConfig.DEVICE_0, "false"); isAligned.put(SchemaConfig.DEVICE_1, "true"); isAligned.put(SchemaConfig.DEVICE_2, "false"); isAligned.put(SchemaConfig.DEVICE_3, "false"); isAligned.put(SchemaConfig.DEVICE_4, "true"); - try (ResultSet resultSet = statement.executeQuery("show devices")) { + try (final ResultSet resultSet = statement.executeQuery("show devices")) { int size = 0; while (resultSet.next()) { size += 1; @@ -370,7 +408,7 @@ public void testLoadWithAutoRegister() throws Exception { isAligned.get(device), resultSet.getString(ColumnHeaderConstant.IS_ALIGNED)); } Assert.assertEquals(isAligned.size(), size); - } catch (Exception e) { + } catch (final Exception e) { e.printStackTrace(); Assert.fail("Parse result set error."); } @@ -382,33 +420,43 @@ public void testAuth() throws Exception { createUser("test", "test123"); // device 0, device 1, sg 0 - try (TsFileGenerator generator = new TsFileGenerator(new File(tmpDir, "test1-0-0-0.tsfile"))) { + try (final TsFileGenerator generator = + new TsFileGenerator(new File(tmpDir, "test1-0-0-0.tsfile"))) { generator.registerTimeseries( SchemaConfig.DEVICE_0, Arrays.asList( SchemaConfig.MEASUREMENT_00, SchemaConfig.MEASUREMENT_01, SchemaConfig.MEASUREMENT_02, - SchemaConfig.MEASUREMENT_03)); + SchemaConfig.MEASUREMENT_03, + SchemaConfig.MEASUREMENT_04, + SchemaConfig.MEASUREMENT_05, + SchemaConfig.MEASUREMENT_06, + SchemaConfig.MEASUREMENT_07)); generator.registerAlignedTimeseries( SchemaConfig.DEVICE_1, Arrays.asList( SchemaConfig.MEASUREMENT_10, SchemaConfig.MEASUREMENT_11, SchemaConfig.MEASUREMENT_12, - SchemaConfig.MEASUREMENT_13)); + SchemaConfig.MEASUREMENT_13, + SchemaConfig.MEASUREMENT_14, + SchemaConfig.MEASUREMENT_15, + SchemaConfig.MEASUREMENT_16, + SchemaConfig.MEASUREMENT_17)); generator.generateData(SchemaConfig.DEVICE_0, 10000, PARTITION_INTERVAL / 10_000, false); generator.generateData(SchemaConfig.DEVICE_1, 10000, PARTITION_INTERVAL / 10_000, true); } // device 2, device 3, device4, sg 1 - try (TsFileGenerator generator = new TsFileGenerator(new File(tmpDir, "test2-0-0-0.tsfile"))) { + try (final TsFileGenerator generator = + new TsFileGenerator(new File(tmpDir, "test2-0-0-0.tsfile"))) { generator.registerTimeseries( - SchemaConfig.DEVICE_2, Arrays.asList(SchemaConfig.MEASUREMENT_20)); + SchemaConfig.DEVICE_2, Collections.singletonList(SchemaConfig.MEASUREMENT_20)); generator.registerTimeseries( - SchemaConfig.DEVICE_3, Arrays.asList(SchemaConfig.MEASUREMENT_30)); + SchemaConfig.DEVICE_3, Collections.singletonList(SchemaConfig.MEASUREMENT_30)); generator.registerAlignedTimeseries( - SchemaConfig.DEVICE_4, Arrays.asList(SchemaConfig.MEASUREMENT_40)); + SchemaConfig.DEVICE_4, Collections.singletonList(SchemaConfig.MEASUREMENT_40)); generator.generateData(SchemaConfig.DEVICE_2, 10000, PARTITION_INTERVAL / 10_000, false); generator.generateData(SchemaConfig.DEVICE_3, 10000, PARTITION_INTERVAL / 10_000, false); generator.generateData(SchemaConfig.DEVICE_4, 10000, PARTITION_INTERVAL / 10_000, true); @@ -444,33 +492,41 @@ public void testAuth() throws Exception { @Test public void testLoadWithOnSuccess() throws Exception { - File file1 = new File(tmpDir, "1-0-0-0.tsfile"); - File file2 = new File(tmpDir, "2-0-0-0.tsfile"); + final File file1 = new File(tmpDir, "1-0-0-0.tsfile"); + final File file2 = new File(tmpDir, "2-0-0-0.tsfile"); long writtenPoint1 = 0; // device 0, device 1, sg 0 - try (TsFileGenerator generator = new TsFileGenerator(file1)) { + try (final TsFileGenerator generator = new TsFileGenerator(file1)) { generator.registerTimeseries( SchemaConfig.DEVICE_0, Arrays.asList( SchemaConfig.MEASUREMENT_00, SchemaConfig.MEASUREMENT_01, SchemaConfig.MEASUREMENT_02, - SchemaConfig.MEASUREMENT_03)); + SchemaConfig.MEASUREMENT_03, + SchemaConfig.MEASUREMENT_04, + SchemaConfig.MEASUREMENT_05, + SchemaConfig.MEASUREMENT_06, + SchemaConfig.MEASUREMENT_07)); generator.registerAlignedTimeseries( SchemaConfig.DEVICE_1, Arrays.asList( SchemaConfig.MEASUREMENT_10, SchemaConfig.MEASUREMENT_11, SchemaConfig.MEASUREMENT_12, - SchemaConfig.MEASUREMENT_13)); + SchemaConfig.MEASUREMENT_13, + SchemaConfig.MEASUREMENT_14, + SchemaConfig.MEASUREMENT_15, + SchemaConfig.MEASUREMENT_16, + SchemaConfig.MEASUREMENT_17)); generator.generateData(SchemaConfig.DEVICE_0, 10000, PARTITION_INTERVAL / 10_000, false); generator.generateData(SchemaConfig.DEVICE_1, 10000, PARTITION_INTERVAL / 10_000, true); writtenPoint1 = generator.getTotalNumber(); } - long writtenPoint2 = 0; + final long writtenPoint2; // device 2, device 3, device4, sg 1 - try (TsFileGenerator generator = new TsFileGenerator(file2)) { + try (final TsFileGenerator generator = new TsFileGenerator(file2)) { generator.registerTimeseries( SchemaConfig.DEVICE_2, Arrays.asList(SchemaConfig.MEASUREMENT_20)); generator.registerTimeseries( @@ -483,16 +539,16 @@ public void testLoadWithOnSuccess() throws Exception { writtenPoint2 = generator.getTotalNumber(); } - try (Connection connection = EnvFactory.getEnv().getConnection(); - Statement statement = connection.createStatement()) { + try (final Connection connection = EnvFactory.getEnv().getConnection(); + final Statement statement = connection.createStatement()) { statement.execute( String.format("load \"%s\" sglevel=2 onSuccess=none", file1.getAbsolutePath())); - try (ResultSet resultSet = + try (final ResultSet resultSet = statement.executeQuery("select count(*) from root.** group by level=1,2")) { if (resultSet.next()) { - long sg1Count = resultSet.getLong("count(root.sg.test_0.*.*)"); + final long sg1Count = resultSet.getLong("count(root.sg.test_0.*.*)"); Assert.assertEquals(writtenPoint1, sg1Count); } else { Assert.fail("This ResultSet is empty."); @@ -501,13 +557,13 @@ public void testLoadWithOnSuccess() throws Exception { Assert.assertTrue(file1.exists()); } - try (Connection connection = EnvFactory.getEnv().getConnection(); - Statement statement = connection.createStatement()) { + try (final Connection connection = EnvFactory.getEnv().getConnection(); + final Statement statement = connection.createStatement()) { statement.execute( String.format("load \"%s\" sglevel=2 onSuccess=delete", file2.getAbsolutePath())); - try (ResultSet resultSet = + try (final ResultSet resultSet = statement.executeQuery("select count(*) from root.** group by level=1,2")) { if (resultSet.next()) { long sg1Count = resultSet.getLong("count(root.sg.test_0.*.*)"); @@ -526,19 +582,19 @@ public void testLoadWithOnSuccess() throws Exception { public void testLoadWithLastCache() throws Exception { registerSchema(); - String device = SchemaConfig.DEVICE_0; - String measurement = SchemaConfig.MEASUREMENT_00.getMeasurementId(); + final String device = SchemaConfig.DEVICE_0; + final String measurement = SchemaConfig.MEASUREMENT_00.getMeasurementId(); - try (Connection connection = EnvFactory.getEnv().getConnection(); - Statement statement = connection.createStatement()) { + try (final Connection connection = EnvFactory.getEnv().getConnection(); + final Statement statement = connection.createStatement()) { statement.execute( String.format("insert into %s(timestamp, %s) values(100, 100)", device, measurement)); - try (ResultSet resultSet = + try (final ResultSet resultSet = statement.executeQuery(String.format("select last %s from %s", measurement, device))) { if (resultSet.next()) { - String lastValue = resultSet.getString(ColumnHeaderConstant.VALUE); + final String lastValue = resultSet.getString(ColumnHeaderConstant.VALUE); Assert.assertEquals("100", lastValue); } else { Assert.fail("This ResultSet is empty."); @@ -546,50 +602,58 @@ public void testLoadWithLastCache() throws Exception { } } - File file1 = new File(tmpDir, "1-0-0-0.tsfile"); - File file2 = new File(tmpDir, "2-0-0-0.tsfile"); + final File file1 = new File(tmpDir, "1-0-0-0.tsfile"); + final File file2 = new File(tmpDir, "2-0-0-0.tsfile"); // device 0, device 1, sg 0 - try (TsFileGenerator generator = new TsFileGenerator(file1)) { + try (final TsFileGenerator generator = new TsFileGenerator(file1)) { generator.registerTimeseries( SchemaConfig.DEVICE_0, Arrays.asList( SchemaConfig.MEASUREMENT_00, SchemaConfig.MEASUREMENT_01, SchemaConfig.MEASUREMENT_02, - SchemaConfig.MEASUREMENT_03)); + SchemaConfig.MEASUREMENT_03, + SchemaConfig.MEASUREMENT_04, + SchemaConfig.MEASUREMENT_05, + SchemaConfig.MEASUREMENT_06, + SchemaConfig.MEASUREMENT_07)); generator.registerAlignedTimeseries( SchemaConfig.DEVICE_1, Arrays.asList( SchemaConfig.MEASUREMENT_10, SchemaConfig.MEASUREMENT_11, SchemaConfig.MEASUREMENT_12, - SchemaConfig.MEASUREMENT_13)); + SchemaConfig.MEASUREMENT_13, + SchemaConfig.MEASUREMENT_14, + SchemaConfig.MEASUREMENT_15, + SchemaConfig.MEASUREMENT_16, + SchemaConfig.MEASUREMENT_17)); generator.generateData(SchemaConfig.DEVICE_0, 10000, PARTITION_INTERVAL / 10_000, false); generator.generateData(SchemaConfig.DEVICE_1, 10000, PARTITION_INTERVAL / 10_000, true); } // device 2, device 3, device4, sg 1 - try (TsFileGenerator generator = new TsFileGenerator(file2)) { + try (final TsFileGenerator generator = new TsFileGenerator(file2)) { generator.registerTimeseries( - SchemaConfig.DEVICE_2, Arrays.asList(SchemaConfig.MEASUREMENT_20)); + SchemaConfig.DEVICE_2, Collections.singletonList(SchemaConfig.MEASUREMENT_20)); generator.registerTimeseries( - SchemaConfig.DEVICE_3, Arrays.asList(SchemaConfig.MEASUREMENT_30)); + SchemaConfig.DEVICE_3, Collections.singletonList(SchemaConfig.MEASUREMENT_30)); generator.registerAlignedTimeseries( - SchemaConfig.DEVICE_4, Arrays.asList(SchemaConfig.MEASUREMENT_40)); + SchemaConfig.DEVICE_4, Collections.singletonList(SchemaConfig.MEASUREMENT_40)); generator.generateData(SchemaConfig.DEVICE_2, 10000, PARTITION_INTERVAL / 10_000, false); generator.generateData(SchemaConfig.DEVICE_3, 10000, PARTITION_INTERVAL / 10_000, false); generator.generateData(SchemaConfig.DEVICE_4, 10000, PARTITION_INTERVAL / 10_000, true); } - try (Connection connection = EnvFactory.getEnv().getConnection(); - Statement statement = connection.createStatement()) { + try (final Connection connection = EnvFactory.getEnv().getConnection(); + final Statement statement = connection.createStatement()) { statement.execute(String.format("load \"%s\" sglevel=2", tmpDir.getAbsolutePath())); - try (ResultSet resultSet = + try (final ResultSet resultSet = statement.executeQuery(String.format("select last %s from %s", measurement, device))) { if (resultSet.next()) { - String lastTime = resultSet.getString(ColumnHeaderConstant.TIME); + final String lastTime = resultSet.getString(ColumnHeaderConstant.TIME); Assert.assertEquals(String.valueOf(PARTITION_INTERVAL), lastTime); } else { Assert.fail("This ResultSet is empty."); @@ -600,56 +664,64 @@ public void testLoadWithLastCache() throws Exception { @Test public void testLoadWithOnNonStandardTsFileName() throws Exception { - File file1 = new File(tmpDir, "1-0-0-0.tsfile"); - File file2 = new File(tmpDir, "a-1.tsfile"); - long writtenPoint1 = 0; + final File file1 = new File(tmpDir, "1-0-0-0.tsfile"); + final File file2 = new File(tmpDir, "a-1.tsfile"); + final long writtenPoint1; // device 0, device 1, sg 0 - try (TsFileGenerator generator = new TsFileGenerator(file1)) { + try (final TsFileGenerator generator = new TsFileGenerator(file1)) { generator.registerTimeseries( SchemaConfig.DEVICE_0, Arrays.asList( SchemaConfig.MEASUREMENT_00, SchemaConfig.MEASUREMENT_01, SchemaConfig.MEASUREMENT_02, - SchemaConfig.MEASUREMENT_03)); + SchemaConfig.MEASUREMENT_03, + SchemaConfig.MEASUREMENT_04, + SchemaConfig.MEASUREMENT_05, + SchemaConfig.MEASUREMENT_06, + SchemaConfig.MEASUREMENT_07)); generator.registerAlignedTimeseries( SchemaConfig.DEVICE_1, Arrays.asList( SchemaConfig.MEASUREMENT_10, SchemaConfig.MEASUREMENT_11, SchemaConfig.MEASUREMENT_12, - SchemaConfig.MEASUREMENT_13)); + SchemaConfig.MEASUREMENT_13, + SchemaConfig.MEASUREMENT_14, + SchemaConfig.MEASUREMENT_15, + SchemaConfig.MEASUREMENT_16, + SchemaConfig.MEASUREMENT_17)); generator.generateData(SchemaConfig.DEVICE_0, 10000, PARTITION_INTERVAL / 10_000, false); generator.generateData(SchemaConfig.DEVICE_1, 10000, PARTITION_INTERVAL / 10_000, true); writtenPoint1 = generator.getTotalNumber(); } - long writtenPoint2 = 0; + final long writtenPoint2; // device 2, device 3, device4, sg 1 - try (TsFileGenerator generator = new TsFileGenerator(file2)) { + try (final TsFileGenerator generator = new TsFileGenerator(file2)) { generator.registerTimeseries( - SchemaConfig.DEVICE_2, Arrays.asList(SchemaConfig.MEASUREMENT_20)); + SchemaConfig.DEVICE_2, Collections.singletonList(SchemaConfig.MEASUREMENT_20)); generator.registerTimeseries( - SchemaConfig.DEVICE_3, Arrays.asList(SchemaConfig.MEASUREMENT_30)); + SchemaConfig.DEVICE_3, Collections.singletonList(SchemaConfig.MEASUREMENT_30)); generator.registerAlignedTimeseries( - SchemaConfig.DEVICE_4, Arrays.asList(SchemaConfig.MEASUREMENT_40)); + SchemaConfig.DEVICE_4, Collections.singletonList(SchemaConfig.MEASUREMENT_40)); generator.generateData(SchemaConfig.DEVICE_2, 10000, PARTITION_INTERVAL / 10_000, false); generator.generateData(SchemaConfig.DEVICE_3, 10000, PARTITION_INTERVAL / 10_000, false); generator.generateData(SchemaConfig.DEVICE_4, 10000, PARTITION_INTERVAL / 10_000, true); writtenPoint2 = generator.getTotalNumber(); } - try (Connection connection = EnvFactory.getEnv().getConnection(); - Statement statement = connection.createStatement()) { + try (final Connection connection = EnvFactory.getEnv().getConnection(); + final Statement statement = connection.createStatement()) { statement.execute(String.format("load \"%s\" sglevel=2", tmpDir.getAbsolutePath())); - try (ResultSet resultSet = + try (final ResultSet resultSet = statement.executeQuery("select count(*) from root.** group by level=1,2")) { if (resultSet.next()) { - long sg1Count = resultSet.getLong("count(root.sg.test_0.*.*)"); + final long sg1Count = resultSet.getLong("count(root.sg.test_0.*.*)"); Assert.assertEquals(writtenPoint1, sg1Count); - long sg2Count = resultSet.getLong("count(root.sg.test_1.*.*)"); + final long sg2Count = resultSet.getLong("count(root.sg.test_1.*.*)"); Assert.assertEquals(writtenPoint2, sg2Count); } else { Assert.fail("This ResultSet is empty."); @@ -660,23 +732,32 @@ public void testLoadWithOnNonStandardTsFileName() throws Exception { @Test public void testLoadWithMods() throws Exception { - long writtenPoint1 = 0; + final long writtenPoint1; // device 0, device 1, sg 0 - try (TsFileGenerator generator = new TsFileGenerator(new File(tmpDir, "1-0-0-0.tsfile"))) { + try (final TsFileGenerator generator = + new TsFileGenerator(new File(tmpDir, "1-0-0-0.tsfile"))) { generator.registerTimeseries( SchemaConfig.DEVICE_0, Arrays.asList( SchemaConfig.MEASUREMENT_00, SchemaConfig.MEASUREMENT_01, SchemaConfig.MEASUREMENT_02, - SchemaConfig.MEASUREMENT_03)); + SchemaConfig.MEASUREMENT_03, + SchemaConfig.MEASUREMENT_04, + SchemaConfig.MEASUREMENT_05, + SchemaConfig.MEASUREMENT_06, + SchemaConfig.MEASUREMENT_07)); generator.registerAlignedTimeseries( SchemaConfig.DEVICE_1, Arrays.asList( SchemaConfig.MEASUREMENT_10, SchemaConfig.MEASUREMENT_11, SchemaConfig.MEASUREMENT_12, - SchemaConfig.MEASUREMENT_13)); + SchemaConfig.MEASUREMENT_13, + SchemaConfig.MEASUREMENT_14, + SchemaConfig.MEASUREMENT_15, + SchemaConfig.MEASUREMENT_16, + SchemaConfig.MEASUREMENT_17)); generator.generateData(SchemaConfig.DEVICE_0, 100000, PARTITION_INTERVAL / 10_000, false); generator.generateData(SchemaConfig.DEVICE_1, 100000, PARTITION_INTERVAL / 10_000, true); generator.generateDeletion(SchemaConfig.DEVICE_0, 10); @@ -684,16 +765,17 @@ public void testLoadWithMods() throws Exception { writtenPoint1 = generator.getTotalNumber(); } - long writtenPoint2 = 0; + final long writtenPoint2; // device 2, device 3, device4, sg 1 - try (TsFileGenerator generator = new TsFileGenerator(new File(tmpDir, "2-0-0-0.tsfile"))) { + try (final TsFileGenerator generator = + new TsFileGenerator(new File(tmpDir, "2-0-0-0.tsfile"))) { generator.resetRandom(1000); generator.registerTimeseries( - SchemaConfig.DEVICE_2, Arrays.asList(SchemaConfig.MEASUREMENT_20)); + SchemaConfig.DEVICE_2, Collections.singletonList(SchemaConfig.MEASUREMENT_20)); generator.registerTimeseries( - SchemaConfig.DEVICE_3, Arrays.asList(SchemaConfig.MEASUREMENT_30)); + SchemaConfig.DEVICE_3, Collections.singletonList(SchemaConfig.MEASUREMENT_30)); generator.registerAlignedTimeseries( - SchemaConfig.DEVICE_4, Arrays.asList(SchemaConfig.MEASUREMENT_40)); + SchemaConfig.DEVICE_4, Collections.singletonList(SchemaConfig.MEASUREMENT_40)); generator.generateData(SchemaConfig.DEVICE_2, 100, PARTITION_INTERVAL / 10_000, false); generator.generateData(SchemaConfig.DEVICE_3, 100, PARTITION_INTERVAL / 10_000, false); generator.generateData(SchemaConfig.DEVICE_4, 100, PARTITION_INTERVAL / 10_000, true); @@ -706,17 +788,17 @@ public void testLoadWithMods() throws Exception { writtenPoint2 = generator.getTotalNumber(); } - try (Connection connection = EnvFactory.getEnv().getConnection(); - Statement statement = connection.createStatement()) { + try (final Connection connection = EnvFactory.getEnv().getConnection(); + final Statement statement = connection.createStatement()) { statement.execute(String.format("load \"%s\" sglevel=2", tmpDir.getAbsolutePath())); - try (ResultSet resultSet = + try (final ResultSet resultSet = statement.executeQuery("select count(*) from root.** group by level=1,2")) { if (resultSet.next()) { - long sg1Count = resultSet.getLong("count(root.sg.test_0.*.*)"); + final long sg1Count = resultSet.getLong("count(root.sg.test_0.*.*)"); Assert.assertEquals(writtenPoint1, sg1Count); - long sg2Count = resultSet.getLong("count(root.sg.test_1.*.*)"); + final long sg2Count = resultSet.getLong("count(root.sg.test_1.*.*)"); Assert.assertEquals(writtenPoint2, sg2Count); } else { Assert.fail("This ResultSet is empty."); @@ -727,14 +809,14 @@ public void testLoadWithMods() throws Exception { @Test public void testLoadWithEmptyTsFile() throws Exception { - try (TsFileGenerator ignored = new TsFileGenerator(new File(tmpDir, "1-0-0-0.tsfile"))) {} + try (final TsFileGenerator ignored = new TsFileGenerator(new File(tmpDir, "1-0-0-0.tsfile"))) {} - try (Connection connection = EnvFactory.getEnv().getConnection(); + try (final Connection connection = EnvFactory.getEnv().getConnection(); Statement statement = connection.createStatement()) { statement.execute(String.format("load \"%s\"", tmpDir.getAbsolutePath())); - try (ResultSet resultSet = statement.executeQuery("show timeseries")) { + try (final ResultSet resultSet = statement.executeQuery("show timeseries")) { Assert.assertFalse(resultSet.next()); } } @@ -742,21 +824,30 @@ public void testLoadWithEmptyTsFile() throws Exception { @Test public void testLoadTsFileWithWrongTimestampPrecision() throws Exception { - try (TsFileGenerator generator = new TsFileGenerator(new File(tmpDir, "1-0-0-0.tsfile"))) { + try (final TsFileGenerator generator = + new TsFileGenerator(new File(tmpDir, "1-0-0-0.tsfile"))) { generator.registerTimeseries( SchemaConfig.DEVICE_0, Arrays.asList( SchemaConfig.MEASUREMENT_00, SchemaConfig.MEASUREMENT_01, SchemaConfig.MEASUREMENT_02, - SchemaConfig.MEASUREMENT_03)); + SchemaConfig.MEASUREMENT_03, + SchemaConfig.MEASUREMENT_04, + SchemaConfig.MEASUREMENT_05, + SchemaConfig.MEASUREMENT_06, + SchemaConfig.MEASUREMENT_07)); generator.registerAlignedTimeseries( SchemaConfig.DEVICE_1, Arrays.asList( SchemaConfig.MEASUREMENT_10, SchemaConfig.MEASUREMENT_11, SchemaConfig.MEASUREMENT_12, - SchemaConfig.MEASUREMENT_13)); + SchemaConfig.MEASUREMENT_13, + SchemaConfig.MEASUREMENT_14, + SchemaConfig.MEASUREMENT_15, + SchemaConfig.MEASUREMENT_16, + SchemaConfig.MEASUREMENT_17)); // generate ns timestamp generator.generateData( SchemaConfig.DEVICE_0, 100000, PARTITION_INTERVAL / 10_000, false, 1694689856546000000L); @@ -764,11 +855,11 @@ public void testLoadTsFileWithWrongTimestampPrecision() throws Exception { SchemaConfig.DEVICE_1, 100000, PARTITION_INTERVAL / 10_000, true, 1694689856546000000L); } - try (Connection connection = EnvFactory.getEnv().getConnection(); - Statement statement = connection.createStatement()) { + try (final Connection connection = EnvFactory.getEnv().getConnection(); + final Statement statement = connection.createStatement()) { statement.execute(String.format("load \"%s\"", tmpDir.getAbsolutePath())); - } catch (IoTDBSQLException e) { + } catch (final IoTDBSQLException e) { Assert.assertTrue(e.getMessage().contains("Current system timestamp precision is ms")); } } @@ -777,24 +868,25 @@ public void testLoadTsFileWithWrongTimestampPrecision() throws Exception { public void testLoadLocally() throws Exception { registerSchema(); - long writtenPoint1 = 0; + final long writtenPoint1; // device 0, device 1, sg 0 - try (TsFileGenerator generator = new TsFileGenerator(new File(tmpDir, "1-0-0-0.tsfile"))) { + try (final TsFileGenerator generator = + new TsFileGenerator(new File(tmpDir, "1-0-0-0.tsfile"))) { generator.registerTimeseries( SchemaConfig.DEVICE_0, Collections.singletonList(SchemaConfig.MEASUREMENT_00)); generator.generateData(SchemaConfig.DEVICE_0, 1, PARTITION_INTERVAL / 10_000, false); writtenPoint1 = generator.getTotalNumber(); } - try (Connection connection = EnvFactory.getEnv().getConnection(); - Statement statement = connection.createStatement()) { + try (final Connection connection = EnvFactory.getEnv().getConnection(); + final Statement statement = connection.createStatement()) { statement.execute(String.format("load \"%s\" sglevel=2", tmpDir.getAbsolutePath())); - try (ResultSet resultSet = + try (final ResultSet resultSet = statement.executeQuery("select count(*) from root.** group by level=1,2")) { if (resultSet.next()) { - long sg1Count = resultSet.getLong("count(root.sg.test_0.*.*)"); + final long sg1Count = resultSet.getLong("count(root.sg.test_0.*.*)"); Assert.assertEquals(writtenPoint1, sg1Count); } else { Assert.fail("This ResultSet is empty."); @@ -817,6 +909,14 @@ private static class SchemaConfig { new MeasurementSchema("sensor_02", TSDataType.DOUBLE, TSEncoding.GORILLA); private static final MeasurementSchema MEASUREMENT_03 = new MeasurementSchema("sensor_03", TSDataType.TEXT, TSEncoding.PLAIN); + private static final MeasurementSchema MEASUREMENT_04 = + new MeasurementSchema("sensor_04", TSDataType.TIMESTAMP, TSEncoding.RLE); + private static final MeasurementSchema MEASUREMENT_05 = + new MeasurementSchema("sensor_05", TSDataType.DATE, TSEncoding.RLE); + private static final MeasurementSchema MEASUREMENT_06 = + new MeasurementSchema("sensor_06", TSDataType.BLOB, TSEncoding.PLAIN); + private static final MeasurementSchema MEASUREMENT_07 = + new MeasurementSchema("sensor_07", TSDataType.STRING, TSEncoding.PLAIN); // device 1, aligned, sg 0 private static final String DEVICE_1 = "root.sg.test_0.a_1"; @@ -828,6 +928,14 @@ private static class SchemaConfig { new MeasurementSchema("sensor_12", TSDataType.DOUBLE, TSEncoding.GORILLA); private static final MeasurementSchema MEASUREMENT_13 = new MeasurementSchema("sensor_13", TSDataType.TEXT, TSEncoding.PLAIN); + private static final MeasurementSchema MEASUREMENT_14 = + new MeasurementSchema("sensor_14", TSDataType.TIMESTAMP, TSEncoding.RLE); + private static final MeasurementSchema MEASUREMENT_15 = + new MeasurementSchema("sensor_15", TSDataType.DATE, TSEncoding.RLE); + private static final MeasurementSchema MEASUREMENT_16 = + new MeasurementSchema("sensor_16", TSDataType.BLOB, TSEncoding.PLAIN); + private static final MeasurementSchema MEASUREMENT_17 = + new MeasurementSchema("sensor_17", TSDataType.STRING, TSEncoding.PLAIN); // device 2, non aligned, sg 1 private static final String DEVICE_2 = "root.sg.test_1.d_2"; diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRecoverIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRecoverIT.java index 7c4d87511d813..41bcc24a375a3 100644 --- a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRecoverIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBRecoverIT.java @@ -98,7 +98,7 @@ public void tearDown() throws Exception { } @Test - public void RecoverTest1() { + public void recoverTest1() { // stop cluster EnvFactory.getEnv().shutdownAllDataNodes(); logger.info("All DataNodes are shut down"); diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBVerifyConnectionIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBVerifyConnectionIT.java new file mode 100644 index 0000000000000..378f47c0c385d --- /dev/null +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/IoTDBVerifyConnectionIT.java @@ -0,0 +1,115 @@ +/* + * 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.iotdb.db.it; + +import org.apache.iotdb.commons.service.ThriftService; +import org.apache.iotdb.consensus.ConsensusFactory; +import org.apache.iotdb.it.env.EnvFactory; +import org.apache.iotdb.it.framework.IoTDBTestRunner; +import org.apache.iotdb.itbase.category.ClusterIT; + +import com.google.common.collect.ImmutableMap; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runner.RunWith; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.Statement; +import java.util.HashMap; +import java.util.Map; + +@RunWith(IoTDBTestRunner.class) +@Category({ClusterIT.class}) +public class IoTDBVerifyConnectionIT { + + @Before + public void setUp() throws Exception { + EnvFactory.getEnv() + .getConfig() + .getCommonConfig() + .setConfigNodeConsensusProtocolClass(ConsensusFactory.RATIS_CONSENSUS); + } + + @After + public void tearDown() throws Exception { + EnvFactory.getEnv().cleanClusterEnvironment(); + } + + @Test + public void testVerifyConnectionAllUp() throws Exception { + EnvFactory.getEnv().initClusterEnvironment(3, 3); + try (Connection connection = EnvFactory.getEnv().getConnection(); + Statement statement = connection.createStatement()) { + ResultSet resultSet = statement.executeQuery("verify connection"); + Assert.assertEquals( + ImmutableMap.of(ThriftService.STATUS_UP, 12), collectConnectionResult(resultSet)); + resultSet = statement.executeQuery("verify connection details"); + Assert.assertEquals( + ImmutableMap.of(ThriftService.STATUS_UP, 54), collectConnectionResult(resultSet)); + } + } + + @Test + public void testVerifyConnectionWithNodeCrash() throws Exception { + EnvFactory.getEnv().initClusterEnvironment(3, 1); + try (Connection connection = EnvFactory.getEnv().getConnection(); + Statement statement = connection.createStatement()) { + ResultSet resultSet = statement.executeQuery("verify connection details"); + Assert.assertEquals( + ImmutableMap.of(ThriftService.STATUS_UP, 18), collectConnectionResult(resultSet)); + final int leaderIndex = EnvFactory.getEnv().getLeaderConfigNodeIndex(); + int shutdownIndex = 0; + if (shutdownIndex == leaderIndex) { + shutdownIndex++; + } + EnvFactory.getEnv().getConfigNodeWrapperList().get(shutdownIndex++).stopForcibly(); + resultSet = statement.executeQuery("verify connection"); + Assert.assertEquals( + ImmutableMap.of(ThriftService.STATUS_UP, 2, ThriftService.STATUS_DOWN, 7), + collectConnectionResult(resultSet)); + resultSet = statement.executeQuery("verify connection details"); + Assert.assertEquals( + ImmutableMap.of(ThriftService.STATUS_UP, 11, ThriftService.STATUS_DOWN, 7), + collectConnectionResult(resultSet)); + } + } + + private static Map collectConnectionResult(ResultSet resultSet) + throws Exception { + Map map = new HashMap<>(); + while (resultSet.next()) { + String result = resultSet.getString(3).split(" ")[0]; + map.computeIfPresent(result, (key, value) -> value + 1); + map.putIfAbsent(result, 1); + } + return map; + } + + private static void showResult(ResultSet resultSet) throws Exception { + while (resultSet.next()) { + System.out.printf( + "%s %s %s\n", resultSet.getString(1), resultSet.getString(2), resultSet.getString(3)); + } + } +} diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceWithTemplateAggregationIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceWithTemplateAggregationIT.java index 5ec4566c54ce6..6d5d16a40c460 100644 --- a/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceWithTemplateAggregationIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/alignbydevice/IoTDBAlignByDeviceWithTemplateAggregationIT.java @@ -104,7 +104,7 @@ public void aggregationTest() { // __endTime result is ambiguous - // not supported: group by session, condition, agg(*), agg(s1+1), count(s1+s2), non-aligned + // not supported: group by session, condition, agg(s1+1), count(s1+s2), non-aligned // template } @@ -528,6 +528,134 @@ public void orderByTest() { "count(s_null) in order by clause doesn't exist."); } + @Test + public void wildCardTest() { + String[] expectedHeader = + new String[] { + "Device,max_time(s3),max_time(s1),max_time(s2),last_value(s1),last_value(s3),last_value(s1),last_value(s2)" + }; + String[] retArray = + new String[] { + "root.sg1.d1,1314000000000,1314000000000,1314000000000,13.14,1314,13.14,true,", + "root.sg1.d2,1314000000001,1314000000001,1314000000001,13.15,1315,13.15,false,", + "root.sg1.d3,1314000000002,1314000000002,1314000000002,13.16,1316,13.16,false,", + "root.sg1.d4,1314000000003,1314000000003,1314000000003,13.14,1314,13.14,true,", + }; + resultSetEqualTest( + "SELECT max_time(*), last_value(s1), last_value(*) FROM root.sg1.** align by device;", + expectedHeader, + retArray); + retArray = + new String[] { + "root.sg2.d1,1314000000000,1314000000000,1314000000000,13.14,1314,13.14,true,", + "root.sg2.d2,1314000000001,1314000000001,1314000000001,13.15,1315,13.15,false,", + "root.sg2.d3,1314000000002,1314000000002,1314000000002,13.16,1316,13.16,false,", + "root.sg2.d4,1314000000003,1314000000003,1314000000003,13.14,1314,13.14,true,", + }; + resultSetEqualTest( + "SELECT max_time(*), last_value(s1), last_value(*) FROM root.sg2.** align by device;", + expectedHeader, + retArray); + + // filter test + expectedHeader = + new String[] {"Device,max_time(s1),last_value(s3),last_value(s1),last_value(s2),count(s2)"}; + retArray = + new String[] { + "root.sg1.d1,1314000000000,1314,13.14,true,3,", + "root.sg1.d2,1314000000001,1315,13.15,false,4,", + "root.sg1.d3,1314000000002,1316,13.16,false,3,", + "root.sg1.d4,1314000000003,1314,13.14,true,4,", + }; + resultSetEqualTest( + "SELECT max_time(s1), last_value(*), count(s2) FROM root.sg1.** where s3>1 align by device;", + expectedHeader, + retArray); + retArray = + new String[] { + "root.sg2.d1,1314000000000,1314,13.14,true,3,", + "root.sg2.d2,1314000000001,1315,13.15,false,4,", + "root.sg2.d3,1314000000002,1316,13.16,false,3,", + "root.sg2.d4,1314000000003,1314,13.14,true,4,", + }; + resultSetEqualTest( + "SELECT max_time(s1), last_value(*), count(s2) FROM root.sg2.** where s3>1 align by device;", + expectedHeader, + retArray); + + // sliding window + expectedHeader = new String[] {"Time,Device,last_value(s1),last_value(s2)"}; + retArray = + new String[] { + "1,root.sg1.d1,2.2,false,", + "1,root.sg1.d2,22.2,false,", + "3,root.sg1.d2,50.0,false,", + "5,root.sg1.d2,50.0,false,", + "7,root.sg1.d3,8.8,false,", + "3,root.sg1.d4,5555.5,false,", + "5,root.sg1.d4,5555.5,false,", + }; + resultSetEqualTest( + "SELECT last_value(*) FROM root.sg1.** where s3+1=1316 or s2=false group by ([1,10),3ms,2ms) having avg(s1)>0 soffset 1 slimit 2 align by device;", + expectedHeader, + retArray); + retArray = + new String[] { + "1,root.sg2.d1,2.2,false,", + "1,root.sg2.d2,22.2,false,", + "3,root.sg2.d2,50.0,false,", + "5,root.sg2.d2,50.0,false,", + "7,root.sg2.d3,8.8,false,", + "3,root.sg2.d4,5555.5,false,", + "5,root.sg2.d4,5555.5,false,", + }; + resultSetEqualTest( + "SELECT last_value(*) FROM root.sg2.** where s3+1=1316 or s2=false group by ([1,10),3ms,2ms) having avg(s1)>0 soffset 1 slimit 2 align by device;", + expectedHeader, + retArray); + + // having + expectedHeader = + new String[] { + "Device,last_value(s3),last_value(s1),last_value(s2),first_value(s3),first_value(s1),first_value(s2)" + }; + retArray = + new String[] { + "root.sg1.d2,1315,13.15,false,11,11.1,false,", + }; + resultSetEqualTest( + "SELECT last_value(*), first_value(*) FROM root.sg1.** where s2=false having count(s3+s1) > 2 align by device;", + expectedHeader, + retArray); + retArray = + new String[] { + "root.sg2.d2,1315,13.15,false,11,11.1,false,", + }; + resultSetEqualTest( + "SELECT last_value(*), first_value(*) FROM root.sg2.** where s2=false having count(s3+s1) > 2 align by device;", + expectedHeader, + retArray); + + // not supported expression: agg1(*)+agg2(*), agg(*)/2 + expectedHeader = new String[] {"Device,count(s3) + 1,count(s1) + 1,count(s2) + 1"}; + retArray = + new String[] { + "root.sg1.d2,5.0,5.0,5.0,", + }; + resultSetEqualTest( + "SELECT count(*)+1 FROM root.sg1.** where s2=false having count(s3+s1) > 2 align by device;", + expectedHeader, + retArray); + retArray = + new String[] { + "root.sg2.d2,5.0,5.0,5.0,", + }; + resultSetEqualTest( + "SELECT count(*)+1 FROM root.sg2.** where s2=false having count(s3+s1) > 2 align by device;", + expectedHeader, + retArray); + } + protected static void insertData() { try (Connection connection = EnvFactory.getEnv().getConnection(); Statement statement = connection.createStatement()) { diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/aligned/IoTDBPredicatePushDownIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/aligned/IoTDBPredicatePushDownIT.java index 4d3ff5120df38..1a65682fc5b83 100644 --- a/integration-test/src/test/java/org/apache/iotdb/db/it/aligned/IoTDBPredicatePushDownIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/aligned/IoTDBPredicatePushDownIT.java @@ -91,6 +91,13 @@ public void testAlignedRawDataAlignByTime1() { }; resultSetEqualTest( "select s2 from root.sg1.d1 where s2 - 1 >= 9 and s2 < 30", expectedHeader3, retArray3); + + String expectedHeader4 = "Time,root.sg1.d1.s2,"; + String[] retArray4 = new String[] {"14,14,", "15,15,"}; + resultSetEqualTest( + "select s2 from root.sg1.d1 where s2 - 1 >= 9 and s2 < 30 offset 3 limit 2", + expectedHeader4, + retArray4); } @Test @@ -164,6 +171,11 @@ public void testAlignedRawDataAlignByTime2() { "30,30,", }; resultSetEqualTest("select s3 from root.sg1.d1 where s3 + 1 > 16", expectedHeader3, retArray3); + + String expectedHeader4 = "Time,root.sg1.d1.s3,"; + String[] retArray4 = new String[] {"3,30000,", "13,130000,", "16,16,"}; + resultSetEqualTest( + "select s3 from root.sg1.d1 where s3 + 1 > 16 limit 3", expectedHeader4, retArray4); } @Test @@ -203,6 +215,13 @@ public void testNonAlignedRawDataAlignByTime1() { }; resultSetEqualTest( "select s2 from root.sg1.d2 where s2 - 1 >= 9 and s2 < 30", expectedHeader3, retArray3); + + String expectedHeader4 = "Time,root.sg1.d2.s2,"; + String[] retArray4 = new String[] {"12,12,", "13,13,", "14,14,"}; + resultSetEqualTest( + "select s2 from root.sg1.d2 where s2 - 1 >= 9 and s2 < 30 limit 3 offset 2", + expectedHeader4, + retArray4); } @Test @@ -257,6 +276,14 @@ public void testNonAlignedRawDataAlignByTime2() { "25,25,", "26,26,", "27,27,", "28,28,", "29,29,", "30,30,", }; resultSetEqualTest("select s3 from root.sg1.d2 where s3 + 1 > 16", expectedHeader3, retArray3); + + String expectedHeader4 = "Time,root.sg1.d2.s3,"; + String[] retArray4 = + new String[] { + "26,26,", "27,27,", "28,28,", "29,29,", "30,30,", + }; + resultSetEqualTest( + "select s3 from root.sg1.d2 where s3 + 1 > 16 offset 10", expectedHeader4, retArray4); } @Test diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/regionscan/IoTDBActiveRegionScanIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/regionscan/IoTDBActiveRegionScanIT.java similarity index 98% rename from integration-test/src/test/java/org/apache/iotdb/db/it/regionscan/IoTDBActiveRegionScanIT.java rename to integration-test/src/test/java/org/apache/iotdb/db/it/schema/regionscan/IoTDBActiveRegionScanIT.java index c608bf3e24c0e..aa568b583c1bd 100644 --- a/integration-test/src/test/java/org/apache/iotdb/db/it/regionscan/IoTDBActiveRegionScanIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/regionscan/IoTDBActiveRegionScanIT.java @@ -17,18 +17,17 @@ * under the License. */ -package org.apache.iotdb.db.it.regionscan; +package org.apache.iotdb.db.it.schema.regionscan; import org.apache.iotdb.it.env.EnvFactory; -import org.apache.iotdb.it.framework.IoTDBTestRunner; import org.apache.iotdb.itbase.category.ClusterIT; import org.apache.iotdb.itbase.category.LocalStandaloneIT; +import org.apache.iotdb.util.AbstractSchemaIT; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.runner.RunWith; import java.sql.Connection; import java.sql.ResultSet; @@ -45,9 +44,8 @@ import static org.junit.Assert.assertTrue; import static org.junit.Assert.fail; -@RunWith(IoTDBTestRunner.class) @Category({LocalStandaloneIT.class, ClusterIT.class}) -public class IoTDBActiveRegionScanIT { +public class IoTDBActiveRegionScanIT extends AbstractSchemaIT { // Data can be viewed in // https://docs.google.com/spreadsheets/d/11tNRIaHmNdFWc0RC4yAloO6JJbmo9S5qxwAqWxeVY6c/edit#gid=0 public static final String[] common_insert_sqls = @@ -145,6 +143,10 @@ public class IoTDBActiveRegionScanIT { public static final String COUNT_TIMESERIES_COLUMN_NAMES = "count(timeseries)"; public static final String COUNT_DEVICES_COLUMN_NAMES = "count(devices)"; + public IoTDBActiveRegionScanIT(SchemaTestMode schemaTestMode) { + super(schemaTestMode); + } + public static void insertData() { try (Connection connection = EnvFactory.getEnv().getConnection(); Statement statement = connection.createStatement()) { diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/regionscan/IoTDBActiveRegionScanIT2.java b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/regionscan/IoTDBActiveRegionScanIT2.java similarity index 91% rename from integration-test/src/test/java/org/apache/iotdb/db/it/regionscan/IoTDBActiveRegionScanIT2.java rename to integration-test/src/test/java/org/apache/iotdb/db/it/schema/regionscan/IoTDBActiveRegionScanIT2.java index be4751495de4b..da56d3078b01e 100644 --- a/integration-test/src/test/java/org/apache/iotdb/db/it/regionscan/IoTDBActiveRegionScanIT2.java +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/regionscan/IoTDBActiveRegionScanIT2.java @@ -17,21 +17,22 @@ * under the License. */ -package org.apache.iotdb.db.it.regionscan; +package org.apache.iotdb.db.it.schema.regionscan; import org.apache.iotdb.it.env.EnvFactory; -import org.apache.iotdb.it.framework.IoTDBTestRunner; import org.apache.iotdb.itbase.category.ClusterIT; import org.apache.iotdb.itbase.category.LocalStandaloneIT; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.experimental.categories.Category; -import org.junit.runner.RunWith; -@RunWith(IoTDBTestRunner.class) @Category({LocalStandaloneIT.class, ClusterIT.class}) public class IoTDBActiveRegionScanIT2 extends IoTDBActiveRegionScanIT { + public IoTDBActiveRegionScanIT2(SchemaTestMode schemaTestMode) { + super(schemaTestMode); + } + @BeforeClass public static void setUp() throws Exception { EnvFactory.getEnv() diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/regionscan/IoTDBActiveRegionScanWithModsIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/regionscan/IoTDBActiveRegionScanWithModsIT.java similarity index 85% rename from integration-test/src/test/java/org/apache/iotdb/db/it/regionscan/IoTDBActiveRegionScanWithModsIT.java rename to integration-test/src/test/java/org/apache/iotdb/db/it/schema/regionscan/IoTDBActiveRegionScanWithModsIT.java index d977a6d0132e6..0c10f507aa214 100644 --- a/integration-test/src/test/java/org/apache/iotdb/db/it/regionscan/IoTDBActiveRegionScanWithModsIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/regionscan/IoTDBActiveRegionScanWithModsIT.java @@ -17,34 +17,32 @@ * under the License. */ -package org.apache.iotdb.db.it.regionscan; +package org.apache.iotdb.db.it.schema.regionscan; import org.apache.iotdb.it.env.EnvFactory; -import org.apache.iotdb.it.framework.IoTDBTestRunner; import org.apache.iotdb.itbase.category.ClusterIT; import org.apache.iotdb.itbase.category.LocalStandaloneIT; +import org.apache.iotdb.util.AbstractSchemaIT; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Test; import org.junit.experimental.categories.Category; -import org.junit.runner.RunWith; import java.sql.Connection; import java.sql.Statement; -import static org.apache.iotdb.db.it.regionscan.IoTDBActiveRegionScanIT.COUNT_DEVICES_COLUMN_NAMES; -import static org.apache.iotdb.db.it.regionscan.IoTDBActiveRegionScanIT.COUNT_TIMESERIES_COLUMN_NAMES; -import static org.apache.iotdb.db.it.regionscan.IoTDBActiveRegionScanIT.SHOW_DEVICES_COLUMN_NAMES; -import static org.apache.iotdb.db.it.regionscan.IoTDBActiveRegionScanIT.SHOW_TIMESERIES_COLUMN_NAMES; -import static org.apache.iotdb.db.it.regionscan.IoTDBActiveRegionScanIT.basicCountActiveDeviceTest; -import static org.apache.iotdb.db.it.regionscan.IoTDBActiveRegionScanIT.basicShowActiveDeviceTest; -import static org.apache.iotdb.db.it.regionscan.IoTDBActiveRegionScanIT.common_insert_sqls; +import static org.apache.iotdb.db.it.schema.regionscan.IoTDBActiveRegionScanIT.COUNT_DEVICES_COLUMN_NAMES; +import static org.apache.iotdb.db.it.schema.regionscan.IoTDBActiveRegionScanIT.COUNT_TIMESERIES_COLUMN_NAMES; +import static org.apache.iotdb.db.it.schema.regionscan.IoTDBActiveRegionScanIT.SHOW_DEVICES_COLUMN_NAMES; +import static org.apache.iotdb.db.it.schema.regionscan.IoTDBActiveRegionScanIT.SHOW_TIMESERIES_COLUMN_NAMES; +import static org.apache.iotdb.db.it.schema.regionscan.IoTDBActiveRegionScanIT.basicCountActiveDeviceTest; +import static org.apache.iotdb.db.it.schema.regionscan.IoTDBActiveRegionScanIT.basicShowActiveDeviceTest; +import static org.apache.iotdb.db.it.schema.regionscan.IoTDBActiveRegionScanIT.common_insert_sqls; import static org.junit.Assert.fail; -@RunWith(IoTDBTestRunner.class) @Category({LocalStandaloneIT.class, ClusterIT.class}) -public class IoTDBActiveRegionScanWithModsIT { +public class IoTDBActiveRegionScanWithModsIT extends AbstractSchemaIT { private static String[] delete_sqls = new String[] { @@ -57,6 +55,10 @@ public class IoTDBActiveRegionScanWithModsIT { "delete from root.sg.unaligned.d2.* where time > 40 and time <= 43" }; + public IoTDBActiveRegionScanWithModsIT(SchemaTestMode schemaTestMode) { + super(schemaTestMode); + } + public static void insertData() { try (Connection connection = EnvFactory.getEnv().getConnection(); Statement statement = connection.createStatement()) { diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/regionscan/IoTDBActiveRegionScanWithModsIT2.java b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/regionscan/IoTDBActiveRegionScanWithModsIT2.java similarity index 91% rename from integration-test/src/test/java/org/apache/iotdb/db/it/regionscan/IoTDBActiveRegionScanWithModsIT2.java rename to integration-test/src/test/java/org/apache/iotdb/db/it/schema/regionscan/IoTDBActiveRegionScanWithModsIT2.java index a87240341e019..5adccd1fd6980 100644 --- a/integration-test/src/test/java/org/apache/iotdb/db/it/regionscan/IoTDBActiveRegionScanWithModsIT2.java +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/regionscan/IoTDBActiveRegionScanWithModsIT2.java @@ -17,21 +17,22 @@ * under the License. */ -package org.apache.iotdb.db.it.regionscan; +package org.apache.iotdb.db.it.schema.regionscan; import org.apache.iotdb.it.env.EnvFactory; -import org.apache.iotdb.it.framework.IoTDBTestRunner; import org.apache.iotdb.itbase.category.ClusterIT; import org.apache.iotdb.itbase.category.LocalStandaloneIT; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.experimental.categories.Category; -import org.junit.runner.RunWith; -@RunWith(IoTDBTestRunner.class) @Category({LocalStandaloneIT.class, ClusterIT.class}) public class IoTDBActiveRegionScanWithModsIT2 extends IoTDBActiveRegionScanWithModsIT { + public IoTDBActiveRegionScanWithModsIT2(SchemaTestMode schemaTestMode) { + super(schemaTestMode); + } + @BeforeClass public static void setUp() throws Exception { EnvFactory.getEnv() diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/schema/regionscan/IoTDBActiveSchemaQueryIT.java b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/regionscan/IoTDBActiveSchemaQueryIT.java new file mode 100644 index 0000000000000..853ef3c87ae00 --- /dev/null +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/schema/regionscan/IoTDBActiveSchemaQueryIT.java @@ -0,0 +1,363 @@ +/* + * 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.iotdb.db.it.schema.regionscan; + +import org.apache.iotdb.it.env.EnvFactory; +import org.apache.iotdb.itbase.category.ClusterIT; +import org.apache.iotdb.itbase.category.LocalStandaloneIT; +import org.apache.iotdb.util.AbstractSchemaIT; + +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; +import org.junit.experimental.categories.Category; +import org.junit.runners.Parameterized; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.Statement; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashSet; +import java.util.Set; + +@Category({LocalStandaloneIT.class, ClusterIT.class}) +public class IoTDBActiveSchemaQueryIT extends AbstractSchemaIT { + + private static String[] sqls = + new String[] { + "create aligned timeseries root.sg.d1(s1(alias1) int32 tags('tag1'='v1', 'tag2'='v2'), s2 double attributes('attr3'='v3'))", + "CREATE TIMESERIES root.sg.d0.s0 WITH DATATYPE=INT32", + "CREATE TIMESERIES root.sg.d0.s1 WITH DATATYPE=INT32,ENCODING=PLAIN,LOSS=SDT,COMPDEV=2", + "CREATE TIMESERIES root.sg.d0.s2 WITH DATATYPE=INT32,ENCODING=PLAIN,LOSS=SDT, COMPDEV=0.01, COMPMINTIME=2, COMPMAXTIME=15", + "CREATE DEVICE TEMPLATE t1 (s1 INT64 encoding=RLE compressor=SNAPPY, s2 INT32)", + "CREATE DEVICE TEMPLATE t2 aligned(s1 INT64 encoding=RLE compressor=SNAPPY, s2 INT32)", + "SET DEVICE TEMPLATE t1 to root.sg.d2", + "SET DEVICE TEMPLATE t2 to root.sg.d3", + "CREATE TIMESERIES OF DEVICE TEMPLATE ON root.sg.d2", + "CREATE TIMESERIES OF DEVICE TEMPLATE ON root.sg.d3", + "set ttl to root.sg.d3 60000", + }; + + public IoTDBActiveSchemaQueryIT(SchemaTestMode schemaTestMode) { + super(schemaTestMode); + } + + @Parameterized.BeforeParam + public static void before() throws Exception { + SchemaTestMode schemaTestMode = setUpEnvironment(); + if (schemaTestMode.equals(SchemaTestMode.PBTree)) { + allocateMemoryForSchemaRegion(10000); + } + EnvFactory.getEnv().initClusterEnvironment(); + } + + @Parameterized.AfterParam + public static void after() throws Exception { + EnvFactory.getEnv().cleanClusterEnvironment(); + tearDownEnvironment(); + } + + @Before + public void setUp() throws Exception { + createSchema(); + } + + @After + public void tearDown() throws Exception { + clearSchema(); + } + + private void createSchema() { + try (Connection connection = EnvFactory.getEnv().getConnection(); + Statement statement = connection.createStatement()) { + for (String sql : sqls) { + statement.execute(sql); + } + } catch (Exception e) { + e.printStackTrace(); + } + } + + @Test + public void testShowTimeSeries() { + try (Connection connection = EnvFactory.getEnv().getConnection(); + Statement statement = connection.createStatement()) { + // 0. Check environment + Set expected = + new HashSet<>( + Arrays.asList( + "root.sg.d1.s1,alias1,root.sg,INT32,TS_2DIFF,LZ4,{\"tag1\":\"v1\",\"tag2\":\"v2\"},null,null,null,BASE,", + "root.sg.d1.s2,null,root.sg,DOUBLE,GORILLA,LZ4,null,{\"attr3\":\"v3\"},null,null,BASE,", + "root.sg.d0.s0,null,root.sg,INT32,TS_2DIFF,LZ4,null,null,null,null,BASE,", + "root.sg.d0.s1,null,root.sg,INT32,PLAIN,LZ4,null,null,SDT,{compdev=2},BASE,", + "root.sg.d0.s2,null,root.sg,INT32,PLAIN,LZ4,null,null,SDT,{compdev=0.01, compmintime=2, compmaxtime=15},BASE,", + "root.sg.d2.s1,null,root.sg,INT64,RLE,SNAPPY,null,null,null,null,BASE,", + "root.sg.d2.s2,null,root.sg,INT32,TS_2DIFF,LZ4,null,null,null,null,BASE,", + "root.sg.d3.s1,null,root.sg,INT64,RLE,SNAPPY,null,null,null,null,BASE,", + "root.sg.d3.s2,null,root.sg,INT32,TS_2DIFF,LZ4,null,null,null,null,BASE,")); + checkResultSet(statement, "show timeseries root.sg.**", expected); + // 1. Without any data, result set should be empty + try (ResultSet resultSet = + statement.executeQuery("show timeseries root.sg.** where time>0")) { + Assert.assertFalse(resultSet.next()); + } + // 2. Insert data and check again. + // - root.db.d0.* time=1 + // - root.db.d1.* time=2 + // - root.db.d2.* time=3 + // - root.db.d3.* time=now() + statement.execute("insert into root.sg.d0(timestamp,s0, s1, s2) values(1,1,1,1)"); + statement.execute("insert into root.sg.d1(timestamp,s1,s2) values(2,2,2)"); + statement.execute("insert into root.sg.d2(timestamp,s1,s2) values(3,3,3)"); + statement.execute("insert into root.sg.d3(timestamp,s1,s2) values(now(),4,4)"); + expected = + new HashSet<>( + Arrays.asList( + "root.sg.d1.s1,alias1,root.sg,INT32,TS_2DIFF,LZ4,{\"tag1\":\"v1\",\"tag2\":\"v2\"},null,null,null,BASE,", + "root.sg.d1.s2,null,root.sg,DOUBLE,GORILLA,LZ4,null,{\"attr3\":\"v3\"},null,null,BASE,", + "root.sg.d0.s0,null,root.sg,INT32,TS_2DIFF,LZ4,null,null,null,null,BASE,", + "root.sg.d0.s1,null,root.sg,INT32,PLAIN,LZ4,null,null,SDT,{compdev=2},BASE,", + "root.sg.d0.s2,null,root.sg,INT32,PLAIN,LZ4,null,null,SDT,{compdev=0.01, compmintime=2, compmaxtime=15},BASE,", + "root.sg.d2.s1,null,root.sg,INT64,RLE,SNAPPY,null,null,null,null,BASE,", + "root.sg.d2.s2,null,root.sg,INT32,TS_2DIFF,LZ4,null,null,null,null,BASE,", + "root.sg.d3.s1,null,root.sg,INT64,RLE,SNAPPY,null,null,null,null,BASE,", + "root.sg.d3.s2,null,root.sg,INT32,TS_2DIFF,LZ4,null,null,null,null,BASE,")); + checkResultSet(statement, "show timeseries root.sg.** where time>0", expected); + checkResultSet( + statement, + "count timeseries root.sg.** where time>0", + new HashSet<>(Collections.singletonList("9,"))); + expected = + new HashSet<>( + Arrays.asList( + "root.sg.d1.s1,alias1,root.sg,INT32,TS_2DIFF,LZ4,{\"tag1\":\"v1\",\"tag2\":\"v2\"},null,null,null,BASE,", + "root.sg.d1.s2,null,root.sg,DOUBLE,GORILLA,LZ4,null,{\"attr3\":\"v3\"},null,null,BASE,", + "root.sg.d2.s1,null,root.sg,INT64,RLE,SNAPPY,null,null,null,null,BASE,", + "root.sg.d2.s2,null,root.sg,INT32,TS_2DIFF,LZ4,null,null,null,null,BASE,", + "root.sg.d3.s1,null,root.sg,INT64,RLE,SNAPPY,null,null,null,null,BASE,", + "root.sg.d3.s2,null,root.sg,INT32,TS_2DIFF,LZ4,null,null,null,null,BASE,")); + checkResultSet(statement, "show timeseries root.sg.** where time>1", expected); + checkResultSet( + statement, + "count timeseries root.sg.** where time>1", + new HashSet<>(Collections.singletonList("6,"))); + expected = + new HashSet<>( + Arrays.asList( + "root.sg.d1.s1,alias1,root.sg,INT32,TS_2DIFF,LZ4,{\"tag1\":\"v1\",\"tag2\":\"v2\"},null,null,null,BASE,", + "root.sg.d1.s2,null,root.sg,DOUBLE,GORILLA,LZ4,null,{\"attr3\":\"v3\"},null,null,BASE,", + "root.sg.d2.s1,null,root.sg,INT64,RLE,SNAPPY,null,null,null,null,BASE,", + "root.sg.d2.s2,null,root.sg,INT32,TS_2DIFF,LZ4,null,null,null,null,BASE,", + "root.sg.d3.s1,null,root.sg,INT64,RLE,SNAPPY,null,null,null,null,BASE,", + "root.sg.d3.s2,null,root.sg,INT32,TS_2DIFF,LZ4,null,null,null,null,BASE,")); + checkResultSet(statement, "show timeseries root.sg.** where time!=1", expected); + checkResultSet( + statement, + "count timeseries root.sg.** where time!=1", + new HashSet<>(Collections.singletonList("6,"))); + expected = + new HashSet<>( + Arrays.asList( + "root.sg.d0.s0,null,root.sg,INT32,TS_2DIFF,LZ4,null,null,null,null,BASE,", + "root.sg.d0.s1,null,root.sg,INT32,PLAIN,LZ4,null,null,SDT,{compdev=2},BASE,", + "root.sg.d0.s2,null,root.sg,INT32,PLAIN,LZ4,null,null,SDT,{compdev=0.01, compmintime=2, compmaxtime=15},BASE,")); + checkResultSet(statement, "show timeseries root.sg.** where time<2", expected); + checkResultSet( + statement, + "count timeseries root.sg.** where time<2", + new HashSet<>(Collections.singletonList("3,"))); + expected = + new HashSet<>( + Arrays.asList( + "root.sg.d0.s0,null,root.sg,INT32,TS_2DIFF,LZ4,null,null,null,null,BASE,", + "root.sg.d0.s1,null,root.sg,INT32,PLAIN,LZ4,null,null,SDT,{compdev=2},BASE,", + "root.sg.d0.s2,null,root.sg,INT32,PLAIN,LZ4,null,null,SDT,{compdev=0.01, compmintime=2, compmaxtime=15},BASE,")); + checkResultSet(statement, "show timeseries root.sg.** where time=1", expected); + checkResultSet( + statement, + "count timeseries root.sg.** where time=1", + new HashSet<>(Collections.singletonList("3,"))); + // 3. Check non-root user + statement.execute("CREATE USER user1 'password'"); + statement.execute("GRANT READ_SCHEMA ON root.sg.d0.s1 TO USER user1"); + statement.execute("GRANT READ_SCHEMA ON root.sg.d3.s1 TO USER user1"); + try (Connection userCon = EnvFactory.getEnv().getConnection("user1", "password"); + Statement userStmt = userCon.createStatement()) { + // 3.1 Without read data permission, result set should be empty + try (ResultSet resultSet = + userStmt.executeQuery("show timeseries root.sg.** where time>0")) { + Assert.assertFalse(resultSet.next()); + } + checkResultSet( + userStmt, + "count timeseries root.sg.** where time>0", + new HashSet<>(Collections.singletonList("0,"))); + } + statement.execute("GRANT READ_DATA ON root.sg.d0.s1 TO USER user1"); + statement.execute("GRANT READ_DATA ON root.sg.d3.s1 TO USER user1"); + try (Connection userCon = EnvFactory.getEnv().getConnection("user1", "password"); + Statement userStmt = userCon.createStatement()) { + // 3.2 With read data permission, result set should not be empty + expected = + new HashSet<>( + Arrays.asList( + "root.sg.d0.s1,null,root.sg,INT32,PLAIN,LZ4,null,null,SDT,{compdev=2},BASE,", + "root.sg.d3.s1,null,root.sg,INT64,RLE,SNAPPY,null,null,null,null,BASE,")); + checkResultSet(userStmt, "show timeseries root.sg.** where time>0", expected); + checkResultSet( + userStmt, + "count timeseries root.sg.** where time>0", + new HashSet<>(Collections.singletonList("2,"))); + } + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.getMessage()); + } + } + + @Test + public void testShowDevices() { + try (Connection connection = EnvFactory.getEnv().getConnection(); + Statement statement = connection.createStatement()) { + // 0. Check environment + Set expected = + new HashSet<>( + Arrays.asList( + "root.sg.d0,false,null,INF,", + "root.sg.d1,true,null,INF,", + "root.sg.d2,false,t1,INF,", + "root.sg.d3,true,t2,60000,")); + checkResultSet(statement, "show devices root.sg.*", expected); + // 1. Without any data, result set should be empty + try (ResultSet resultSet = statement.executeQuery("show devices root.sg.* where time>0")) { + Assert.assertFalse(resultSet.next()); + } + // 2. Insert data and check again. + // - root.sg.d0.* time=1 + // - root.sg.d1.* time=2 + // - root.sg.d2.* time=3 + // - root.sg.d3.* time=now() + statement.execute("insert into root.sg.d0(timestamp,s0, s1, s2) values(1,1,1,1)"); + statement.execute("insert into root.sg.d1(timestamp,s1,s2) values(2,2,2)"); + statement.execute("insert into root.sg.d2(timestamp,s1,s2) values(3,3,3)"); + statement.execute("insert into root.sg.d3(timestamp,s1,s2) values(now(),4,4)"); + expected = + new HashSet<>( + Arrays.asList( + "root.sg.d0,false,null,INF,", + "root.sg.d1,true,null,INF,", + "root.sg.d2,false,t1,INF,", + "root.sg.d3,true,t2,60000,")); + checkResultSet(statement, "show devices root.sg.* where time>0", expected); + checkResultSet( + statement, + "count devices root.sg.* where time>0", + new HashSet<>(Collections.singletonList("4,"))); + expected = + new HashSet<>( + Arrays.asList( + "root.sg.d1,true,null,INF,", + "root.sg.d2,false,t1,INF,", + "root.sg.d3,true,t2,60000,")); + checkResultSet(statement, "show devices root.sg.* where time>1", expected); + checkResultSet( + statement, + "count devices root.sg.* where time>1", + new HashSet<>(Collections.singletonList("3,"))); + expected = + new HashSet<>( + Arrays.asList( + "root.sg.d1,true,null,INF,", + "root.sg.d2,false,t1,INF,", + "root.sg.d3,true,t2,60000,")); + checkResultSet(statement, "show devices root.sg.* where time!=1", expected); + checkResultSet( + statement, + "count devices root.sg.* where time!=1", + new HashSet<>(Collections.singletonList("3,"))); + expected = new HashSet<>(Collections.singletonList("root.sg.d0,false,null,INF,")); + checkResultSet(statement, "show devices root.sg.* where time<2", expected); + checkResultSet( + statement, + "count devices root.sg.* where time<2", + new HashSet<>(Collections.singletonList("1,"))); + expected = new HashSet<>(Collections.singletonList("root.sg.d0,false,null,INF,")); + checkResultSet(statement, "show devices root.sg.* where time=1", expected); + checkResultSet( + statement, + "count devices root.sg.* where time=1", + new HashSet<>(Collections.singletonList("1,"))); + // 3. Check non-root user + statement.execute("CREATE USER user1 'password'"); + statement.execute("GRANT READ_SCHEMA ON root.sg.d0.s1 TO USER user1"); + statement.execute("GRANT READ_SCHEMA ON root.sg.d3.s1 TO USER user1"); + try (Connection userCon = EnvFactory.getEnv().getConnection("user1", "password"); + Statement userStmt = userCon.createStatement()) { + // 3.1 Without read data permission, result set should be empty + try (ResultSet resultSet = userStmt.executeQuery("show devices root.sg.* where time>0")) { + Assert.assertFalse(resultSet.next()); + } + checkResultSet( + userStmt, + "count devices root.sg.* where time>0", + new HashSet<>(Collections.singletonList("0,"))); + } + statement.execute("GRANT READ_DATA ON root.sg.d0.s1 TO USER user1"); + statement.execute("GRANT READ_DATA ON root.sg.d3.s1 TO USER user1"); + try (Connection userCon = EnvFactory.getEnv().getConnection("user1", "password"); + Statement userStmt = userCon.createStatement()) { + // 3.2 With read data permission, result set should not be empty + expected = + new HashSet<>(Arrays.asList("root.sg.d0,false,null,INF,", "root.sg.d3,true,t2,60000,")); + checkResultSet(userStmt, "show devices root.sg.* where time>0", expected); + checkResultSet( + userStmt, + "count devices root.sg.* where time>0", + new HashSet<>(Collections.singletonList("2,"))); + } + + } catch (Exception e) { + e.printStackTrace(); + Assert.fail(e.getMessage()); + } + } + + private void checkResultSet(Statement statement, String sql, Set expected) + throws Exception { + try (ResultSet resultSet = statement.executeQuery(sql)) { + ResultSetMetaData resultSetMetaData = resultSet.getMetaData(); + while (resultSet.next()) { + StringBuilder builder = new StringBuilder(); + for (int i = 1; i <= resultSetMetaData.getColumnCount(); i++) { + builder.append(resultSet.getString(i)).append(","); + } + if (!expected.contains(builder.toString())) { + System.out.println(builder.toString()); + } + Assert.assertTrue(expected.contains(builder.toString())); + expected.remove(builder.toString()); + } + } + Assert.assertTrue(expected.isEmpty()); + } +} diff --git a/integration-test/src/test/java/org/apache/iotdb/db/it/utils/TestUtils.java b/integration-test/src/test/java/org/apache/iotdb/db/it/utils/TestUtils.java index 176d0158dfce7..372c9200c5e6c 100644 --- a/integration-test/src/test/java/org/apache/iotdb/db/it/utils/TestUtils.java +++ b/integration-test/src/test/java/org/apache/iotdb/db/it/utils/TestUtils.java @@ -704,6 +704,9 @@ public static void assertDataEventuallyOnEnv( Statement statement = connection.createStatement()) { // Keep retrying if there are execution failures await() + .pollInSameThread() + .pollDelay(1L, TimeUnit.SECONDS) + .pollInterval(1L, TimeUnit.SECONDS) .atMost(timeoutSeconds, TimeUnit.SECONDS) .untilAsserted( () -> { @@ -720,6 +723,36 @@ public static void assertDataEventuallyOnEnv( } } + public static void assertDataEventuallyOnEnv( + BaseEnv env, String sql, Map expectedHeaderWithResult) { + assertDataEventuallyOnEnv(env, sql, expectedHeaderWithResult, 600); + } + + public static void assertDataEventuallyOnEnv( + BaseEnv env, String sql, Map expectedHeaderWithResult, long timeoutSeconds) { + try (Connection connection = env.getConnection(); + Statement statement = connection.createStatement()) { + // Keep retrying if there are execution failures + await() + .pollInSameThread() + .pollDelay(1L, TimeUnit.SECONDS) + .pollInterval(1L, TimeUnit.SECONDS) + .atMost(timeoutSeconds, TimeUnit.SECONDS) + .untilAsserted( + () -> { + try { + TestUtils.assertSingleResultSetEqual( + executeQueryWithRetry(statement, sql), expectedHeaderWithResult); + } catch (Exception e) { + Assert.fail(); + } + }); + } catch (Exception e) { + e.printStackTrace(); + fail(); + } + } + public static void assertDataAlwaysOnEnv( BaseEnv env, String sql, String expectedHeader, Set expectedResSet) { assertDataAlwaysOnEnv(env, sql, expectedHeader, expectedResSet, 10); @@ -735,6 +768,9 @@ public static void assertDataAlwaysOnEnv( Statement statement = connection.createStatement()) { // Keep retrying if there are execution failures await() + .pollInSameThread() + .pollDelay(1L, TimeUnit.SECONDS) + .pollInterval(1L, TimeUnit.SECONDS) .atMost(consistentSeconds, TimeUnit.SECONDS) .failFast( () -> { diff --git a/integration-test/src/test/java/org/apache/iotdb/pipe/it/autocreate/IoTDBPipeDataSinkIT.java b/integration-test/src/test/java/org/apache/iotdb/pipe/it/autocreate/IoTDBPipeDataSinkIT.java index 50a9b0d2ec5b2..8cd8d66d38791 100644 --- a/integration-test/src/test/java/org/apache/iotdb/pipe/it/autocreate/IoTDBPipeDataSinkIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/pipe/it/autocreate/IoTDBPipeDataSinkIT.java @@ -148,4 +148,109 @@ public void testLegacyConnector() throws Exception { Collections.singleton("0,1.0,")); } } + + @Test + public void testReceiverAutoCreateByLog() throws Exception { + testReceiverAutoCreate( + new HashMap() { + { + put("source.realtime.mode", "forced-log"); + } + }); + } + + @Test + public void testReceiverAutoCreateByFile() throws Exception { + testReceiverAutoCreate( + new HashMap() { + { + put("source.realtime.mode", "batch"); + } + }); + } + + @Test + public void testReceiverAutoCreateWithPattern() throws Exception { + testReceiverAutoCreate( + new HashMap() { + { + put("source.realtime.mode", "batch"); + put("source.path", "root.ln.wf01.wt0*.*"); + } + }); + } + + private void testReceiverAutoCreate(final Map extractorAttributes) + throws Exception { + final DataNodeWrapper receiverDataNode = receiverEnv.getDataNodeWrapper(0); + + final String receiverIp = receiverDataNode.getIp(); + final int receiverPort = receiverDataNode.getPort(); + + try (final SyncConfigNodeIServiceClient client = + (SyncConfigNodeIServiceClient) senderEnv.getLeaderConfigNodeConnection()) { + final Map processorAttributes = new HashMap<>(); + final Map connectorAttributes = new HashMap<>(); + + connectorAttributes.put("sink", "iotdb-thrift-sink"); + connectorAttributes.put("sink.batch.enable", "false"); + connectorAttributes.put("sink.ip", receiverIp); + connectorAttributes.put("sink.port", Integer.toString(receiverPort)); + + final TSStatus status = + client.createPipe( + new TCreatePipeReq("testPipe", connectorAttributes) + .setExtractorAttributes(extractorAttributes) + .setProcessorAttributes(processorAttributes)); + + Assert.assertEquals(TSStatusCode.SUCCESS_STATUS.getStatusCode(), status.getCode()); + + // Do not fail if the failure has nothing to do with pipe + // Because the failures will randomly generate due to resource limitation + if (!TestUtils.tryExecuteNonQueriesWithRetry( + senderEnv, + Arrays.asList( + "create timeSeries root.ln.wf01.wt01.boolean boolean", + "create timeSeries root.ln.wf01.wt01.int32 int32", + "create timeSeries root.ln.wf01.wt01.int64 int64", + "create timeSeries root.ln.wf01.wt01.float float", + "create timeSeries root.ln.wf01.wt01.double double", + "create timeSeries root.ln.wf01.wt01.time_stamp timestamp", + "create timeSeries root.ln.wf01.wt01.date date", + "create timeSeries root.ln.wf01.wt01.text text", + "create timeSeries root.ln.wf01.wt01.string string", + "create timeSeries root.ln.wf01.wt01.blob blob", + "create aligned timeSeries root.ln.wf01.wt02(int32 int32, boolean boolean)", + "insert into root.ln.wf01.wt01(time, boolean, int32, int64, float, double, time_stamp, date, text, string, blob) values (20000, false, 123, 321, 13.3, 14.4, now(), '2000-12-13', 'abc', 'def', X'f103')", + "insert into root.ln.wf01.wt02(time, int32, boolean) values (20000, 123, false)", + // For pattern parse + "insert into root.ln.wf01.wt11(time, redundant_data) values (20000, -1)", + "flush"))) { + return; + } + + TestUtils.assertDataEventuallyOnEnv( + receiverEnv, + "show timeSeries root.ln.wf01.wt01.*", + "Timeseries,Alias,Database,DataType,Encoding,Compression,Tags,Attributes,Deadband,DeadbandParameters,ViewType,", + Collections.unmodifiableSet( + new HashSet<>( + Arrays.asList( + "root.ln.wf01.wt01.boolean,null,root.ln,BOOLEAN,RLE,LZ4,null,null,null,null,BASE,", + "root.ln.wf01.wt01.int32,null,root.ln,INT32,TS_2DIFF,LZ4,null,null,null,null,BASE,", + "root.ln.wf01.wt01.int64,null,root.ln,INT64,TS_2DIFF,LZ4,null,null,null,null,BASE,", + "root.ln.wf01.wt01.float,null,root.ln,FLOAT,GORILLA,LZ4,null,null,null,null,BASE,", + "root.ln.wf01.wt01.double,null,root.ln,DOUBLE,GORILLA,LZ4,null,null,null,null,BASE,", + "root.ln.wf01.wt01.time_stamp,null,root.ln,TIMESTAMP,TS_2DIFF,LZ4,null,null,null,null,BASE,", + "root.ln.wf01.wt01.date,null,root.ln,DATE,TS_2DIFF,LZ4,null,null,null,null,BASE,", + "root.ln.wf01.wt01.text,null,root.ln,TEXT,PLAIN,LZ4,null,null,null,null,BASE,", + "root.ln.wf01.wt01.string,null,root.ln,STRING,PLAIN,LZ4,null,null,null,null,BASE,", + "root.ln.wf01.wt01.blob,null,root.ln,BLOB,PLAIN,LZ4,null,null,null,null,BASE,")))); + TestUtils.assertDataEventuallyOnEnv( + receiverEnv, + "show devices root.ln.wf01.wt02", + "Device,IsAligned,Template,TTL,", + Collections.singleton("root.ln.wf01.wt02,true,null,INF,")); + } + } } diff --git a/integration-test/src/test/java/org/apache/iotdb/pipe/it/autocreate/IoTDBPipeExtractorIT.java b/integration-test/src/test/java/org/apache/iotdb/pipe/it/autocreate/IoTDBPipeExtractorIT.java index 1befb2b765d7b..2a4439eb605c9 100644 --- a/integration-test/src/test/java/org/apache/iotdb/pipe/it/autocreate/IoTDBPipeExtractorIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/pipe/it/autocreate/IoTDBPipeExtractorIT.java @@ -24,7 +24,9 @@ import org.apache.iotdb.confignode.rpc.thrift.TCreatePipeReq; import org.apache.iotdb.confignode.rpc.thrift.TShowPipeInfo; import org.apache.iotdb.confignode.rpc.thrift.TShowPipeReq; +import org.apache.iotdb.consensus.ConsensusFactory; import org.apache.iotdb.db.it.utils.TestUtils; +import org.apache.iotdb.it.env.MultiEnvFactory; import org.apache.iotdb.it.env.cluster.node.DataNodeWrapper; import org.apache.iotdb.it.framework.IoTDBTestRunner; import org.apache.iotdb.itbase.category.MultiClusterIT2AutoCreateSchema; @@ -32,6 +34,7 @@ import org.apache.iotdb.rpc.TSStatusCode; import org.junit.Assert; +import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -51,6 +54,39 @@ @RunWith(IoTDBTestRunner.class) @Category({MultiClusterIT2AutoCreateSchema.class}) public class IoTDBPipeExtractorIT extends AbstractPipeDualAutoIT { + + @Before + public void setUp() { + MultiEnvFactory.createEnv(2); + senderEnv = MultiEnvFactory.getEnv(0); + receiverEnv = MultiEnvFactory.getEnv(1); + + // TODO: delete ratis configurations + senderEnv + .getConfig() + .getCommonConfig() + .setAutoCreateSchemaEnabled(true) + .setConfigNodeConsensusProtocolClass(ConsensusFactory.RATIS_CONSENSUS) + .setSchemaRegionConsensusProtocolClass(ConsensusFactory.RATIS_CONSENSUS) + // Disable sender compaction for tsfile determination in loose range test + .setEnableSeqSpaceCompaction(false) + .setEnableUnseqSpaceCompaction(false) + .setEnableCrossSpaceCompaction(false); + receiverEnv + .getConfig() + .getCommonConfig() + .setAutoCreateSchemaEnabled(true) + .setConfigNodeConsensusProtocolClass(ConsensusFactory.RATIS_CONSENSUS) + .setSchemaRegionConsensusProtocolClass(ConsensusFactory.RATIS_CONSENSUS); + + // 10 min, assert that the operations will not time out + senderEnv.getConfig().getCommonConfig().setCnConnectionTimeoutMs(600000); + receiverEnv.getConfig().getCommonConfig().setCnConnectionTimeoutMs(600000); + + senderEnv.initClusterEnvironment(); + receiverEnv.initClusterEnvironment(); + } + @Test public void testExtractorValidParameter() throws Exception { final DataNodeWrapper receiverDataNode = receiverEnv.getDataNodeWrapper(0); @@ -867,6 +903,136 @@ public void testSourceStartTimeAndEndTimeWorkingWithOrWithoutPattern() throws Ex } } + @Test + public void testHistoryLooseRange() throws Exception { + final DataNodeWrapper receiverDataNode = receiverEnv.getDataNodeWrapper(0); + + final String receiverIp = receiverDataNode.getIp(); + final int receiverPort = receiverDataNode.getPort(); + + try (final SyncConfigNodeIServiceClient client = + (SyncConfigNodeIServiceClient) senderEnv.getLeaderConfigNodeConnection()) { + if (!TestUtils.tryExecuteNonQueriesWithRetry( + senderEnv, + Arrays.asList( + // TsFile 1, extracted without parse + "insert into root.db.d1 (time, at1, at2)" + " values (1000, 1, 2), (2000, 3, 4)", + // TsFile 2, not extracted because pattern not overlapped + "insert into root.db1.d1 (time, at1, at2)" + " values (1000, 1, 2), (2000, 3, 4)", + "flush"))) { + return; + } + + if (!TestUtils.tryExecuteNonQueriesWithRetry( + senderEnv, + Arrays.asList( + // TsFile 3, not extracted because time range not overlapped + "insert into root.db.d1 (time, at1, at2)" + " values (3000, 1, 2), (4000, 3, 4)", + "flush"))) { + return; + } + + final Map extractorAttributes = new HashMap<>(); + final Map processorAttributes = new HashMap<>(); + final Map connectorAttributes = new HashMap<>(); + + extractorAttributes.put("source.path", "root.db.d1.at1"); + extractorAttributes.put("source.inclusion", "data.insert"); + extractorAttributes.put("source.history.start-time", "1500"); + extractorAttributes.put("source.history.end-time", "2500"); + extractorAttributes.put("source.history.loose-range", "time, path"); + + connectorAttributes.put("connector", "iotdb-thrift-connector"); + connectorAttributes.put("connector.batch.enable", "false"); + connectorAttributes.put("connector.ip", receiverIp); + connectorAttributes.put("connector.port", Integer.toString(receiverPort)); + + TSStatus status = + client.createPipe( + new TCreatePipeReq("p1", connectorAttributes) + .setExtractorAttributes(extractorAttributes) + .setProcessorAttributes(processorAttributes)); + Assert.assertEquals(TSStatusCode.SUCCESS_STATUS.getStatusCode(), status.getCode()); + Assert.assertEquals( + TSStatusCode.SUCCESS_STATUS.getStatusCode(), client.startPipe("p1").getCode()); + + TestUtils.assertDataEventuallyOnEnv( + receiverEnv, + "select count(*) from root.** group by level=0", + "count(root.*.*.*),", + Collections.singleton("4,")); + } + } + + @Test + public void testRealtimeLooseRange() throws Exception { + final DataNodeWrapper receiverDataNode = receiverEnv.getDataNodeWrapper(0); + final String receiverIp = receiverDataNode.getIp(); + final int receiverPort = receiverDataNode.getPort(); + + final Map extractorAttributes = new HashMap<>(); + final Map processorAttributes = new HashMap<>(); + final Map connectorAttributes = new HashMap<>(); + + extractorAttributes.put("source.path", "root.db.d1.at1"); + extractorAttributes.put("source.inclusion", "data.insert"); + extractorAttributes.put("source.realtime.loose-range", "time, path"); + extractorAttributes.put("source.start-time", "2000"); + extractorAttributes.put("source.end-time", "10000"); + extractorAttributes.put("source.realtime.mode", "batch"); + + connectorAttributes.put("connector", "iotdb-thrift-connector"); + connectorAttributes.put("connector.batch.enable", "false"); + connectorAttributes.put("connector.ip", receiverIp); + connectorAttributes.put("connector.port", Integer.toString(receiverPort)); + + try (final SyncConfigNodeIServiceClient client = + (SyncConfigNodeIServiceClient) senderEnv.getLeaderConfigNodeConnection()) { + TSStatus status = + client.createPipe( + new TCreatePipeReq("p1", connectorAttributes) + .setExtractorAttributes(extractorAttributes) + .setProcessorAttributes(processorAttributes)); + Assert.assertEquals(TSStatusCode.SUCCESS_STATUS.getStatusCode(), status.getCode()); + Assert.assertEquals( + TSStatusCode.SUCCESS_STATUS.getStatusCode(), client.startPipe("p1").getCode()); + + if (!TestUtils.tryExecuteNonQueriesWithRetry( + senderEnv, + Arrays.asList( + "insert into root.db.d1 (time, at1, at2)" + " values (1000, 1, 2), (3000, 3, 4)", + "flush"))) { + return; + } + + if (!TestUtils.tryExecuteNonQueriesWithRetry( + senderEnv, + Arrays.asList( + "insert into root.db1.d1 (time, at1, at2)" + " values (1000, 1, 2), (3000, 3, 4)", + "flush"))) { + return; + } + + if (!TestUtils.tryExecuteNonQueriesWithRetry( + senderEnv, + Arrays.asList( + "insert into root.db.d1 (time, at1)" + " values (5000, 1), (16000, 3)", + "insert into root.db.d1 (time, at1, at2)" + " values (5001, 1, 2), (6001, 3, 4)", + "flush"))) { + return; + } + + TestUtils.assertDataEventuallyOnEnv( + receiverEnv, + "select count(at1) from root.db.d1 where time >= 2000 and time <= 10000", + new HashMap() { + { + put("count(root.db.d1.at1)", "4"); + } + }); + } + } + private void assertTimeseriesCountOnReceiver(BaseEnv receiverEnv, int count) { TestUtils.assertDataEventuallyOnEnv( receiverEnv, "count timeseries", "count(timeseries),", Collections.singleton(count + ",")); diff --git a/integration-test/src/test/java/org/apache/iotdb/pipe/it/single/IoTDBPipeAggregateIT.java b/integration-test/src/test/java/org/apache/iotdb/pipe/it/single/IoTDBPipeAggregateIT.java index 544509b82894a..cbd9c08f4e5c2 100644 --- a/integration-test/src/test/java/org/apache/iotdb/pipe/it/single/IoTDBPipeAggregateIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/pipe/it/single/IoTDBPipeAggregateIT.java @@ -78,6 +78,20 @@ public void testAggregator() throws Exception { .setProcessorAttributes(processorAttributes)); Assert.assertEquals(TSStatusCode.SUCCESS_STATUS.getStatusCode(), status.getCode()); + // Test unsupported types + if (!TestUtils.tryExecuteNonQueriesWithRetry( + env, + Arrays.asList( + "create timeSeries root.ln.wf01.wt01.boolean boolean", + "create timeSeries root.ln.wf01.wt01.date date", + "create timeSeries root.ln.wf01.wt01.text text", + "create timeSeries root.ln.wf01.wt01.string string", + "create timeSeries root.ln.wf01.wt01.blob blob", + "insert into root.ln.wf01.wt01(time, boolean, date, text, string, blob) values (20000, false, '2000-12-13', 'abc', 'def', X'f103')", + "flush"))) { + return; + } + if (!TestUtils.tryExecuteNonQueriesWithRetry( env, Arrays.asList( diff --git a/integration-test/src/test/java/org/apache/iotdb/subscription/it/AbstractSubscriptionIT.java b/integration-test/src/test/java/org/apache/iotdb/subscription/it/AbstractSubscriptionIT.java new file mode 100644 index 0000000000000..a168dbc78ba72 --- /dev/null +++ b/integration-test/src/test/java/org/apache/iotdb/subscription/it/AbstractSubscriptionIT.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.subscription.it; + +import org.apache.iotdb.session.subscription.consumer.SubscriptionExecutorServiceManager; + +import org.junit.After; +import org.junit.Before; +import org.junit.Rule; +import org.junit.rules.TestName; +import org.junit.rules.TestRule; + +public abstract class AbstractSubscriptionIT { + + @Rule public TestName testName = new TestName(); + + @Rule public final TestRule skipOnSetUpFailure = new SkipOnSetUpFailure("setUp"); + + @Before + public void setUp() { + // set thread name + Thread.currentThread().setName(String.format("%s - main", testName.getMethodName())); + + // set thread pools core size + SubscriptionExecutorServiceManager.setControlFlowExecutorCorePoolSize(1); + SubscriptionExecutorServiceManager.setUpstreamDataFlowExecutorCorePoolSize(1); + SubscriptionExecutorServiceManager.setDownstreamDataFlowExecutorCorePoolSize(1); + } + + @After + public void tearDown() {} +} diff --git a/integration-test/src/test/java/org/apache/iotdb/subscription/it/IoTDBSubscriptionITConstant.java b/integration-test/src/test/java/org/apache/iotdb/subscription/it/IoTDBSubscriptionITConstant.java index d2dc8ee49a5fc..5b8ec39327414 100644 --- a/integration-test/src/test/java/org/apache/iotdb/subscription/it/IoTDBSubscriptionITConstant.java +++ b/integration-test/src/test/java/org/apache/iotdb/subscription/it/IoTDBSubscriptionITConstant.java @@ -19,11 +19,24 @@ package org.apache.iotdb.subscription.it; +import org.awaitility.Awaitility; +import org.awaitility.core.ConditionFactory; + +import java.util.concurrent.TimeUnit; + public class IoTDBSubscriptionITConstant { - public static final long AWAITILITY_POLL_DELAY_SECOND = 1L; - public static final long AWAITILITY_POLL_INTERVAL_SECOND = 2L; - public static final long AWAITILITY_AT_MOST_SECOND = 240L; + private static final long AWAITILITY_POLL_DELAY_SECOND = 1L; + private static final long AWAITILITY_POLL_INTERVAL_SECOND = 1L; + private static final long AWAITILITY_AT_MOST_SECOND = 600L; + + public static final ConditionFactory AWAIT = + Awaitility.await() + .pollInSameThread() + .pollDelay(IoTDBSubscriptionITConstant.AWAITILITY_POLL_DELAY_SECOND, TimeUnit.SECONDS) + .pollInterval( + IoTDBSubscriptionITConstant.AWAITILITY_POLL_INTERVAL_SECOND, TimeUnit.SECONDS) + .atMost(IoTDBSubscriptionITConstant.AWAITILITY_AT_MOST_SECOND, TimeUnit.SECONDS); public static final long SLEEP_NS = 1_000_000_000L; public static final long POLL_TIMEOUT_MS = 10_000L; diff --git a/integration-test/src/test/java/org/apache/iotdb/subscription/it/SkipOnSetUpFailure.java b/integration-test/src/test/java/org/apache/iotdb/subscription/it/SkipOnSetUpFailure.java new file mode 100644 index 0000000000000..add7b7c1e2b88 --- /dev/null +++ b/integration-test/src/test/java/org/apache/iotdb/subscription/it/SkipOnSetUpFailure.java @@ -0,0 +1,82 @@ +/* + * 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.iotdb.subscription.it; + +import org.checkerframework.checker.nullness.qual.NonNull; +import org.junit.AssumptionViolatedException; +import org.junit.rules.TestRule; +import org.junit.runner.Description; +import org.junit.runners.model.Statement; + +import java.lang.reflect.Method; + +public class SkipOnSetUpFailure implements TestRule { + + private final String setUpMethodName; + + /** + * @param setUpMethodName Should be exactly the same as the method name decorated with @Before. + */ + public SkipOnSetUpFailure(@NonNull final String setUpMethodName) { + this.setUpMethodName = setUpMethodName; + } + + @Override + public Statement apply(final Statement base, final Description description) { + return new Statement() { + @Override + public void evaluate() throws Throwable { + try { + base.evaluate(); + } catch (final Throwable e) { + // Trace back the exception stack to determine whether the exception was thrown during the + // setUp phase. + for (final StackTraceElement stackTraceElement : e.getStackTrace()) { + if (setUpMethodName.equals(stackTraceElement.getMethodName()) + && description.getClassName().equals(stackTraceElement.getClassName()) + && isMethodAnnotationWithBefore(stackTraceElement.getMethodName())) { + e.printStackTrace(); + // Skip this test. + throw new AssumptionViolatedException( + String.format( + "Skipping test due to setup failure for %s#%s", + description.getClassName(), description.getMethodName())); + } + } + + // Re-throw the exception (which means the test has failed). + throw e; + + // Regardless of the circumstances, the method decorated with @After will always be + // executed. + } + } + + private boolean isMethodAnnotationWithBefore(final String methodName) { + try { + final Method method = description.getTestClass().getDeclaredMethod(methodName); + return method.isAnnotationPresent(org.junit.Before.class); + } catch (final Throwable ignored) { + return false; + } + } + }; + } +} diff --git a/integration-test/src/test/java/org/apache/iotdb/subscription/it/local/IoTDBSubscriptionRestartIT.java b/integration-test/src/test/java/org/apache/iotdb/subscription/it/cluster/IoTDBSubscriptionRestartIT.java similarity index 89% rename from integration-test/src/test/java/org/apache/iotdb/subscription/it/local/IoTDBSubscriptionRestartIT.java rename to integration-test/src/test/java/org/apache/iotdb/subscription/it/cluster/IoTDBSubscriptionRestartIT.java index 2764fad56b83e..41dd654383d66 100644 --- a/integration-test/src/test/java/org/apache/iotdb/subscription/it/local/IoTDBSubscriptionRestartIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/subscription/it/cluster/IoTDBSubscriptionRestartIT.java @@ -17,7 +17,7 @@ * under the License. */ -package org.apache.iotdb.subscription.it.local; +package org.apache.iotdb.subscription.it.cluster; import org.apache.iotdb.commons.client.sync.SyncConfigNodeIServiceClient; import org.apache.iotdb.confignode.rpc.thrift.TShowSubscriptionReq; @@ -36,9 +36,9 @@ import org.apache.iotdb.session.subscription.consumer.SubscriptionPullConsumer; import org.apache.iotdb.session.subscription.payload.SubscriptionMessage; import org.apache.iotdb.session.subscription.payload.SubscriptionSessionDataSet; +import org.apache.iotdb.subscription.it.AbstractSubscriptionIT; import org.apache.iotdb.subscription.it.IoTDBSubscriptionITConstant; -import org.awaitility.Awaitility; import org.junit.After; import org.junit.Assert; import org.junit.Before; @@ -51,20 +51,23 @@ import java.util.HashMap; import java.util.List; import java.util.Map; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.LockSupport; +import static org.apache.iotdb.subscription.it.IoTDBSubscriptionITConstant.AWAIT; import static org.junit.Assert.fail; @RunWith(IoTDBTestRunner.class) @Category({ClusterIT.class}) -public class IoTDBSubscriptionRestartIT { +public class IoTDBSubscriptionRestartIT extends AbstractSubscriptionIT { private static final Logger LOGGER = LoggerFactory.getLogger(IoTDBSubscriptionRestartIT.class); + @Override @Before - public void setUp() throws Exception { + public void setUp() { + super.setUp(); + EnvFactory.getEnv() .getConfig() .getCommonConfig() @@ -77,8 +80,11 @@ public void setUp() throws Exception { EnvFactory.getEnv().initClusterEnvironment(3, 3); } + @Override @After - public void tearDown() throws Exception { + public void tearDown() { + super.tearDown(); + EnvFactory.getEnv().cleanClusterEnvironment(); } @@ -123,6 +129,7 @@ public void testSubscriptionAfterRestartCluster() throws Exception { TestUtils.restartCluster(EnvFactory.getEnv()); } catch (final Throwable e) { e.printStackTrace(); + // Avoid failure return; } @@ -148,9 +155,10 @@ public void testSubscriptionAfterRestartCluster() throws Exception { String.format("insert into root.db.d1(time, s1) values (%s, 1)", i)); } session.executeNonQueryStatement("flush"); - } catch (final Exception e) { + } catch (final Throwable e) { e.printStackTrace(); - fail(e.getMessage()); + // Avoid failure + return; } // Subscription again @@ -188,18 +196,14 @@ public void testSubscriptionAfterRestartCluster() throws Exception { } finally { LOGGER.info("consumer exiting..."); } - }); + }, + String.format("%s - %s", testName.getMethodName(), consumer)); thread.start(); // Check timestamps size try { // Keep retrying if there are execution failures - Awaitility.await() - .pollDelay(IoTDBSubscriptionITConstant.AWAITILITY_POLL_DELAY_SECOND, TimeUnit.SECONDS) - .pollInterval( - IoTDBSubscriptionITConstant.AWAITILITY_POLL_INTERVAL_SECOND, TimeUnit.SECONDS) - .atMost(IoTDBSubscriptionITConstant.AWAITILITY_AT_MOST_SECOND, TimeUnit.SECONDS) - .untilAsserted(() -> Assert.assertEquals(100, timestamps.size())); + AWAIT.untilAsserted(() -> Assert.assertEquals(100, timestamps.size())); } catch (final Exception e) { e.printStackTrace(); fail(e.getMessage()); @@ -253,9 +257,10 @@ public void testSubscriptionAfterRestartDataNode() throws Exception { String.format("insert into root.db.d1(time, s1) values (%s, 1)", i)); } session.executeNonQueryStatement("flush"); - } catch (final Exception e) { + } catch (final Throwable e) { e.printStackTrace(); - fail(e.getMessage()); + // Avoid failure + return; } // Shutdown DN 1 & DN 2 @@ -265,6 +270,7 @@ public void testSubscriptionAfterRestartDataNode() throws Exception { EnvFactory.getEnv().shutdownDataNode(2); } catch (final Throwable e) { e.printStackTrace(); + // Avoid failure return; } @@ -303,7 +309,8 @@ public void testSubscriptionAfterRestartDataNode() throws Exception { } finally { LOGGER.info("consumer exiting..."); } - }); + }, + String.format("%s - %s", testName.getMethodName(), consumer)); thread.start(); // Start DN 1 & DN 2 @@ -314,6 +321,7 @@ public void testSubscriptionAfterRestartDataNode() throws Exception { ((AbstractEnv) EnvFactory.getEnv()).checkClusterStatusWithoutUnknown(); } catch (final Throwable e) { e.printStackTrace(); + // Avoid failure return; } @@ -324,20 +332,16 @@ public void testSubscriptionAfterRestartDataNode() throws Exception { String.format("insert into root.db.d1(time, s1) values (%s, 1)", i)); } session.executeNonQueryStatement("flush"); - } catch (final Exception e) { + } catch (final Throwable e) { e.printStackTrace(); - fail(e.getMessage()); + // Avoid failure + return; } // Check timestamps size try { // Keep retrying if there are execution failures - Awaitility.await() - .pollDelay(IoTDBSubscriptionITConstant.AWAITILITY_POLL_DELAY_SECOND, TimeUnit.SECONDS) - .pollInterval( - IoTDBSubscriptionITConstant.AWAITILITY_POLL_INTERVAL_SECOND, TimeUnit.SECONDS) - .atMost(IoTDBSubscriptionITConstant.AWAITILITY_AT_MOST_SECOND, TimeUnit.SECONDS) - .untilAsserted(() -> Assert.assertEquals(200, timestamps.size())); + AWAIT.untilAsserted(() -> Assert.assertEquals(200, timestamps.size())); } catch (final Exception e) { e.printStackTrace(); fail(e.getMessage()); @@ -391,9 +395,10 @@ public void testSubscriptionWhenConfigNodeLeaderChange() throws Exception { String.format("insert into root.db.d1(time, s1) values (%s, 1)", i)); } session.executeNonQueryStatement("flush"); - } catch (final Exception e) { + } catch (final Throwable e) { e.printStackTrace(); - fail(e.getMessage()); + // Avoid failure + return; } // Subscription again @@ -431,11 +436,18 @@ public void testSubscriptionWhenConfigNodeLeaderChange() throws Exception { } finally { LOGGER.info("consumer exiting..."); } - }); + }, + String.format("%s - %s", testName.getMethodName(), consumer)); thread.start(); // Shutdown leader CN - EnvFactory.getEnv().shutdownConfigNode(EnvFactory.getEnv().getLeaderConfigNodeIndex()); + try { + EnvFactory.getEnv().shutdownConfigNode(EnvFactory.getEnv().getLeaderConfigNodeIndex()); + } catch (final Throwable e) { + e.printStackTrace(); + // Avoid failure + return; + } // Insert some realtime data try (final ISession session = EnvFactory.getEnv().getSessionConnection()) { @@ -444,9 +456,10 @@ public void testSubscriptionWhenConfigNodeLeaderChange() throws Exception { String.format("insert into root.db.d1(time, s1) values (%s, 1)", i)); } session.executeNonQueryStatement("flush"); - } catch (final Exception e) { + } catch (final Throwable e) { e.printStackTrace(); - fail(e.getMessage()); + // Avoid failure + return; } // Show topics and subscriptions @@ -467,12 +480,7 @@ public void testSubscriptionWhenConfigNodeLeaderChange() throws Exception { // Check timestamps size try { // Keep retrying if there are execution failures - Awaitility.await() - .pollDelay(IoTDBSubscriptionITConstant.AWAITILITY_POLL_DELAY_SECOND, TimeUnit.SECONDS) - .pollInterval( - IoTDBSubscriptionITConstant.AWAITILITY_POLL_INTERVAL_SECOND, TimeUnit.SECONDS) - .atMost(IoTDBSubscriptionITConstant.AWAITILITY_AT_MOST_SECOND, TimeUnit.SECONDS) - .untilAsserted(() -> Assert.assertEquals(200, timestamps.size())); + AWAIT.untilAsserted(() -> Assert.assertEquals(200, timestamps.size())); } catch (final Exception e) { e.printStackTrace(); fail(e.getMessage()); diff --git a/integration-test/src/test/java/org/apache/iotdb/subscription/it/dual/AbstractSubscriptionDualIT.java b/integration-test/src/test/java/org/apache/iotdb/subscription/it/dual/AbstractSubscriptionDualIT.java index 9aa01ad4acfba..fb25cdc3a6c09 100644 --- a/integration-test/src/test/java/org/apache/iotdb/subscription/it/dual/AbstractSubscriptionDualIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/subscription/it/dual/AbstractSubscriptionDualIT.java @@ -21,17 +21,21 @@ import org.apache.iotdb.it.env.MultiEnvFactory; import org.apache.iotdb.itbase.env.BaseEnv; +import org.apache.iotdb.subscription.it.AbstractSubscriptionIT; import org.junit.After; import org.junit.Before; -abstract class AbstractSubscriptionDualIT { +abstract class AbstractSubscriptionDualIT extends AbstractSubscriptionIT { protected BaseEnv senderEnv; protected BaseEnv receiverEnv; + @Override @Before public void setUp() { + super.setUp(); + MultiEnvFactory.createEnv(2); senderEnv = MultiEnvFactory.getEnv(0); receiverEnv = MultiEnvFactory.getEnv(1); @@ -42,7 +46,7 @@ public void setUp() { receiverEnv.initClusterEnvironment(); } - void setUpConfig() { + protected void setUpConfig() { // enable auto create schema senderEnv.getConfig().getCommonConfig().setAutoCreateSchemaEnabled(true); receiverEnv.getConfig().getCommonConfig().setAutoCreateSchemaEnabled(true); @@ -52,8 +56,11 @@ void setUpConfig() { receiverEnv.getConfig().getCommonConfig().setCnConnectionTimeoutMs(600000); } + @Override @After - public final void tearDown() { + public void tearDown() { + super.tearDown(); + senderEnv.cleanClusterEnvironment(); receiverEnv.cleanClusterEnvironment(); } diff --git a/integration-test/src/test/java/org/apache/iotdb/subscription/it/dual/IoTDBSubscriptionConsumerGroupIT.java b/integration-test/src/test/java/org/apache/iotdb/subscription/it/dual/IoTDBSubscriptionConsumerGroupIT.java index 992d151520f90..e332574925004 100644 --- a/integration-test/src/test/java/org/apache/iotdb/subscription/it/dual/IoTDBSubscriptionConsumerGroupIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/subscription/it/dual/IoTDBSubscriptionConsumerGroupIT.java @@ -42,7 +42,6 @@ import org.apache.tsfile.read.expression.QueryExpression; import org.apache.tsfile.read.query.dataset.QueryDataSet; import org.apache.tsfile.utils.Pair; -import org.awaitility.Awaitility; import org.junit.Assert; import org.junit.Before; import org.junit.Test; @@ -62,11 +61,11 @@ import java.util.Map; import java.util.Properties; import java.util.Set; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.LockSupport; import java.util.stream.Collectors; +import static org.apache.iotdb.subscription.it.IoTDBSubscriptionITConstant.AWAIT; import static org.junit.Assert.fail; @RunWith(IoTDBTestRunner.class) @@ -109,7 +108,7 @@ static final class SubscriptionInfo { } @Override - void setUpConfig() { + protected void setUpConfig() { super.setUpConfig(); // Enable air gap receiver @@ -1005,31 +1004,36 @@ private void pollMessagesAndCheck( LOGGER.info("consumer {} exiting...", consumers.get(index)); } }, - consumers.get(index).toString()); + String.format("%s - %s", testName.getMethodName(), consumers.get(index).toString())); t.start(); threads.add(t); } // Check data on receiver + final long[] currentTime = {System.currentTimeMillis()}; try { try (final Connection connection = receiverEnv.getConnection(); final Statement statement = connection.createStatement()) { // Keep retrying if there are execution failures - Awaitility.await() - .pollDelay(IoTDBSubscriptionITConstant.AWAITILITY_POLL_DELAY_SECOND, TimeUnit.SECONDS) - .pollInterval( - IoTDBSubscriptionITConstant.AWAITILITY_POLL_INTERVAL_SECOND, TimeUnit.SECONDS) - .atMost(IoTDBSubscriptionITConstant.AWAITILITY_AT_MOST_SECOND, TimeUnit.SECONDS) - .untilAsserted( - () -> { - if (receiverCrashed.get()) { - LOGGER.info("detect receiver crashed, skipping this test..."); - return; - } - TestUtils.assertSingleResultSetEqual( - TestUtils.executeQueryWithRetry(statement, "select count(*) from root.**"), - expectedHeaderWithResult); - }); + AWAIT.untilAsserted( + () -> { + if (receiverCrashed.get()) { + LOGGER.info("detect receiver crashed, skipping this test..."); + return; + } + // potential stuck + if (System.currentTimeMillis() - currentTime[0] > 60_000L) { + for (final DataNodeWrapper wrapper : senderEnv.getDataNodeWrapperList()) { + wrapper.executeJstack(); + // wrapper.executeJstack(String.format("%s_%s", testName.getMethodName(), + // currentTime[0])); + } + currentTime[0] = System.currentTimeMillis(); + } + TestUtils.assertSingleResultSetEqual( + TestUtils.executeQueryWithRetry(statement, "select count(*) from root.**"), + expectedHeaderWithResult); + }); } } catch (final Exception e) { e.printStackTrace(); diff --git a/integration-test/src/test/java/org/apache/iotdb/subscription/it/dual/IoTDBSubscriptionTimePrecisionIT.java b/integration-test/src/test/java/org/apache/iotdb/subscription/it/dual/IoTDBSubscriptionTimePrecisionIT.java index 2b1cc407b7f79..39a9f2225f6bb 100644 --- a/integration-test/src/test/java/org/apache/iotdb/subscription/it/dual/IoTDBSubscriptionTimePrecisionIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/subscription/it/dual/IoTDBSubscriptionTimePrecisionIT.java @@ -30,7 +30,6 @@ import org.apache.iotdb.subscription.it.IoTDBSubscriptionITConstant; import org.apache.tsfile.write.record.Tablet; -import org.awaitility.Awaitility; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -43,10 +42,10 @@ import java.util.Iterator; import java.util.List; import java.util.Properties; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.LockSupport; +import static org.apache.iotdb.subscription.it.IoTDBSubscriptionITConstant.AWAIT; import static org.junit.Assert.fail; @RunWith(IoTDBTestRunner.class) @@ -57,7 +56,7 @@ public class IoTDBSubscriptionTimePrecisionIT extends AbstractSubscriptionDualIT LoggerFactory.getLogger(IoTDBSubscriptionTimePrecisionIT.class); @Override - void setUpConfig() { + protected void setUpConfig() { super.setUpConfig(); // Set timestamp precision to nanosecond @@ -160,7 +159,8 @@ public void testTopicTimePrecision() throws Exception { } finally { LOGGER.info("consumer exiting..."); } - }); + }, + String.format("%s - consumer", testName.getMethodName())); thread.start(); // Check data on receiver @@ -168,21 +168,16 @@ public void testTopicTimePrecision() throws Exception { try (final Connection connection = receiverEnv.getConnection(); final Statement statement = connection.createStatement()) { // Keep retrying if there are execution failures - Awaitility.await() - .pollDelay(IoTDBSubscriptionITConstant.AWAITILITY_POLL_DELAY_SECOND, TimeUnit.SECONDS) - .pollInterval( - IoTDBSubscriptionITConstant.AWAITILITY_POLL_INTERVAL_SECOND, TimeUnit.SECONDS) - .atMost(IoTDBSubscriptionITConstant.AWAITILITY_AT_MOST_SECOND, TimeUnit.SECONDS) - .untilAsserted( - () -> - TestUtils.assertSingleResultSetEqual( - TestUtils.executeQueryWithRetry(statement, "select count(*) from root.**"), - new HashMap() { - { - put("count(root.db.d1.s2)", "100"); - put("count(root.db.d2.s1)", "100"); - } - })); + AWAIT.untilAsserted( + () -> + TestUtils.assertSingleResultSetEqual( + TestUtils.executeQueryWithRetry(statement, "select count(*) from root.**"), + new HashMap() { + { + put("count(root.db.d1.s2)", "100"); + put("count(root.db.d2.s1)", "100"); + } + })); } } catch (final Exception e) { e.printStackTrace(); diff --git a/integration-test/src/test/java/org/apache/iotdb/subscription/it/dual/IoTDBSubscriptionTopicIT.java b/integration-test/src/test/java/org/apache/iotdb/subscription/it/dual/IoTDBSubscriptionTopicIT.java index 0cd6bc0d0a106..d4aee45c482ad 100644 --- a/integration-test/src/test/java/org/apache/iotdb/subscription/it/dual/IoTDBSubscriptionTopicIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/subscription/it/dual/IoTDBSubscriptionTopicIT.java @@ -20,12 +20,15 @@ package org.apache.iotdb.subscription.it.dual; import org.apache.iotdb.commons.client.sync.SyncConfigNodeIServiceClient; +import org.apache.iotdb.confignode.rpc.thrift.TShowSubscriptionReq; +import org.apache.iotdb.confignode.rpc.thrift.TShowSubscriptionResp; import org.apache.iotdb.confignode.rpc.thrift.TShowTopicInfo; import org.apache.iotdb.confignode.rpc.thrift.TShowTopicReq; import org.apache.iotdb.db.it.utils.TestUtils; import org.apache.iotdb.isession.ISession; import org.apache.iotdb.it.framework.IoTDBTestRunner; import org.apache.iotdb.itbase.category.MultiClusterIT2Subscription; +import org.apache.iotdb.rpc.RpcUtils; import org.apache.iotdb.rpc.subscription.config.TopicConstant; import org.apache.iotdb.rpc.subscription.exception.SubscriptionRuntimeCriticalException; import org.apache.iotdb.session.subscription.SubscriptionSession; @@ -33,8 +36,11 @@ import org.apache.iotdb.session.subscription.payload.SubscriptionMessage; import org.apache.iotdb.subscription.it.IoTDBSubscriptionITConstant; +import org.apache.tsfile.read.TsFileReader; +import org.apache.tsfile.read.common.Path; +import org.apache.tsfile.read.expression.QueryExpression; +import org.apache.tsfile.read.query.dataset.QueryDataSet; import org.apache.tsfile.write.record.Tablet; -import org.awaitility.Awaitility; import org.junit.Assert; import org.junit.Test; import org.junit.experimental.categories.Category; @@ -45,17 +51,18 @@ import java.sql.Connection; import java.sql.Statement; import java.util.ArrayList; +import java.util.Collections; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Properties; import java.util.Set; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.locks.LockSupport; +import static org.apache.iotdb.subscription.it.IoTDBSubscriptionITConstant.AWAIT; import static org.junit.Assert.fail; @RunWith(IoTDBTestRunner.class) @@ -64,6 +71,19 @@ public class IoTDBSubscriptionTopicIT extends AbstractSubscriptionDualIT { private static final Logger LOGGER = LoggerFactory.getLogger(IoTDBSubscriptionTopicIT.class); + @Override + protected void setUpConfig() { + super.setUpConfig(); + + // Shorten heartbeat and sync interval to avoid timeout of query mode test + senderEnv + .getConfig() + .getCommonConfig() + .setPipeHeartbeatIntervalSecondsForCollectingPipeMeta(30); + senderEnv.getConfig().getCommonConfig().setPipeMetaSyncerInitialSyncDelayMinutes(1); + senderEnv.getConfig().getCommonConfig().setPipeMetaSyncerSyncIntervalMinutes(1); + } + @Test public void testTopicPathSubscription() throws Exception { // Insert some historical data on sender @@ -136,7 +156,8 @@ public void testTopicPathSubscription() throws Exception { } finally { LOGGER.info("consumer exiting..."); } - }); + }, + String.format("%s - consumer", testName.getMethodName())); thread.start(); // Check data on receiver @@ -144,21 +165,16 @@ public void testTopicPathSubscription() throws Exception { try (final Connection connection = receiverEnv.getConnection(); final Statement statement = connection.createStatement()) { // Keep retrying if there are execution failures - Awaitility.await() - .pollDelay(IoTDBSubscriptionITConstant.AWAITILITY_POLL_DELAY_SECOND, TimeUnit.SECONDS) - .pollInterval( - IoTDBSubscriptionITConstant.AWAITILITY_POLL_INTERVAL_SECOND, TimeUnit.SECONDS) - .atMost(IoTDBSubscriptionITConstant.AWAITILITY_AT_MOST_SECOND, TimeUnit.SECONDS) - .untilAsserted( - () -> - TestUtils.assertSingleResultSetEqual( - TestUtils.executeQueryWithRetry(statement, "select count(*) from root.**"), - new HashMap() { - { - put("count(root.db.d1.s)", "100"); - put("count(root.db.d2.s)", "100"); - } - })); + AWAIT.untilAsserted( + () -> + TestUtils.assertSingleResultSetEqual( + TestUtils.executeQueryWithRetry(statement, "select count(*) from root.**"), + new HashMap() { + { + put("count(root.db.d1.s)", "100"); + put("count(root.db.d2.s)", "100"); + } + })); } } catch (final Exception e) { e.printStackTrace(); @@ -238,7 +254,8 @@ public void testTopicTimeSubscription() throws Exception { } finally { LOGGER.info("consumer exiting..."); } - }); + }, + String.format("%s - consumer", testName.getMethodName())); thread.start(); // Check data on receiver @@ -246,20 +263,15 @@ public void testTopicTimeSubscription() throws Exception { try (final Connection connection = receiverEnv.getConnection(); final Statement statement = connection.createStatement()) { // Keep retrying if there are execution failures - Awaitility.await() - .pollDelay(IoTDBSubscriptionITConstant.AWAITILITY_POLL_DELAY_SECOND, TimeUnit.SECONDS) - .pollInterval( - IoTDBSubscriptionITConstant.AWAITILITY_POLL_INTERVAL_SECOND, TimeUnit.SECONDS) - .atMost(IoTDBSubscriptionITConstant.AWAITILITY_AT_MOST_SECOND, TimeUnit.SECONDS) - .untilAsserted( - () -> - TestUtils.assertSingleResultSetEqual( - TestUtils.executeQueryWithRetry(statement, "select count(*) from root.**"), - new HashMap() { - { - put("count(root.db.d2.s)", "100"); - } - })); + AWAIT.untilAsserted( + () -> + TestUtils.assertSingleResultSetEqual( + TestUtils.executeQueryWithRetry(statement, "select count(*) from root.**"), + new HashMap() { + { + put("count(root.db.d2.s)", "100"); + } + })); } } catch (final Exception e) { e.printStackTrace(); @@ -336,7 +348,8 @@ public void testTopicProcessorSubscription() throws Exception { } finally { LOGGER.info("consumer exiting..."); } - }); + }, + String.format("%s - consumer", testName.getMethodName())); thread.start(); // Check data on receiver @@ -348,17 +361,12 @@ public void testTopicProcessorSubscription() throws Exception { try (final Connection connection = receiverEnv.getConnection(); final Statement statement = connection.createStatement()) { // Keep retrying if there are execution failures - Awaitility.await() - .pollDelay(IoTDBSubscriptionITConstant.AWAITILITY_POLL_DELAY_SECOND, TimeUnit.SECONDS) - .pollInterval( - IoTDBSubscriptionITConstant.AWAITILITY_POLL_INTERVAL_SECOND, TimeUnit.SECONDS) - .atMost(IoTDBSubscriptionITConstant.AWAITILITY_AT_MOST_SECOND, TimeUnit.SECONDS) - .untilAsserted( - () -> - TestUtils.assertResultSetEqual( - TestUtils.executeQueryWithRetry(statement, "select * from root.**"), - "Time,root.db.d1.at1,", - expectedResSet)); + AWAIT.untilAsserted( + () -> + TestUtils.assertResultSetEqual( + TestUtils.executeQueryWithRetry(statement, "select * from root.**"), + "Time,root.db.d1.at1,", + expectedResSet)); } } catch (final Exception e) { e.printStackTrace(); @@ -392,9 +400,9 @@ public void testTopicNameWithBackQuote() throws Exception { } // Create topic on sender - final String topic1 = "`topic1`"; - final String topic2 = "`'topic2'`"; - final String topic3 = "`\"topic3\"`"; + final String topic1 = "`topic4`"; + final String topic2 = "`'topic5'`"; + final String topic3 = "`\"topic6\"`"; final String host = senderEnv.getIP(); final int port = Integer.parseInt(senderEnv.getPort()); try (final SubscriptionSession session = new SubscriptionSession(host, port)) { @@ -464,7 +472,8 @@ public void testTopicNameWithBackQuote() throws Exception { } finally { LOGGER.info("consumer exiting..."); } - }); + }, + String.format("%s - consumer", testName.getMethodName())); thread.start(); // Check data on receiver @@ -472,20 +481,15 @@ public void testTopicNameWithBackQuote() throws Exception { try (final Connection connection = receiverEnv.getConnection(); final Statement statement = connection.createStatement()) { // Keep retrying if there are execution failures - Awaitility.await() - .pollDelay(IoTDBSubscriptionITConstant.AWAITILITY_POLL_DELAY_SECOND, TimeUnit.SECONDS) - .pollInterval( - IoTDBSubscriptionITConstant.AWAITILITY_POLL_INTERVAL_SECOND, TimeUnit.SECONDS) - .atMost(IoTDBSubscriptionITConstant.AWAITILITY_AT_MOST_SECOND, TimeUnit.SECONDS) - .untilAsserted( - () -> - TestUtils.assertSingleResultSetEqual( - TestUtils.executeQueryWithRetry(statement, "select count(*) from root.**"), - new HashMap() { - { - put("count(root.db.d1.s)", "300"); - } - })); + AWAIT.untilAsserted( + () -> + TestUtils.assertSingleResultSetEqual( + TestUtils.executeQueryWithRetry(statement, "select count(*) from root.**"), + new HashMap() { + { + put("count(root.db.d1.s)", "300"); + } + })); } } catch (final Exception e) { e.printStackTrace(); @@ -507,7 +511,7 @@ public void testTopicInvalidTimeRangeConfig() throws Exception { final Properties properties = new Properties(); properties.put(TopicConstant.START_TIME_KEY, "2024-01-32"); properties.put(TopicConstant.END_TIME_KEY, TopicConstant.NOW_TIME_VALUE); - session.createTopic("topic1", properties); + session.createTopic("topic7", properties); fail(); } catch (final Exception ignored) { } @@ -519,7 +523,7 @@ public void testTopicInvalidTimeRangeConfig() throws Exception { final Properties properties = new Properties(); properties.put(TopicConstant.START_TIME_KEY, "2001.01.01T08:00:00"); properties.put(TopicConstant.END_TIME_KEY, "2000.01.01T08:00:00"); - session.createTopic("topic2", properties); + session.createTopic("topic8", properties); fail(); } catch (final Exception ignored) { } @@ -529,21 +533,258 @@ public void testTopicInvalidTimeRangeConfig() throws Exception { @Test public void testTopicInvalidPathConfig() throws Exception { // Test invalid path when using tsfile format + // NOTE: Delete this test after the restriction "on path/time range/processor when subscribing + // to tsfile" is removed. final Properties config = new Properties(); config.put(TopicConstant.FORMAT_KEY, TopicConstant.FORMAT_TS_FILE_HANDLER_VALUE); config.put(TopicConstant.PATH_KEY, "root.db.*.s"); - testTopicInvalidRuntimeConfigTemplate("topic3", config); + testTopicInvalidRuntimeConfigTemplate("topic9", config); } @Test public void testTopicInvalidProcessorConfig() throws Exception { // Test invalid processor when using tsfile format + // NOTE: Delete this test after the restriction "on path/time range/processor when subscribing + // to tsfile" is removed. final Properties config = new Properties(); config.put(TopicConstant.FORMAT_KEY, TopicConstant.FORMAT_TS_FILE_HANDLER_VALUE); config.put("processor", "tumbling-time-sampling-processor"); config.put("processor.tumbling-time.interval-seconds", "1"); config.put("processor.down-sampling.split-file", "true"); - testTopicInvalidRuntimeConfigTemplate("topic4", config); + testTopicInvalidRuntimeConfigTemplate("topic10", config); + } + + @Test + public void testTopicWithQueryMode() throws Exception { + // Insert some historical data + try (final ISession session = senderEnv.getSessionConnection()) { + for (int i = 0; i < 100; ++i) { + session.executeNonQueryStatement( + String.format("insert into root.db.d1(time, s1) values (%s, 1)", i)); + } + session.executeNonQueryStatement("flush"); + } catch (final Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } + + // Create topic + final String topicName = "topic11"; + final String host = senderEnv.getIP(); + final int port = Integer.parseInt(senderEnv.getPort()); + try (final SubscriptionSession session = new SubscriptionSession(host, port)) { + session.open(); + final Properties config = new Properties(); + config.put(TopicConstant.FORMAT_KEY, TopicConstant.FORMAT_TS_FILE_HANDLER_VALUE); + config.put(TopicConstant.MODE_KEY, TopicConstant.MODE_QUERY_VALUE); + session.createTopic(topicName, config); + } catch (final Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } + assertTopicCount(1); + + // Subscription + final AtomicInteger rowCount = new AtomicInteger(); + final AtomicBoolean isClosed = new AtomicBoolean(false); + final Thread thread = + new Thread( + () -> { + try (final SubscriptionPullConsumer consumer = + new SubscriptionPullConsumer.Builder() + .host(host) + .port(port) + .consumerId("c1") + .consumerGroupId("cg1") + .autoCommit(false) + .buildPullConsumer()) { + consumer.open(); + consumer.subscribe(topicName); + while (!isClosed.get()) { + LockSupport.parkNanos(IoTDBSubscriptionITConstant.SLEEP_NS); // wait some time + final List messages = + consumer.poll(IoTDBSubscriptionITConstant.POLL_TIMEOUT_MS); + for (final SubscriptionMessage message : messages) { + try (final TsFileReader tsFileReader = + message.getTsFileHandler().openReader()) { + final Path path = new Path("root.db.d1", "s1", true); + final QueryDataSet dataSet = + tsFileReader.query( + QueryExpression.create(Collections.singletonList(path), null)); + while (dataSet.hasNext()) { + dataSet.next(); + rowCount.addAndGet(1); + } + } + } + consumer.commitSync(messages); + } + // Exiting the loop represents passing the awaitility test, at this point the result + // of 'show subscription' is empty, so there is no need to explicitly unsubscribe. + } catch (final Exception e) { + e.printStackTrace(); + // Avoid failure + } finally { + LOGGER.info("consumer exiting..."); + } + }, + String.format("%s - consumer", testName.getMethodName())); + thread.start(); + + try { + // Keep retrying if there are execution failures + AWAIT.untilAsserted( + () -> { + // Check row count + Assert.assertEquals(100, rowCount.get()); + // Check empty subscription + try (final SyncConfigNodeIServiceClient client = + (SyncConfigNodeIServiceClient) senderEnv.getLeaderConfigNodeConnection()) { + final TShowSubscriptionResp showSubscriptionResp = + client.showSubscription(new TShowSubscriptionReq()); + Assert.assertEquals( + RpcUtils.SUCCESS_STATUS.getCode(), showSubscriptionResp.status.getCode()); + Assert.assertNotNull(showSubscriptionResp.subscriptionInfoList); + Assert.assertEquals(0, showSubscriptionResp.subscriptionInfoList.size()); + } + }); + } catch (final Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } finally { + isClosed.set(true); + thread.join(); + } + } + + @Test + public void testTopicWithLooseRange() throws Exception { + // Insert some historical data on sender + try (final ISession session = senderEnv.getSessionConnection()) { + session.executeNonQueryStatement( + "insert into root.db.d1 (time, at1, at2) values (1000, 1, 2), (2000, 3, 4)"); + session.executeNonQueryStatement( + "insert into root.db1.d1 (time, at1, at2) values (1000, 1, 2), (2000, 3, 4)"); + session.executeNonQueryStatement( + "insert into root.db.d1 (time, at1, at2) values (3000, 1, 2), (4000, 3, 4)"); + session.executeNonQueryStatement("flush"); + } catch (final Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } + + // Create topic + final String topicName = "topic12"; + final String host = senderEnv.getIP(); + final int port = Integer.parseInt(senderEnv.getPort()); + try (final SubscriptionSession session = new SubscriptionSession(host, port)) { + session.open(); + final Properties config = new Properties(); + config.put(TopicConstant.LOOSE_RANGE_KEY, TopicConstant.LOOSE_RANGE_TIME_AND_PATH_VALUE); + config.put(TopicConstant.PATH_KEY, "root.db.d1.at1"); + config.put(TopicConstant.START_TIME_KEY, "1500"); + config.put(TopicConstant.END_TIME_KEY, "2500"); + session.createTopic(topicName, config); + } catch (final Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } + assertTopicCount(1); + + final AtomicBoolean dataPrepared = new AtomicBoolean(false); + final AtomicBoolean topicSubscribed = new AtomicBoolean(false); + final AtomicBoolean result = new AtomicBoolean(false); + final List threads = new ArrayList<>(); + + // Subscribe on sender + threads.add( + new Thread( + () -> { + try (final SubscriptionPullConsumer consumer = + new SubscriptionPullConsumer.Builder() + .host(host) + .port(port) + .consumerId("c1") + .consumerGroupId("cg1") + .autoCommit(false) + .buildPullConsumer(); + final ISession session = receiverEnv.getSessionConnection()) { + consumer.open(); + consumer.subscribe(topicName); + topicSubscribed.set(true); + while (!result.get()) { + LockSupport.parkNanos(IoTDBSubscriptionITConstant.SLEEP_NS); // wait some time + if (dataPrepared.get()) { + final List messages = + consumer.poll(IoTDBSubscriptionITConstant.POLL_TIMEOUT_MS); + for (final SubscriptionMessage message : messages) { + for (final Iterator it = + message.getSessionDataSetsHandler().tabletIterator(); + it.hasNext(); ) { + final Tablet tablet = it.next(); + session.insertTablet(tablet); + } + } + consumer.commitSync(messages); + } + } + consumer.unsubscribe(topicName); + } catch (final Exception e) { + e.printStackTrace(); + // Avoid failure + } finally { + LOGGER.info("consumer exiting..."); + } + }, + String.format("%s - consumer", testName.getMethodName()))); + + // Insert some realtime data on sender + threads.add( + new Thread( + () -> { + while (!topicSubscribed.get()) { + LockSupport.parkNanos(IoTDBSubscriptionITConstant.SLEEP_NS); // wait some time + } + try (final ISession session = senderEnv.getSessionConnection()) { + session.executeNonQueryStatement( + "insert into root.db.d1 (time, at1, at2) values (1001, 1, 2), (2001, 3, 4)"); + session.executeNonQueryStatement( + "insert into root.db1.d1 (time, at1, at2) values (1001, 1, 2), (2001, 3, 4)"); + session.executeNonQueryStatement( + "insert into root.db.d1 (time, at1, at2) values (3001, 1, 2), (4001, 3, 4)"); + session.executeNonQueryStatement("flush"); + } catch (final Exception e) { + e.printStackTrace(); + fail(e.getMessage()); + } + dataPrepared.set(true); + }, + String.format("%s - data inserter", testName.getMethodName()))); + + for (final Thread thread : threads) { + thread.start(); + } + + try (final Connection connection = receiverEnv.getConnection(); + final Statement statement = connection.createStatement()) { + // Keep retrying if there are execution failures + AWAIT.untilAsserted( + () -> + TestUtils.assertSingleResultSetEqual( + TestUtils.executeQueryWithRetry( + statement, + "select count(at1) from root.db.d1 where time >= 1500 and time <= 2500"), + new HashMap() { + { + put("count(root.db.d1.at1)", "2"); + } + })); + } + + result.set(true); + for (final Thread thread : threads) { + thread.join(); + } } private void testTopicInvalidRuntimeConfigTemplate( @@ -600,7 +841,8 @@ private void testTopicInvalidRuntimeConfigTemplate( } finally { LOGGER.info("consumer exiting..."); } - })); + }, + String.format("%s - consumer", testName.getMethodName()))); // Insert some realtime data on sender threads.add( @@ -628,18 +870,15 @@ private void testTopicInvalidRuntimeConfigTemplate( fail(e.getMessage()); } dataPrepared.set(true); - })); + }, + String.format("%s - data inserter", testName.getMethodName()))); for (final Thread thread : threads) { thread.start(); } - Awaitility.await() - .pollDelay(IoTDBSubscriptionITConstant.AWAITILITY_POLL_DELAY_SECOND, TimeUnit.SECONDS) - .pollInterval(IoTDBSubscriptionITConstant.AWAITILITY_POLL_INTERVAL_SECOND, TimeUnit.SECONDS) - .atMost(IoTDBSubscriptionITConstant.AWAITILITY_AT_MOST_SECOND, TimeUnit.SECONDS) - // The expected SubscriptionRuntimeCriticalException was not thrown if result is false - .untilTrue(result); + // The expected SubscriptionRuntimeCriticalException was not thrown if result is false + AWAIT.untilTrue(result); for (final Thread thread : threads) { thread.join(); diff --git a/integration-test/src/test/java/org/apache/iotdb/subscription/it/local/AbstractSubscriptionLocalIT.java b/integration-test/src/test/java/org/apache/iotdb/subscription/it/local/AbstractSubscriptionLocalIT.java new file mode 100644 index 0000000000000..bb248f745d4ed --- /dev/null +++ b/integration-test/src/test/java/org/apache/iotdb/subscription/it/local/AbstractSubscriptionLocalIT.java @@ -0,0 +1,45 @@ +/* + * 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.iotdb.subscription.it.local; + +import org.apache.iotdb.it.env.EnvFactory; +import org.apache.iotdb.subscription.it.AbstractSubscriptionIT; + +import org.junit.After; +import org.junit.Before; + +abstract class AbstractSubscriptionLocalIT extends AbstractSubscriptionIT { + + @Override + @Before + public void setUp() { + super.setUp(); + + EnvFactory.getEnv().initClusterEnvironment(); + } + + @Override + @After + public void tearDown() { + super.tearDown(); + + EnvFactory.getEnv().cleanClusterEnvironment(); + } +} diff --git a/integration-test/src/test/java/org/apache/iotdb/subscription/it/local/IoTDBSubscriptionBasicIT.java b/integration-test/src/test/java/org/apache/iotdb/subscription/it/local/IoTDBSubscriptionBasicIT.java index 13a5e8abc2617..e9c97c0689672 100644 --- a/integration-test/src/test/java/org/apache/iotdb/subscription/it/local/IoTDBSubscriptionBasicIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/subscription/it/local/IoTDBSubscriptionBasicIT.java @@ -36,14 +36,16 @@ import org.apache.iotdb.session.subscription.payload.SubscriptionTsFileHandler; import org.apache.iotdb.subscription.it.IoTDBSubscriptionITConstant; +import org.apache.tsfile.common.conf.TSFileConfig; +import org.apache.tsfile.enums.TSDataType; import org.apache.tsfile.read.TsFileReader; import org.apache.tsfile.read.common.Path; +import org.apache.tsfile.read.common.RowRecord; import org.apache.tsfile.read.expression.QueryExpression; import org.apache.tsfile.read.query.dataset.QueryDataSet; -import org.awaitility.Awaitility; -import org.junit.After; +import org.apache.tsfile.utils.Binary; +import org.apache.tsfile.write.record.Tablet; import org.junit.Assert; -import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -53,42 +55,87 @@ import java.nio.file.Files; import java.nio.file.NoSuchFileException; import java.time.Duration; +import java.time.LocalDate; import java.util.ArrayList; import java.util.Collections; import java.util.List; import java.util.Properties; -import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.LockSupport; import java.util.stream.Collectors; +import static org.apache.iotdb.subscription.it.IoTDBSubscriptionITConstant.AWAIT; import static org.junit.Assert.fail; @RunWith(IoTDBTestRunner.class) @Category({LocalStandaloneIT.class}) -public class IoTDBSubscriptionBasicIT { +public class IoTDBSubscriptionBasicIT extends AbstractSubscriptionLocalIT { private static final Logger LOGGER = LoggerFactory.getLogger(IoTDBSubscriptionBasicIT.class); - @Before - public void setUp() throws Exception { - EnvFactory.getEnv().initClusterEnvironment(); + @Test + public void testSubscribeBooleanData() throws Exception { + testBasicSubscribeTablets(TSDataType.BOOLEAN, "true", true); + } + + @Test + public void testSubscribeIntData() throws Exception { + testBasicSubscribeTablets(TSDataType.INT32, "1", 1); + } + + @Test + public void testSubscribeLongData() throws Exception { + testBasicSubscribeTablets(TSDataType.INT64, "1", 1L); + } + + @Test + public void testSubscribeFloatData() throws Exception { + testBasicSubscribeTablets(TSDataType.FLOAT, "1.0", 1.0F); + } + + @Test + public void testSubscribeDoubleData() throws Exception { + testBasicSubscribeTablets(TSDataType.DOUBLE, "1.0", 1.0); + } + + @Test + public void testSubscribeTextData() throws Exception { + testBasicSubscribeTablets(TSDataType.TEXT, "'a'", new Binary("a", TSFileConfig.STRING_CHARSET)); + } + + @Test + public void testSubscribeTimestampData() throws Exception { + testBasicSubscribeTablets(TSDataType.TIMESTAMP, "123", 123L); } - @After - public void tearDown() throws Exception { - EnvFactory.getEnv().cleanClusterEnvironment(); + @Test + public void testSubscribeDateData() throws Exception { + testBasicSubscribeTablets(TSDataType.DATE, "'2011-03-01'", LocalDate.of(2011, 3, 1)); + } + + @Test + public void testSubscribeBlobData() throws Exception { + testBasicSubscribeTablets( + TSDataType.BLOB, "X'f013'", new Binary(new byte[] {(byte) 0xf0, 0x13})); } @Test - public void testBasicSubscribeTablets() throws Exception { + public void testSubscribeStringData() throws Exception { + testBasicSubscribeTablets( + TSDataType.STRING, "'a'", new Binary("a", TSFileConfig.STRING_CHARSET)); + } + + private void testBasicSubscribeTablets( + final TSDataType type, final String valueStr, final Object expectedData) throws Exception { // Insert some historical data try (final ISession session = EnvFactory.getEnv().getSessionConnection()) { + session.executeNonQueryStatement( + String.format("create timeseries root.db.d1.s1 %s", type.toString())); for (int i = 0; i < 100; ++i) { session.executeNonQueryStatement( - String.format("insert into root.db.d1(time, s1) values (%s, 1)", i)); + String.format("insert into root.db.d1(time, s1) values (%s, %s)", i, valueStr)); } session.executeNonQueryStatement("flush"); } catch (final Exception e) { @@ -132,7 +179,12 @@ public void testBasicSubscribeTablets() throws Exception { for (final SubscriptionSessionDataSet dataSet : message.getSessionDataSetsHandler()) { while (dataSet.hasNext()) { - dataSet.next(); + final RowRecord record = dataSet.next(); + Assert.assertEquals(type.toString(), dataSet.getColumnTypes().get(1)); + Assert.assertEquals(type, record.getFields().get(0).getDataType()); + Assert.assertEquals(expectedData, getValue(type, dataSet.getTablet())); + Assert.assertEquals( + expectedData, record.getFields().get(0).getObjectValue(type)); rowCount.addAndGet(1); } } @@ -146,18 +198,14 @@ public void testBasicSubscribeTablets() throws Exception { } finally { LOGGER.info("consumer exiting..."); } - }); + }, + String.format("%s - consumer", testName.getMethodName())); thread.start(); // Check row count try { // Keep retrying if there are execution failures - Awaitility.await() - .pollDelay(IoTDBSubscriptionITConstant.AWAITILITY_POLL_DELAY_SECOND, TimeUnit.SECONDS) - .pollInterval( - IoTDBSubscriptionITConstant.AWAITILITY_POLL_INTERVAL_SECOND, TimeUnit.SECONDS) - .atMost(IoTDBSubscriptionITConstant.AWAITILITY_AT_MOST_SECOND, TimeUnit.SECONDS) - .untilAsserted(() -> Assert.assertEquals(100, rowCount.get())); + AWAIT.untilAsserted(() -> Assert.assertEquals(100, rowCount.get())); } catch (final Exception e) { e.printStackTrace(); fail(e.getMessage()); @@ -167,6 +215,30 @@ public void testBasicSubscribeTablets() throws Exception { } } + private Object getValue(final TSDataType type, final Tablet tablet) { + switch (type) { + case BOOLEAN: + return ((boolean[]) tablet.values[0])[0]; + case INT32: + return ((int[]) tablet.values[0])[0]; + case INT64: + case TIMESTAMP: + return ((long[]) tablet.values[0])[0]; + case FLOAT: + return ((float[]) tablet.values[0])[0]; + case DOUBLE: + return ((double[]) tablet.values[0])[0]; + case TEXT: + case BLOB: + case STRING: + return ((Binary[]) tablet.values[0])[0]; + case DATE: + return ((LocalDate[]) tablet.values[0])[0]; + default: + return null; + } + } + @Test public void testBasicSubscribeTsFile() throws Exception { // Insert some historical data @@ -242,18 +314,14 @@ public void testBasicSubscribeTsFile() throws Exception { } finally { LOGGER.info("consumer exiting..."); } - }); + }, + String.format("%s - consumer", testName.getMethodName())); thread.start(); // Check row count try { // Keep retrying if there are execution failures - Awaitility.await() - .pollDelay(IoTDBSubscriptionITConstant.AWAITILITY_POLL_DELAY_SECOND, TimeUnit.SECONDS) - .pollInterval( - IoTDBSubscriptionITConstant.AWAITILITY_POLL_INTERVAL_SECOND, TimeUnit.SECONDS) - .atMost(IoTDBSubscriptionITConstant.AWAITILITY_AT_MOST_SECOND, TimeUnit.SECONDS) - .untilAsserted(() -> Assert.assertEquals(100, rowCount.get())); + AWAIT.untilAsserted(() -> Assert.assertEquals(100, rowCount.get())); } catch (final Exception e) { e.printStackTrace(); fail(e.getMessage()); @@ -379,18 +447,14 @@ public void onFailure(final Throwable e) { } finally { LOGGER.info("consumer exiting..."); } - }); + }, + String.format("%s - consumer", testName.getMethodName())); thread.start(); // Check row count try { // Keep retrying if there are execution failures - Awaitility.await() - .pollDelay(IoTDBSubscriptionITConstant.AWAITILITY_POLL_DELAY_SECOND, TimeUnit.SECONDS) - .pollInterval( - IoTDBSubscriptionITConstant.AWAITILITY_POLL_INTERVAL_SECOND, TimeUnit.SECONDS) - .atMost(IoTDBSubscriptionITConstant.AWAITILITY_AT_MOST_SECOND, TimeUnit.SECONDS) - .untilAsserted(() -> Assert.assertEquals(100, rowCount.get())); + AWAIT.untilAsserted(() -> Assert.assertEquals(100, rowCount.get())); Assert.assertTrue(commitSuccessCount.get() > lastCommitSuccessCount.get()); Assert.assertEquals(0, commitFailureCount.get()); } catch (final Exception e) { @@ -416,12 +480,7 @@ public void onFailure(final Throwable e) { // Check row count try { // Keep retrying if there are execution failures - Awaitility.await() - .pollDelay(IoTDBSubscriptionITConstant.AWAITILITY_POLL_DELAY_SECOND, TimeUnit.SECONDS) - .pollInterval( - IoTDBSubscriptionITConstant.AWAITILITY_POLL_INTERVAL_SECOND, TimeUnit.SECONDS) - .atMost(IoTDBSubscriptionITConstant.AWAITILITY_AT_MOST_SECOND, TimeUnit.SECONDS) - .untilAsserted(() -> Assert.assertEquals(200, rowCount.get())); + AWAIT.untilAsserted(() -> Assert.assertEquals(200, rowCount.get())); Assert.assertTrue(commitSuccessCount.get() > lastCommitSuccessCount.get()); Assert.assertEquals(0, commitFailureCount.get()); } catch (final Exception e) { @@ -486,16 +545,11 @@ public void testBasicPushConsumer() { consumer.subscribe(topicName); // The push consumer should automatically poll 10 rows of data by 1 onReceive() - Awaitility.await() - .pollDelay(IoTDBSubscriptionITConstant.AWAITILITY_POLL_DELAY_SECOND, TimeUnit.SECONDS) - .pollInterval( - IoTDBSubscriptionITConstant.AWAITILITY_POLL_INTERVAL_SECOND, TimeUnit.SECONDS) - .atMost(IoTDBSubscriptionITConstant.AWAITILITY_AT_MOST_SECOND, TimeUnit.SECONDS) - .untilAsserted( - () -> { - Assert.assertEquals(10, rowCount.get()); - Assert.assertTrue(onReceiveCount.get() > lastOnReceiveCount.get()); - }); + AWAIT.untilAsserted( + () -> { + Assert.assertEquals(10, rowCount.get()); + Assert.assertTrue(onReceiveCount.get() > lastOnReceiveCount.get()); + }); lastOnReceiveCount.set(onReceiveCount.get()); @@ -508,16 +562,11 @@ public void testBasicPushConsumer() { session.executeNonQueryStatement("flush"); } - Awaitility.await() - .pollDelay(IoTDBSubscriptionITConstant.AWAITILITY_POLL_DELAY_SECOND, TimeUnit.SECONDS) - .pollInterval( - IoTDBSubscriptionITConstant.AWAITILITY_POLL_INTERVAL_SECOND, TimeUnit.SECONDS) - .atMost(IoTDBSubscriptionITConstant.AWAITILITY_AT_MOST_SECOND, TimeUnit.SECONDS) - .untilAsserted( - () -> { - Assert.assertEquals(20, rowCount.get()); - Assert.assertTrue(onReceiveCount.get() > lastOnReceiveCount.get()); - }); + AWAIT.untilAsserted( + () -> { + Assert.assertEquals(20, rowCount.get()); + Assert.assertTrue(onReceiveCount.get() > lastOnReceiveCount.get()); + }); lastOnReceiveCount.set(onReceiveCount.get()); @@ -529,16 +578,11 @@ public void testBasicPushConsumer() { session.executeNonQueryStatement("flush"); } - Awaitility.await() - .pollDelay(IoTDBSubscriptionITConstant.AWAITILITY_POLL_DELAY_SECOND, TimeUnit.SECONDS) - .pollInterval( - IoTDBSubscriptionITConstant.AWAITILITY_POLL_INTERVAL_SECOND, TimeUnit.SECONDS) - .atMost(IoTDBSubscriptionITConstant.AWAITILITY_AT_MOST_SECOND, TimeUnit.SECONDS) - .untilAsserted( - () -> { - Assert.assertEquals(30, rowCount.get()); - Assert.assertTrue(onReceiveCount.get() > lastOnReceiveCount.get()); - }); + AWAIT.untilAsserted( + () -> { + Assert.assertEquals(30, rowCount.get()); + Assert.assertTrue(onReceiveCount.get() > lastOnReceiveCount.get()); + }); consumer.unsubscribe(topicName); } catch (final Exception e) { @@ -624,22 +668,18 @@ public void testPollUnsubscribedTopics() throws Exception { } finally { LOGGER.info("consumer exiting..."); } - }); + }, + String.format("%s - consumer", testName.getMethodName())); thread.start(); // Check row count try { // Keep retrying if there are execution failures - Awaitility.await() - .pollDelay(IoTDBSubscriptionITConstant.AWAITILITY_POLL_DELAY_SECOND, TimeUnit.SECONDS) - .pollInterval( - IoTDBSubscriptionITConstant.AWAITILITY_POLL_INTERVAL_SECOND, TimeUnit.SECONDS) - .atMost(IoTDBSubscriptionITConstant.AWAITILITY_AT_MOST_SECOND, TimeUnit.SECONDS) - .untilAsserted( - () -> { - Assert.assertEquals(100, rowCount.get()); - Assert.assertEquals((100 + 199) * 100 / 2, timestampSum.get()); - }); + AWAIT.untilAsserted( + () -> { + Assert.assertEquals(100, rowCount.get()); + Assert.assertEquals((100 + 199) * 100 / 2, timestampSum.get()); + }); } catch (final Exception e) { e.printStackTrace(); fail(e.getMessage()); diff --git a/integration-test/src/test/java/org/apache/iotdb/subscription/it/local/IoTDBSubscriptionIdempotentIT.java b/integration-test/src/test/java/org/apache/iotdb/subscription/it/local/IoTDBSubscriptionIdempotentIT.java index b671acd6709f4..85fff437f18e6 100644 --- a/integration-test/src/test/java/org/apache/iotdb/subscription/it/local/IoTDBSubscriptionIdempotentIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/subscription/it/local/IoTDBSubscriptionIdempotentIT.java @@ -25,9 +25,7 @@ import org.apache.iotdb.session.subscription.SubscriptionSession; import org.apache.iotdb.session.subscription.consumer.SubscriptionPullConsumer; -import org.junit.After; import org.junit.Assert; -import org.junit.Before; import org.junit.Test; import org.junit.experimental.categories.Category; import org.junit.runner.RunWith; @@ -38,20 +36,10 @@ @RunWith(IoTDBTestRunner.class) @Category({LocalStandaloneIT.class}) -public class IoTDBSubscriptionIdempotentIT { +public class IoTDBSubscriptionIdempotentIT extends AbstractSubscriptionLocalIT { private static final Logger LOGGER = LoggerFactory.getLogger(IoTDBSubscriptionIdempotentIT.class); - @Before - public void setUp() throws Exception { - EnvFactory.getEnv().initClusterEnvironment(); - } - - @After - public void tearDown() throws Exception { - EnvFactory.getEnv().cleanClusterEnvironment(); - } - @Test public void testSubscribeOrUnsubscribeNonExistedTopicTest() { final String host = EnvFactory.getEnv().getIP(); diff --git a/integration-test/src/test/java/org/apache/iotdb/tools/it/ExportTsFileTestIT.java b/integration-test/src/test/java/org/apache/iotdb/tools/it/ExportTsFileTestIT.java index 71a3d62a382ab..5994d4d554eea 100644 --- a/integration-test/src/test/java/org/apache/iotdb/tools/it/ExportTsFileTestIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/tools/it/ExportTsFileTestIT.java @@ -90,7 +90,7 @@ protected void testOnWindows() throws IOException { "root", "-pw", "root", - "-td", + "-t", "target", "-q", "select * from root.test.t2 where time > 1 and time < 1000000000000", @@ -116,7 +116,7 @@ protected void testOnWindows() throws IOException { "root", "-pw", "root", - "-td", + "-t", "target", "-q", "select * from root.test.t2 where time > 1 and time < 1000000000000", @@ -143,7 +143,7 @@ protected void testOnUnix() throws IOException { "root", "-pw", "root", - "-td", + "-t", "target", "-q", "select * from root.**"); @@ -166,7 +166,7 @@ protected void testOnUnix() throws IOException { "root", "-pw", "root", - "-td", + "-t", "target", "-q", "select * from root.**"); diff --git a/integration-test/src/test/java/org/apache/iotdb/util/AbstractSchemaIT.java b/integration-test/src/test/java/org/apache/iotdb/util/AbstractSchemaIT.java index deefd0cccc90e..1c3f3708ae374 100644 --- a/integration-test/src/test/java/org/apache/iotdb/util/AbstractSchemaIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/util/AbstractSchemaIT.java @@ -100,6 +100,14 @@ protected static void clearSchema() throws Exception { "DROP DEVICE TEMPLATE " + resultSet.getString(ColumnHeaderConstant.TEMPLATE_NAME)); } } + // drop all users + try (ResultSet resultSet = statement.executeQuery("LIST USER")) { + while (resultSet.next()) { + if (!resultSet.getString(ColumnHeaderConstant.USER).equals("root")) { + statement.execute("DROP USER " + resultSet.getString(ColumnHeaderConstant.USER)); + } + } + } } } diff --git a/iotdb-api/pipe-api/src/main/java/org/apache/iotdb/pipe/api/access/Row.java b/iotdb-api/pipe-api/src/main/java/org/apache/iotdb/pipe/api/access/Row.java index b3c1342347da1..f22ac5e026dc6 100644 --- a/iotdb-api/pipe-api/src/main/java/org/apache/iotdb/pipe/api/access/Row.java +++ b/iotdb-api/pipe-api/src/main/java/org/apache/iotdb/pipe/api/access/Row.java @@ -25,6 +25,7 @@ import org.apache.tsfile.read.common.Path; +import java.time.LocalDate; import java.util.List; public interface Row { @@ -44,17 +45,28 @@ public interface Row { * @param columnIndex index of the specified column * @return the int value at the specified column in this row */ - int getInt(int columnIndex); + int getInt(final int columnIndex); + + /** + * Returns the localDate value at the specified column in this row. + * + *

Users need to ensure that the data type of the specified column is {@code Type.DATE}. + * + * @param columnIndex index of the specified column + * @return the int value at the specified column in this row + */ + LocalDate getDate(final int columnIndex); /** * Returns the long value at the specified column in this row. * - *

Users need to ensure that the data type of the specified column is {@code Type.INT64}. + *

Users need to ensure that the data type of the specified column is {@code Type.INT64} or + * {@code Type.TIMESTAMP}. * * @param columnIndex index of the specified column * @return the long value at the specified column in this row */ - long getLong(int columnIndex); + long getLong(final int columnIndex); /** * Returns the float value at the specified column in this row. @@ -64,7 +76,7 @@ public interface Row { * @param columnIndex index of the specified column * @return the float value at the specified column in this row */ - float getFloat(int columnIndex); + float getFloat(final int columnIndex); /** * Returns the double value at the specified column in this row. @@ -74,7 +86,7 @@ public interface Row { * @param columnIndex index of the specified column * @return the double value at the specified column in this row */ - double getDouble(int columnIndex); + double getDouble(final int columnIndex); /** * Returns the boolean value at the specified column in this row. @@ -84,35 +96,37 @@ public interface Row { * @param columnIndex index of the specified column * @return the boolean value at the specified column in this row */ - boolean getBoolean(int columnIndex); + boolean getBoolean(final int columnIndex); /** * Returns the Binary value at the specified column in this row. * - *

Users need to ensure that the data type of the specified column is {@code Type.TEXT}. + *

Users need to ensure that the data type of the specified column is {@code Type.TEXT}, {@code + * Type.BLOB} or {@code Type.STRING}. * * @param columnIndex index of the specified column * @return the Binary value at the specified column in this row */ - Binary getBinary(int columnIndex); + Binary getBinary(final int columnIndex); /** * Returns the String value at the specified column in this row. * - *

Users need to ensure that the data type of the specified column is {@code Type.TEXT}. + *

Users need to ensure that the data type of the specified column is {@code Type.TEXT} or + * {@code Type.STRING}. * * @param columnIndex index of the specified column * @return the String value at the specified column in this row */ - String getString(int columnIndex); + String getString(final int columnIndex); /** - * Returns the Object value at the specified column in this row. + * Returns the raw Object stored at the specified column in this row. * * @param columnIndex index of the specified column * @return the Object value at the specified column in this row */ - Object getObject(int columnIndex); + Object getObject(final int columnIndex); /** * Returns the actual data type of the value at the specified column in this row. @@ -120,7 +134,7 @@ public interface Row { * @param columnIndex index of the specified column * @return the actual data type of the value at the specified column in this row */ - Type getDataType(int columnIndex); + Type getDataType(final int columnIndex); /** * Returns {@code true} if the value of the specified column is null. @@ -128,7 +142,7 @@ public interface Row { * @param columnIndex index of the specified column * @return {@code true} if the value of the specified column is null */ - boolean isNull(int columnIndex); + boolean isNull(final int columnIndex); /** * Returns the number of columns (excluding the timestamp column). @@ -144,7 +158,7 @@ public interface Row { * @return the actual column index of the given column name * @throws PipeParameterNotValidException if the given column name is not existed in the Row */ - int getColumnIndex(Path columnName) throws PipeParameterNotValidException; + int getColumnIndex(final Path columnName) throws PipeParameterNotValidException; /** * Returns the actual column (measurement) name of the given column index. @@ -152,7 +166,7 @@ public interface Row { * @param columnIndex the column index * @return the actual column (measurement) name of the given column index */ - String getColumnName(int columnIndex); + String getColumnName(final int columnIndex); /** * Returns the column data types in the Row. diff --git a/iotdb-api/pipe-api/src/main/java/org/apache/iotdb/pipe/api/type/Type.java b/iotdb-api/pipe-api/src/main/java/org/apache/iotdb/pipe/api/type/Type.java index 85a4390eae46e..9093133631a0e 100644 --- a/iotdb-api/pipe-api/src/main/java/org/apache/iotdb/pipe/api/type/Type.java +++ b/iotdb-api/pipe-api/src/main/java/org/apache/iotdb/pipe/api/type/Type.java @@ -36,7 +36,20 @@ public enum Type { DOUBLE((byte) 4), /* TEXT */ - TEXT((byte) 5); + TEXT((byte) 5), + + /* TsDataType.Vector and TsDataType.UNKNOWN are inner types of TsFile-module, which should not be supported in UDF APIs. To be consistent with TsDataType, the next value starts with 8 */ + /* TIMESTAMP */ + TIMESTAMP((byte) 8), + + /* DATE */ + DATE((byte) 9), + + /* BLOB */ + BLOB((byte) 10), + + /* STRING */ + STRING((byte) 11); private final byte dataType; diff --git a/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/utils/RowImpl.java b/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/utils/RowImpl.java index d7d3a88486902..533ab9574df6d 100644 --- a/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/utils/RowImpl.java +++ b/iotdb-api/udf-api/src/main/java/org/apache/iotdb/udf/api/utils/RowImpl.java @@ -142,6 +142,14 @@ private static Type transformToUDFDataType(TSDataType tsDataType) { return Type.DOUBLE; case 5: return Type.TEXT; + case 8: + return Type.TIMESTAMP; + case 9: + return Type.DATE; + case 10: + return Type.BLOB; + case 11: + return Type.STRING; default: throw new IllegalArgumentException("Invalid input: " + type); } diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/AbstractTsFileTool.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/AbstractTsFileTool.java index 4a4ee1dbb11fc..fe8691ddf8b65 100644 --- a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/AbstractTsFileTool.java +++ b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/AbstractTsFileTool.java @@ -42,8 +42,8 @@ public abstract class AbstractTsFileTool { protected static final String USERNAME_ARGS = "u"; protected static final String USERNAME_NAME = "username"; - protected static final String TIMEOUT_ARGS = "t"; - protected static final String TIMEOUT_NAME = "timeout"; + protected static final String TIMEOUT_ARGS = "timeout"; + protected static final String TIMEOUT_NAME = "queryTimeout"; protected static final int MAX_HELP_CONSOLE_WIDTH = 92; protected static final int CODE_OK = 0; protected static final int CODE_ERROR = 1; @@ -109,7 +109,7 @@ protected static void createBaseOptions() { .longOpt(HOST_NAME) .argName(HOST_NAME) .hasArg() - .desc("Host Name") + .desc("Host Name (optional)") .build(); options.addOption(opHost); @@ -118,7 +118,7 @@ protected static void createBaseOptions() { .longOpt(PORT_NAME) .argName(PORT_NAME) .hasArg() - .desc("Port") + .desc("Port (optional)") .build(); options.addOption(opPort); @@ -127,7 +127,7 @@ protected static void createBaseOptions() { .longOpt(USERNAME_NAME) .argName(USERNAME_NAME) .hasArg() - .desc("Username") + .desc("Username (optional)") .build(); options.addOption(opUsername); @@ -137,7 +137,7 @@ protected static void createBaseOptions() { .optionalArg(true) .argName(PW_NAME) .hasArg() - .desc("Password") + .desc("Password (optional)") .build(); options.addOption(opPassword); } diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/ExportTsFile.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/ExportTsFile.java index 3f89ec69c5296..9ab3d6b3ec65b 100644 --- a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/ExportTsFile.java +++ b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/ExportTsFile.java @@ -62,13 +62,13 @@ public class ExportTsFile extends AbstractTsFileTool { - private static final String TARGET_DIR_ARGS = "td"; + private static final String TARGET_DIR_ARGS = "t"; private static final String TARGET_DIR_NAME = "targetDirectory"; - private static final String TARGET_FILE_ARGS = "f"; - private static final String TARGET_FILE_NAME = "targetFile"; + private static final String TARGET_FILE_ARGS = "tfn"; + private static final String TARGET_FILE_NAME = "targetFileName"; private static final String SQL_FILE_ARGS = "s"; - private static final String SQL_FILE_NAME = "sqlfile"; + private static final String SQL_FILE_NAME = "sourceSqlFile"; private static final String QUERY_COMMAND_ARGS = "q"; private static final String QUERY_COMMAND_NAME = "queryCommand"; private static final String DUMP_FILE_NAME_DEFAULT = "dump"; @@ -266,7 +266,7 @@ private static void createOptions() { Option opTimeout = Option.builder(TIMEOUT_ARGS) - .longOpt(TIMEOUT_NAME) + .argName(TIMEOUT_NAME) .hasArg() .desc("Timeout for session query") .build(); diff --git a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/ImportTsFile.java b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/ImportTsFile.java index 4e74dbe5f594e..320b03334df59 100644 --- a/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/ImportTsFile.java +++ b/iotdb-client/cli/src/main/java/org/apache/iotdb/tool/ImportTsFile.java @@ -310,7 +310,9 @@ public static int importFromTargetPath() { } sessionPool = - new SessionPool(host, Integer.parseInt(port), username, password, threadNum + 1); + new SessionPool( + host, Integer.parseInt(port), username, password, threadNum + 1, false, false); + sessionPool.setEnableQueryRedirection(false); traverseAndCollectFiles(file); addNoResourceOrModsToQueue(); diff --git a/iotdb-client/client-cpp/README.md b/iotdb-client/client-cpp/README.md index deb6ea4e428bc..81983e06e2e4d 100644 --- a/iotdb-client/client-cpp/README.md +++ b/iotdb-client/client-cpp/README.md @@ -20,46 +20,79 @@ --> # Building C++ Client -To compile cpp client, add "-P with-cpp" option to maven build command. - -The compiling requires the module "compile-tools" to be built first. -For more information, please refer to "compile-tools/README.md". - -Explicitly using mvnw here as the build requires maven 3.9 and the default installation is older - ## Compile and Test: ### Compile -`mvn clean package -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests` -### Test -First build IoTDB server - -Explicitly using "install" instead of package in order to be sure we're using libs built on this machine +#### Unix +To compile the cpp client, use the following command: +`mvn clean package -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests` -`mvn clean install -P with-cpp -pl distribution,iotdb-client/client-cpp -am -DskipTests` +#### Windows +To compile on Windows, please install Boost first and add following Maven +settings: +``` +-Dboost.include.dir=${your boost header folder} -Dboost.library.dir=${your boost lib (stage) folder}` +``` -After run verify +The thrift dependency that the cpp client uses is incompatible with MinGW, please use Visual +Studio. It is highly recommended to use Visual Studio 2022 or later. -`mvn clean verify -P with-cpp -pl iotdb-client/client-cpp -am` +##### Visual Studio 2022 +If you are using Visual Studio 2022, you can compile the cpp client with the following command: -To compile on Windows, please install Boost first and add following Maven settings: ``` --Dboost.include.dir=${your boost header folder} -Dboost.library.dir=${your boost lib (stage) folder}` +mvn clean package -P with-cpp -pl iotdb-client/client-cpp -am -DskipTest +-D"boost.include.dir"="D:\boost_1_75_0" -D"boost.library.dir"="D:\boost_1_75_0\stage\lib" ``` -e.g., +#### Visual Studio 2019 or older +If you are using Visual Studio 2019 or older, the pre-built Thrift library is incompatible. You +will have to compile the thrift library manually: + +1. Install the dependencies of Thrift: +* flex http://gnuwin32.sourceforge.net/packages/flex.htm +* bison http://gnuwin32.sourceforge.net/packages/bison.htm +* openssl https://slproweb.com/products/Win32OpenSSL.html + +2. Clone the repository: https://github.com/apache/iotdb-bin-resources. + +3. Enter the "iotdb-tools-thrift" folder in the cloned repository; use the following command to + compile the thrift library: + +`mvn install` + +4. If you encounter a problem like "cannot find 'unistd.h'", please open the file +"iotdb-bin-resources\iotdb-tools-thrift\target\build\compiler\cpp\thrift\thriftl.cc" and replace +"#include " with "#include " and "#include "; then, rerun the command + in the third step; + +5. Return to the cpp client repository and compile it with: + ``` mvn clean package -P with-cpp -pl iotdb-client/client-cpp -am -DskipTest -D"boost.include.dir"="D:\boost_1_75_0" -D"boost.library.dir"="D:\boost_1_75_0\stage\lib" ``` -## + +### Test +First build IoTDB server together with the cpp client. + +Explicitly using "install" instead of package in order to be sure we're using libs built on this +machine. + +`mvn clean install -P with-cpp -pl distribution,iotdb-client/client-cpp -am -DskipTests` + +After run verify + +`mvn clean verify -P with-cpp -pl iotdb-client/client-cpp -am` + +## Package Hierarchy If the compilation finishes successfully, the packaged zip file will be placed under "client-cpp/target/client-cpp-${project.version}-cpp-${os}.zip". -On Mac machines, the hierarchy of the package should look like this: +On macOS, the hierarchy of the package should look like this: ``` . +-- client @@ -71,17 +104,22 @@ On Mac machines, the hierarchy of the package should look like this: | +-- thrift | +-- thrift_headers... | +-- lib -| +-- libiotdb_session.dylib +| +-- Release +| +-- libiotdb_session.dylib +| +-- parser.dylib +| +-- thriftmd.dylib +| +-- tutorialgencpp.dylib ``` ## Using C++ Client: ``` -1. Put the zip file "client-cpp-${project.version}-cpp-${os}.zip" wherever you want +1. Put the zip file "client-cpp-${project.version}-cpp-${os}.zip" wherever you want; -2. Unzip the archive using the following command, and then you can get the two directories mentioned above, the header file and the dynamic library +2. Unzip the archive using the following command, and then you can get the two directories +mentioned above, the header file and the dynamic library: unzip client-cpp-${project.version}-cpp-${os}.zip -3. Write C++ code to call the operation interface of cpp-client to operate IOTDB, +3. Write C++ code to call the operation interface of the cpp client to operate IoTDB, for detail interface information, please refer to the link: https://iotdb.apache.org/zh/UserGuide/Master/API/Programming-Cpp-Native-API.html E.g: diff --git a/iotdb-client/client-cpp/src/assembly/client-cpp.xml b/iotdb-client/client-cpp/src/assembly/client-cpp.xml index 9de99eae649a9..729fdadde235a 100644 --- a/iotdb-client/client-cpp/src/assembly/client-cpp.xml +++ b/iotdb-client/client-cpp/src/assembly/client-cpp.xml @@ -33,13 +33,19 @@ include - ${project.basedir}/../compile-tools/thrift/target/thrift-${thrift.version}/lib/cpp/src + ${project.build.directory}/thrift/include - **/*.h - **/*.tcc + ** include + + ${project.build.directory}/thrift/lib + + ** + + lib + ${project.build.directory}/build/main diff --git a/iotdb-client/client-py/iotdb/utils/IoTDBRpcDataSet.py b/iotdb-client/client-py/iotdb/utils/IoTDBRpcDataSet.py index 53ef09b8e7aa3..eb859d7d30c1d 100644 --- a/iotdb-client/client-py/iotdb/utils/IoTDBRpcDataSet.py +++ b/iotdb-client/client-py/iotdb/utils/IoTDBRpcDataSet.py @@ -151,7 +151,7 @@ def construct_one_data_frame(self): self.__query_data_set.time, np.dtype(np.longlong).newbyteorder(">") ) if time_array.dtype.byteorder == ">": - time_array = time_array.byteswap().newbyteorder("<") + time_array = time_array.byteswap().view(time_array.dtype.newbyteorder("<")) result[0] = time_array total_length = len(time_array) for i in range(self.column_size): @@ -205,7 +205,9 @@ def construct_one_data_frame(self): else: raise RuntimeError("unsupported data type {}.".format(data_type)) if data_array.dtype.byteorder == ">": - data_array = data_array.byteswap().newbyteorder("<") + data_array = data_array.byteswap().view( + data_array.dtype.newbyteorder("<") + ) # self.__query_data_set.valueList[location] = None if len(data_array) < total_length: # INT32 or INT64 or boolean @@ -258,7 +260,9 @@ def resultset_to_pandas(self): self.__query_data_set.time, np.dtype(np.longlong).newbyteorder(">") ) if time_array.dtype.byteorder == ">": - time_array = time_array.byteswap().newbyteorder("<") + time_array = time_array.byteswap().view( + time_array.dtype.newbyteorder("<") + ) if self.ignore_timestamp is None or self.ignore_timestamp is False: result[IoTDBRpcDataSet.TIMESTAMP_STR].append(time_array) @@ -317,7 +321,9 @@ def resultset_to_pandas(self): else: raise RuntimeError("unsupported data type {}.".format(data_type)) if data_array.dtype.byteorder == ">": - data_array = data_array.byteswap().newbyteorder("<") + data_array = data_array.byteswap().view( + data_array.dtype.newbyteorder("<") + ) self.__query_data_set.valueList[location] = None tmp_array = [] if len(data_array) < total_length: diff --git a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/RpcUtils.java b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/RpcUtils.java index 9b29f052f28b2..e48054abb1974 100644 --- a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/RpcUtils.java +++ b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/RpcUtils.java @@ -146,18 +146,20 @@ public static TSStatus getStatus(TSStatusCode tsStatusCode) { public static TSStatus getStatus(List statusList) { TSStatus status = new TSStatus(TSStatusCode.MULTIPLE_ERROR.getStatusCode()); status.setSubStatus(statusList); - StringBuilder errMsg = new StringBuilder().append("Multiple error occur, messages: "); - Set msgSet = new HashSet<>(); - for (TSStatus subStatus : statusList) { - if (subStatus.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode() - && subStatus.getCode() != TSStatusCode.REDIRECTION_RECOMMEND.getStatusCode()) { - if (!msgSet.contains(status.getMessage())) { - errMsg.append(status.getMessage()).append("; "); - msgSet.add(status.getMessage()); + if (LOGGER.isDebugEnabled()) { + StringBuilder errMsg = new StringBuilder().append("Multiple error occur, messages: "); + Set msgSet = new HashSet<>(); + for (TSStatus subStatus : statusList) { + if (subStatus.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode() + && subStatus.getCode() != TSStatusCode.REDIRECTION_RECOMMEND.getStatusCode()) { + if (!msgSet.contains(status)) { + errMsg.append(status).append("; "); + msgSet.add(status); + } } } + LOGGER.debug(errMsg.toString(), new Exception(errMsg.toString())); } - LOGGER.warn(errMsg.toString()); return status; } diff --git a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java index 2324dbbd575f2..e57365b33ea46 100644 --- a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java +++ b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/TSStatusCode.java @@ -166,6 +166,7 @@ public enum TSStatusCode { CAN_NOT_CONNECT_DATANODE(1007), TRANSFER_LEADER_ERROR(1008), GET_CLUSTER_ID_ERROR(1009), + CAN_NOT_CONNECT_CONFIGNODE(1010), // Sync, Load TsFile LOAD_FILE_ERROR(1100), diff --git a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/config/TopicConfig.java b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/config/TopicConfig.java index fe62ba622a965..6dc42ed634aea 100644 --- a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/config/TopicConfig.java +++ b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/config/TopicConfig.java @@ -28,7 +28,10 @@ import java.nio.ByteBuffer; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; +import java.util.stream.Collectors; public class TopicConfig extends PipeParameters { @@ -40,6 +43,25 @@ public TopicConfig(final Map attributes) { super(attributes); } + private static final Map REALTIME_BATCH_MODE_CONFIG = + Collections.singletonMap("realtime.mode", "batch"); + private static final Map REALTIME_STREAM_MODE_CONFIG = + Collections.singletonMap("realtime.mode", "stream"); + + private static final Map QUERY_MODE_CONFIG = + Collections.singletonMap("mode", "query"); + private static final Map SUBSCRIBE_MODE_CONFIG = + Collections.singletonMap("mode", "subscribe"); + + private static final Set LOOSE_RANGE_KEY_SET = + Collections.unmodifiableSet( + new HashSet() { + { + add("history.loose-range"); + add("realtime.loose-range"); + } + }); + /////////////////////////////// de/ser /////////////////////////////// public void serialize(final DataOutputStream stream) throws IOException { @@ -84,21 +106,29 @@ public Map getAttributesWithTimeRange(final long creationTime) { attributesWithTimeRange.put(TopicConstant.END_TIME_KEY, endTime); } - // enable loose range when using tsfile format - if (TopicConstant.FORMAT_TS_FILE_HANDLER_VALUE.equals( - attributes.getOrDefault(TopicConstant.FORMAT_KEY, TopicConstant.FORMAT_DEFAULT_VALUE))) { - attributesWithTimeRange.put("history.loose-range", "time"); - attributesWithTimeRange.put("realtime.loose-range", "time"); - } - return attributesWithTimeRange; } public Map getAttributesWithRealtimeMode() { return TopicConstant.FORMAT_TS_FILE_HANDLER_VALUE.equals( attributes.getOrDefault(TopicConstant.FORMAT_KEY, TopicConstant.FORMAT_DEFAULT_VALUE)) - ? Collections.singletonMap("realtime.mode", "batch") - : Collections.singletonMap("realtime.mode", "hybrid"); + ? REALTIME_BATCH_MODE_CONFIG + : REALTIME_STREAM_MODE_CONFIG; + } + + public Map getAttributesWithSourceMode() { + return TopicConstant.MODE_QUERY_VALUE.equals( + attributes.getOrDefault(TopicConstant.MODE_KEY, TopicConstant.MODE_DEFAULT_VALUE)) + ? QUERY_MODE_CONFIG + : SUBSCRIBE_MODE_CONFIG; + } + + public Map getAttributesWithSourceLooseRange() { + final String looseRangeValue = + attributes.getOrDefault( + TopicConstant.LOOSE_RANGE_KEY, TopicConstant.LOOSE_RANGE_DEFAULT_VALUE); + return LOOSE_RANGE_KEY_SET.stream() + .collect(Collectors.toMap(key -> key, key -> looseRangeValue)); } public Map getAttributesWithProcessorPrefix() { diff --git a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/config/TopicConstant.java b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/config/TopicConstant.java index bd44cf1bcc95d..a3226c1d64063 100644 --- a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/config/TopicConstant.java +++ b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/config/TopicConstant.java @@ -30,11 +30,22 @@ public class TopicConstant { public static final String END_TIME_KEY = "end-time"; public static final String NOW_TIME_VALUE = "now"; + public static final String MODE_KEY = "mode"; + public static final String MODE_SUBSCRIBE_VALUE = "subscribe"; + public static final String MODE_QUERY_VALUE = "query"; + public static final String MODE_DEFAULT_VALUE = MODE_SUBSCRIBE_VALUE; + public static final String FORMAT_KEY = "format"; public static final String FORMAT_SESSION_DATA_SETS_HANDLER_VALUE = "SessionDataSetsHandler"; public static final String FORMAT_TS_FILE_HANDLER_VALUE = "TsFileHandler"; public static final String FORMAT_DEFAULT_VALUE = FORMAT_SESSION_DATA_SETS_HANDLER_VALUE; + public static final String LOOSE_RANGE_KEY = "loose-range"; + public static final String LOOSE_RANGE_TIME_VALUE = "time"; + public static final String LOOSE_RANGE_PATH_VALUE = "path"; + public static final String LOOSE_RANGE_TIME_AND_PATH_VALUE = "time,path"; + public static final String LOOSE_RANGE_DEFAULT_VALUE = ""; + private TopicConstant() { throw new IllegalStateException("Utility class"); } diff --git a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/exception/SubscriptionIdentifierSemanticException.java b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/exception/SubscriptionIdentifierSemanticException.java new file mode 100644 index 0000000000000..6eb9ba6d73484 --- /dev/null +++ b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/exception/SubscriptionIdentifierSemanticException.java @@ -0,0 +1,42 @@ +/* + * 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.iotdb.rpc.subscription.exception; + +import java.util.Objects; + +public class SubscriptionIdentifierSemanticException extends SubscriptionException { + + public SubscriptionIdentifierSemanticException(final String message) { + super(message); + } + + public SubscriptionIdentifierSemanticException(final String message, final Throwable cause) { + super(message, cause); + } + + @Override + public boolean equals(final Object obj) { + return obj instanceof SubscriptionIdentifierSemanticException + && Objects.equals( + getMessage(), ((SubscriptionIdentifierSemanticException) obj).getMessage()) + && Objects.equals( + getTimeStamp(), ((SubscriptionIdentifierSemanticException) obj).getTimeStamp()); + } +} diff --git a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/payload/poll/SubscriptionPollResponse.java b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/payload/poll/SubscriptionPollResponse.java index d386903f124d0..01d173d274283 100644 --- a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/payload/poll/SubscriptionPollResponse.java +++ b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/payload/poll/SubscriptionPollResponse.java @@ -95,6 +95,9 @@ public static SubscriptionPollResponse deserialize(final ByteBuffer buffer) { case ERROR: payload = new ErrorPayload().deserialize(buffer); break; + case TERMINATION: + payload = new TerminationPayload().deserialize(buffer); + break; default: LOGGER.warn("unexpected response type: {}, payload will be null", responseType); break; diff --git a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/payload/poll/SubscriptionPollResponseType.java b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/payload/poll/SubscriptionPollResponseType.java index a22c9590c65fc..b27791b36c538 100644 --- a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/payload/poll/SubscriptionPollResponseType.java +++ b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/payload/poll/SubscriptionPollResponseType.java @@ -31,6 +31,8 @@ public enum SubscriptionPollResponseType { FILE_INIT((short) 2), FILE_PIECE((short) 3), FILE_SEAL((short) 4), + + TERMINATION((short) 5), ; private final short type; diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/task/DecoratingLock.java b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/payload/poll/TerminationPayload.java similarity index 61% rename from iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/task/DecoratingLock.java rename to iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/payload/poll/TerminationPayload.java index cc5d0d93e5eee..c2da3f92e6dd8 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/task/DecoratingLock.java +++ b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/payload/poll/TerminationPayload.java @@ -17,28 +17,26 @@ * under the License. */ -package org.apache.iotdb.commons.pipe.task; +package org.apache.iotdb.rpc.subscription.payload.poll; -import java.util.concurrent.atomic.AtomicBoolean; +import java.io.DataOutputStream; +import java.nio.ByteBuffer; -public class DecoratingLock { - private final AtomicBoolean isDecorating = new AtomicBoolean(false); +public class TerminationPayload implements SubscriptionPollPayload { - public void waitForDecorated() { - while (isDecorating.get()) { - try { - Thread.sleep(10); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - } - } + @Override + public void serialize(final DataOutputStream stream) { + // do nothing } - public void markAsDecorating() { - isDecorating.set(true); + @Override + public SubscriptionPollPayload deserialize(final ByteBuffer buffer) { + // do nothing + return null; } - public void markAsDecorated() { - isDecorating.set(false); + @Override + public String toString() { + return "TerminationPayload"; } } diff --git a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/payload/response/PipeSubscribeSubscribeResp.java b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/payload/response/PipeSubscribeSubscribeResp.java index a5540150898d2..1d1571b0122ee 100644 --- a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/payload/response/PipeSubscribeSubscribeResp.java +++ b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/payload/response/PipeSubscribeSubscribeResp.java @@ -22,10 +22,25 @@ import org.apache.iotdb.common.rpc.thrift.TSStatus; import org.apache.iotdb.service.rpc.thrift.TPipeSubscribeResp; +import org.apache.tsfile.utils.PublicBAOS; +import org.apache.tsfile.utils.ReadWriteIOUtils; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Collections; +import java.util.HashSet; import java.util.Objects; +import java.util.Set; public class PipeSubscribeSubscribeResp extends TPipeSubscribeResp { + private transient Set topicNames = new HashSet<>(); // subscribed topic names + + public Set getTopicNames() { + return topicNames; + } + /////////////////////////////// Thrift /////////////////////////////// /** @@ -34,11 +49,32 @@ public class PipeSubscribeSubscribeResp extends TPipeSubscribeResp { */ public static PipeSubscribeSubscribeResp toTPipeSubscribeResp(final TSStatus status) { final PipeSubscribeSubscribeResp resp = new PipeSubscribeSubscribeResp(); + resp.status = status; + resp.version = PipeSubscribeResponseVersion.VERSION_1.getVersion(); + resp.type = PipeSubscribeResponseType.ACK.getType(); + return resp; + } + + /** + * Serialize the incoming parameters into `PipeSubscribeSubscribeResp`, called by the subscription + * server. + */ + public static PipeSubscribeSubscribeResp toTPipeSubscribeResp( + final TSStatus status, final Set topicNames) throws IOException { + final PipeSubscribeSubscribeResp resp = new PipeSubscribeSubscribeResp(); resp.status = status; resp.version = PipeSubscribeResponseVersion.VERSION_1.getVersion(); resp.type = PipeSubscribeResponseType.ACK.getType(); + try (final PublicBAOS byteArrayOutputStream = new PublicBAOS(); + final DataOutputStream outputStream = new DataOutputStream(byteArrayOutputStream)) { + ReadWriteIOUtils.writeObjectSet(topicNames, outputStream); + resp.body = + Collections.singletonList( + ByteBuffer.wrap(byteArrayOutputStream.getBuf(), 0, byteArrayOutputStream.size())); + } + return resp; } @@ -47,11 +83,19 @@ public static PipeSubscribeSubscribeResp fromTPipeSubscribeResp( final TPipeSubscribeResp subscribeResp) { final PipeSubscribeSubscribeResp resp = new PipeSubscribeSubscribeResp(); + if (Objects.nonNull(subscribeResp.body)) { + for (final ByteBuffer byteBuffer : subscribeResp.body) { + if (Objects.nonNull(byteBuffer) && byteBuffer.hasRemaining()) { + resp.topicNames = ReadWriteIOUtils.readObjectSet(byteBuffer); + break; + } + } + } + resp.status = subscribeResp.status; resp.version = subscribeResp.version; resp.type = subscribeResp.type; resp.body = subscribeResp.body; - return resp; } @@ -66,7 +110,8 @@ public boolean equals(final Object obj) { return false; } final PipeSubscribeSubscribeResp that = (PipeSubscribeSubscribeResp) obj; - return Objects.equals(this.status, that.status) + return Objects.equals(this.topicNames, that.topicNames) + && Objects.equals(this.status, that.status) && this.version == that.version && this.type == that.type && Objects.equals(this.body, that.body); @@ -74,6 +119,6 @@ public boolean equals(final Object obj) { @Override public int hashCode() { - return Objects.hash(status, version, type, body); + return Objects.hash(topicNames, status, version, type, body); } } diff --git a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/payload/response/PipeSubscribeUnsubscribeResp.java b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/payload/response/PipeSubscribeUnsubscribeResp.java index a93e38013acc6..e5d8ccf69cf4b 100644 --- a/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/payload/response/PipeSubscribeUnsubscribeResp.java +++ b/iotdb-client/service-rpc/src/main/java/org/apache/iotdb/rpc/subscription/payload/response/PipeSubscribeUnsubscribeResp.java @@ -22,10 +22,25 @@ import org.apache.iotdb.common.rpc.thrift.TSStatus; import org.apache.iotdb.service.rpc.thrift.TPipeSubscribeResp; +import org.apache.tsfile.utils.PublicBAOS; +import org.apache.tsfile.utils.ReadWriteIOUtils; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Collections; +import java.util.HashSet; import java.util.Objects; +import java.util.Set; public class PipeSubscribeUnsubscribeResp extends TPipeSubscribeResp { + private transient Set topicNames = new HashSet<>(); // subscribed topic names + + public Set getTopicNames() { + return topicNames; + } + /////////////////////////////// Thrift /////////////////////////////// /** @@ -34,11 +49,32 @@ public class PipeSubscribeUnsubscribeResp extends TPipeSubscribeResp { */ public static PipeSubscribeUnsubscribeResp toTPipeSubscribeResp(final TSStatus status) { final PipeSubscribeUnsubscribeResp resp = new PipeSubscribeUnsubscribeResp(); + resp.status = status; + resp.version = PipeSubscribeResponseVersion.VERSION_1.getVersion(); + resp.type = PipeSubscribeResponseType.ACK.getType(); + return resp; + } + + /** + * Serialize the incoming parameters into `PipeSubscribeUnsubscribeResp`, called by the + * subscription server. + */ + public static PipeSubscribeUnsubscribeResp toTPipeSubscribeResp( + final TSStatus status, final Set topicNames) throws IOException { + final PipeSubscribeUnsubscribeResp resp = new PipeSubscribeUnsubscribeResp(); resp.status = status; resp.version = PipeSubscribeResponseVersion.VERSION_1.getVersion(); resp.type = PipeSubscribeResponseType.ACK.getType(); + try (final PublicBAOS byteArrayOutputStream = new PublicBAOS(); + final DataOutputStream outputStream = new DataOutputStream(byteArrayOutputStream)) { + ReadWriteIOUtils.writeObjectSet(topicNames, outputStream); + resp.body = + Collections.singletonList( + ByteBuffer.wrap(byteArrayOutputStream.getBuf(), 0, byteArrayOutputStream.size())); + } + return resp; } @@ -47,11 +83,19 @@ public static PipeSubscribeUnsubscribeResp fromTPipeSubscribeResp( final TPipeSubscribeResp unsubscribeResp) { final PipeSubscribeUnsubscribeResp resp = new PipeSubscribeUnsubscribeResp(); + if (Objects.nonNull(unsubscribeResp.body)) { + for (final ByteBuffer byteBuffer : unsubscribeResp.body) { + if (Objects.nonNull(byteBuffer) && byteBuffer.hasRemaining()) { + resp.topicNames = ReadWriteIOUtils.readObjectSet(byteBuffer); + break; + } + } + } + resp.status = unsubscribeResp.status; resp.version = unsubscribeResp.version; resp.type = unsubscribeResp.type; resp.body = unsubscribeResp.body; - return resp; } @@ -66,7 +110,8 @@ public boolean equals(final Object obj) { return false; } final PipeSubscribeUnsubscribeResp that = (PipeSubscribeUnsubscribeResp) obj; - return Objects.equals(this.status, that.status) + return Objects.equals(this.topicNames, that.topicNames) + && Objects.equals(this.status, that.status) && this.version == that.version && this.type == that.type && Objects.equals(this.body, that.body); @@ -74,6 +119,6 @@ public boolean equals(final Object obj) { @Override public int hashCode() { - return Objects.hash(status, version, type, body); + return Objects.hash(topicNames, status, version, type, body); } } diff --git a/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/consumer/SubscriptionConsumer.java b/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/consumer/SubscriptionConsumer.java index 2bbd4a129a91b..410348c991b38 100644 --- a/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/consumer/SubscriptionConsumer.java +++ b/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/consumer/SubscriptionConsumer.java @@ -40,6 +40,7 @@ import org.apache.iotdb.rpc.subscription.payload.poll.SubscriptionPollResponseType; import org.apache.iotdb.rpc.subscription.payload.poll.TabletsPayload; import org.apache.iotdb.session.subscription.payload.SubscriptionMessage; +import org.apache.iotdb.session.subscription.util.IdentifierUtils; import org.apache.iotdb.session.subscription.util.RandomStringGenerator; import org.apache.iotdb.session.subscription.util.SubscriptionPollTimer; import org.apache.iotdb.session.util.SessionUtils; @@ -50,8 +51,10 @@ import java.io.File; import java.io.IOException; import java.io.RandomAccessFile; +import java.net.URLEncoder; import java.nio.file.FileAlreadyExistsException; import java.nio.file.Files; +import java.nio.file.InvalidPathException; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; @@ -69,6 +72,7 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.LockSupport; +import java.util.stream.Collectors; abstract class SubscriptionConsumer implements AutoCloseable { @@ -92,6 +96,10 @@ abstract class SubscriptionConsumer implements AutoCloseable { private final String fileSaveDir; private final boolean fileSaveFsync; + protected volatile Set subscribedTopicNames = new HashSet<>(); + + /////////////////////////////// getter /////////////////////////////// + public String getConsumerId() { return consumerId; } @@ -100,6 +108,14 @@ public String getConsumerGroupId() { return consumerGroupId; } + /** + * @return When only subscribing to the query mode topics, if there is no new data to + * process, return {@code false}; otherwise, return {@code true}. + */ + public boolean hasMoreData() { + return !subscribedTopicNames.isEmpty(); + } + /////////////////////////////// ctor /////////////////////////////// protected SubscriptionConsumer(final Builder builder) { @@ -221,6 +237,17 @@ public void subscribe(final String... topicNames) throws SubscriptionException { } public void subscribe(final Set topicNames) throws SubscriptionException { + // parse topic names from external source + subscribe(topicNames, true); + } + + private void subscribe(Set topicNames, final boolean needParse) + throws SubscriptionException { + if (needParse) { + topicNames = + topicNames.stream().map(IdentifierUtils::parseIdentifier).collect(Collectors.toSet()); + } + providers.acquireReadLock(); try { subscribeWithRedirection(topicNames); @@ -238,6 +265,17 @@ public void unsubscribe(final String... topicNames) throws SubscriptionException } public void unsubscribe(final Set topicNames) throws SubscriptionException { + // parse topic names from external source + unsubscribe(topicNames, true); + } + + private void unsubscribe(Set topicNames, final boolean needParse) + throws SubscriptionException { + if (needParse) { + topicNames = + topicNames.stream().map(IdentifierUtils::parseIdentifier).collect(Collectors.toSet()); + } + providers.acquireReadLock(); try { unsubscribeWithRedirection(topicNames); @@ -284,33 +322,51 @@ private Path getFileDir(final String topicName) throws IOException { return dirPath; } - private Path getFilePath(final String topicName, String fileName) throws SubscriptionException { - Path filePath; + private Path getFilePath( + final String topicName, + final String fileName, + final boolean allowFileAlreadyExistsException, + final boolean allowInvalidPathException) + throws SubscriptionException { try { - filePath = getFileDir(topicName).resolve(fileName); + final Path filePath = getFileDir(topicName).resolve(fileName); Files.createFile(filePath); + return filePath; } catch (final FileAlreadyExistsException fileAlreadyExistsException) { - fileName += "." + RandomStringGenerator.generate(16); - try { - filePath = getFileDir(topicName).resolve(fileName); - Files.createFile(filePath); - } catch (final IOException e) { - throw new SubscriptionRuntimeNonCriticalException(e.getMessage(), e); + if (allowFileAlreadyExistsException) { + return getFilePath( + topicName, fileName + "." + RandomStringGenerator.generate(16), false, true); + } + throw new SubscriptionRuntimeNonCriticalException( + fileAlreadyExistsException.getMessage(), fileAlreadyExistsException); + } catch (final InvalidPathException invalidPathException) { + if (allowInvalidPathException) { + return getFilePath(URLEncoder.encode(topicName), fileName, true, false); } + throw new SubscriptionRuntimeNonCriticalException( + invalidPathException.getMessage(), invalidPathException); } catch (final IOException e) { throw new SubscriptionRuntimeNonCriticalException(e.getMessage(), e); } - return filePath; } /////////////////////////////// poll /////////////////////////////// - protected List poll(final Set topicNames, final long timeoutMs) + protected List poll( + /* @NotNull */ final Set topicNames, final long timeoutMs) throws SubscriptionException { final List messages = new ArrayList<>(); final SubscriptionPollTimer timer = new SubscriptionPollTimer(System.currentTimeMillis(), timeoutMs); + // check topic names + topicNames.stream() + .filter(topicName -> !subscribedTopicNames.contains(topicName)) + .forEach( + topicName -> + LOGGER.warn( + "SubscriptionConsumer {} does not subscribe to topic {}", this, topicName)); + do { try { // poll tablets or file @@ -336,18 +392,21 @@ protected List poll(final Set topicNames, final lon case ERROR: final ErrorPayload payload = (ErrorPayload) pollResponse.getPayload(); final String errorMessage = payload.getErrorMessage(); - final boolean critical = payload.isCritical(); - LOGGER.warn( - "Error occurred when SubscriptionConsumer {} polling topics {}: {}, critical: {}", - this, - topicNames, - errorMessage, - critical); - if (critical) { + if (payload.isCritical()) { throw new SubscriptionRuntimeCriticalException(errorMessage); } else { throw new SubscriptionRuntimeNonCriticalException(errorMessage); } + case TERMINATION: + final SubscriptionCommitContext commitContext = pollResponse.getCommitContext(); + final String topicNameToUnsubscribe = commitContext.getTopicName(); + LOGGER.info( + "Termination occurred when SubscriptionConsumer {} polling topics {}, unsubscribe topic {} automatically", + this, + topicNames, + topicNameToUnsubscribe); + unsubscribe(Collections.singleton(topicNameToUnsubscribe), false); + break; default: LOGGER.warn("unexpected response type: {}", responseType); break; @@ -398,7 +457,7 @@ private Optional pollFile( final SubscriptionCommitContext commitContext, final String fileName) throws SubscriptionException { final String topicName = commitContext.getTopicName(); - final Path filePath = getFilePath(topicName, fileName); + final Path filePath = getFilePath(topicName, fileName, true, true); final File file = filePath.toFile(); try (final RandomAccessFile fileWriter = new RandomAccessFile(file, "rw")) { return Optional.of(pollFileInternal(commitContext, file, fileWriter)); @@ -576,6 +635,9 @@ private List pollInternal(final Set topicNames try { final SubscriptionProvider provider = providers.getNextAvailableProvider(); if (Objects.isNull(provider) || !provider.isAvailable()) { + if (isClosed()) { + return Collections.emptyList(); + } throw new SubscriptionConnectionException( String.format( "Cluster has no available subscription providers when %s poll topic %s", @@ -601,6 +663,9 @@ private List pollFileInternal( try { final SubscriptionProvider provider = providers.getProvider(dataNodeId); if (Objects.isNull(provider) || !provider.isAvailable()) { + if (isClosed()) { + return Collections.emptyList(); + } throw new SubscriptionConnectionException( String.format( "something unexpected happened when %s poll file from subscription provider with data node id %s, the subscription provider may be unavailable or not existed", @@ -660,6 +725,9 @@ private void commitInternal( try { final SubscriptionProvider provider = providers.getProvider(dataNodeId); if (Objects.isNull(provider) || !provider.isAvailable()) { + if (isClosed()) { + return; + } throw new SubscriptionConnectionException( String.format( "something unexpected happened when %s commit (nack: %s) messages to subscription provider with data node id %s, the subscription provider may be unavailable or not existed", @@ -775,7 +843,7 @@ private void subscribeWithRedirection(final Set topicNames) throws Subsc } for (final SubscriptionProvider provider : providers) { try { - provider.subscribe(topicNames); + subscribedTopicNames = provider.subscribe(topicNames); return; } catch (final Exception e) { LOGGER.warn( @@ -805,7 +873,7 @@ private void unsubscribeWithRedirection(final Set topicNames) } for (final SubscriptionProvider provider : providers) { try { - provider.unsubscribe(topicNames); + subscribedTopicNames = provider.unsubscribe(topicNames); return; } catch (final Exception e) { LOGGER.warn( @@ -897,12 +965,12 @@ public Builder password(final String password) { } public Builder consumerId(final String consumerId) { - this.consumerId = consumerId; + this.consumerId = IdentifierUtils.parseIdentifier(consumerId); return this; } public Builder consumerGroupId(final String consumerGroupId) { - this.consumerGroupId = consumerGroupId; + this.consumerGroupId = IdentifierUtils.parseIdentifier(consumerGroupId); return this; } diff --git a/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/consumer/SubscriptionExecutorServiceManager.java b/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/consumer/SubscriptionExecutorServiceManager.java index 5a587ff96fba6..6ce5946d4fcc6 100644 --- a/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/consumer/SubscriptionExecutorServiceManager.java +++ b/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/consumer/SubscriptionExecutorServiceManager.java @@ -29,12 +29,12 @@ import java.util.concurrent.ScheduledFuture; import java.util.concurrent.TimeUnit; -final class SubscriptionExecutorServiceManager { +public final class SubscriptionExecutorServiceManager { private static final Logger LOGGER = LoggerFactory.getLogger(SubscriptionExecutorServiceManager.class); - private static final long AWAIT_TERMINATION_TIMEOUT_MS = 10_000L; + private static final long AWAIT_TERMINATION_TIMEOUT_MS = 15_000L; private static final String CONTROL_FLOW_EXECUTOR_NAME = "SubscriptionControlFlowExecutor"; private static final String UPSTREAM_DATA_FLOW_EXECUTOR_NAME = @@ -172,9 +172,9 @@ boolean isShutdown() { } void setCorePoolSize(final int corePoolSize) { - if (!isShutdown()) { + if (isShutdown()) { synchronized (this) { - if (!isShutdown()) { + if (isShutdown()) { this.corePoolSize = corePoolSize; return; } diff --git a/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/consumer/SubscriptionProvider.java b/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/consumer/SubscriptionProvider.java index 70589472f8287..9bce0d6774faf 100644 --- a/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/consumer/SubscriptionProvider.java +++ b/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/consumer/SubscriptionProvider.java @@ -40,6 +40,8 @@ import org.apache.iotdb.rpc.subscription.payload.request.PipeSubscribeUnsubscribeReq; import org.apache.iotdb.rpc.subscription.payload.response.PipeSubscribeHandshakeResp; import org.apache.iotdb.rpc.subscription.payload.response.PipeSubscribePollResp; +import org.apache.iotdb.rpc.subscription.payload.response.PipeSubscribeSubscribeResp; +import org.apache.iotdb.rpc.subscription.payload.response.PipeSubscribeUnsubscribeResp; import org.apache.iotdb.service.rpc.thrift.TPipeSubscribeResp; import org.apache.iotdb.session.subscription.SubscriptionSession; import org.apache.iotdb.session.subscription.SubscriptionSessionConnection; @@ -215,7 +217,7 @@ void heartbeat() throws SubscriptionException { verifyPipeSubscribeSuccess(resp.status); } - void subscribe(final Set topicNames) throws SubscriptionException { + Set subscribe(final Set topicNames) throws SubscriptionException { final PipeSubscribeSubscribeReq req; try { req = PipeSubscribeSubscribeReq.toTPipeSubscribeReq(topicNames); @@ -241,9 +243,12 @@ void subscribe(final Set topicNames) throws SubscriptionException { throw new SubscriptionConnectionException(e.getMessage(), e); } verifyPipeSubscribeSuccess(resp.status); + final PipeSubscribeSubscribeResp subscribeResp = + PipeSubscribeSubscribeResp.fromTPipeSubscribeResp(resp); + return subscribeResp.getTopicNames(); } - void unsubscribe(final Set topicNames) throws SubscriptionException { + Set unsubscribe(final Set topicNames) throws SubscriptionException { final PipeSubscribeUnsubscribeReq req; try { req = PipeSubscribeUnsubscribeReq.toTPipeSubscribeReq(topicNames); @@ -269,6 +274,9 @@ void unsubscribe(final Set topicNames) throws SubscriptionException { throw new SubscriptionConnectionException(e.getMessage(), e); } verifyPipeSubscribeSuccess(resp.status); + final PipeSubscribeUnsubscribeResp unsubscribeResp = + PipeSubscribeUnsubscribeResp.fromTPipeSubscribeResp(resp); + return unsubscribeResp.getTopicNames(); } List poll(final SubscriptionPollRequest pollMessage) diff --git a/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/consumer/SubscriptionPullConsumer.java b/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/consumer/SubscriptionPullConsumer.java index 2306e4d05c1e2..38dfc530ee352 100644 --- a/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/consumer/SubscriptionPullConsumer.java +++ b/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/consumer/SubscriptionPullConsumer.java @@ -22,6 +22,7 @@ import org.apache.iotdb.rpc.subscription.config.ConsumerConstant; import org.apache.iotdb.rpc.subscription.exception.SubscriptionException; import org.apache.iotdb.session.subscription.payload.SubscriptionMessage; +import org.apache.iotdb.session.subscription.util.IdentifierUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -39,6 +40,7 @@ import java.util.concurrent.ConcurrentSkipListSet; import java.util.concurrent.ScheduledFuture; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.stream.Collectors; /** * The {@link SubscriptionPullConsumer} corresponds to the pull consumption mode in the message @@ -150,7 +152,12 @@ public List poll(final Set topicNames, final Durati @Override public List poll(final Set topicNames, final long timeoutMs) throws SubscriptionException { - final List messages = super.poll(topicNames, timeoutMs); + // parse topic names from external source + final Set parsedTopicNames = + topicNames.stream().map(IdentifierUtils::parseIdentifier).collect(Collectors.toSet()); + + // poll messages + final List messages = super.poll(parsedTopicNames, timeoutMs); // add to uncommitted messages if (autoCommit) { diff --git a/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/consumer/SubscriptionPushConsumer.java b/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/consumer/SubscriptionPushConsumer.java index 7ff1dd39b15bd..7323473552caf 100644 --- a/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/consumer/SubscriptionPushConsumer.java +++ b/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/consumer/SubscriptionPushConsumer.java @@ -27,7 +27,6 @@ import org.slf4j.LoggerFactory; import java.util.ArrayList; -import java.util.Collections; import java.util.List; import java.util.Objects; import java.util.Properties; @@ -162,9 +161,12 @@ public void run() { return; } + if (subscribedTopicNames.isEmpty()) { + return; + } + try { - // Poll all subscribed topics by passing an empty set - final List messages = poll(Collections.emptySet(), autoPollTimeoutMs); + final List messages = poll(subscribedTopicNames, autoPollTimeoutMs); if (ackStrategy.equals(AckStrategy.BEFORE_CONSUME)) { ack(messages); diff --git a/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/payload/SubscriptionFileHandler.java b/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/payload/SubscriptionFileHandler.java index 60c269b86370c..0ec121f96992a 100644 --- a/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/payload/SubscriptionFileHandler.java +++ b/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/payload/SubscriptionFileHandler.java @@ -39,14 +39,14 @@ public SubscriptionFileHandler(final String absolutePath) { /** * @return a new File instance of the corresponding file */ - public File getFile() { + public synchronized File getFile() { return new File(absolutePath); } /** * @return a new Path instance of the corresponding file */ - public Path getPath() { + public synchronized Path getPath() { return Paths.get(absolutePath); } @@ -54,7 +54,7 @@ public Path getPath() { * @return the path to the source file * @throws IOException if an I/O error occurs */ - public Path deleteFile() throws IOException { + public synchronized Path deleteFile() throws IOException { final Path sourcePath = getPath(); Files.delete(sourcePath); return sourcePath; @@ -65,7 +65,7 @@ public Path deleteFile() throws IOException { * @return the path to the target file * @throws IOException if an I/O error occurs */ - public Path moveFile(final String target) throws IOException { + public synchronized Path moveFile(final String target) throws IOException { return this.moveFile(Paths.get(target)); } @@ -74,7 +74,10 @@ public Path moveFile(final String target) throws IOException { * @return the path to the target file * @throws IOException if an I/O error occurs */ - public Path moveFile(final Path target) throws IOException { + public synchronized Path moveFile(final Path target) throws IOException { + if (!Files.exists(target.getParent())) { + Files.createDirectories(target.getParent()); + } return Files.move(getPath(), target, StandardCopyOption.REPLACE_EXISTING); } @@ -83,7 +86,7 @@ public Path moveFile(final Path target) throws IOException { * @return the path to the target file * @throws IOException if an I/O error occurs */ - public Path copyFile(final String target) throws IOException { + public synchronized Path copyFile(final String target) throws IOException { return this.copyFile(Paths.get(target)); } @@ -92,7 +95,10 @@ public Path copyFile(final String target) throws IOException { * @return the path to the target file * @throws IOException if an I/O error occurs */ - public Path copyFile(final Path target) throws IOException { + public synchronized Path copyFile(final Path target) throws IOException { + if (!Files.exists(target.getParent())) { + Files.createDirectories(target.getParent()); + } return Files.copy( getPath(), target, StandardCopyOption.REPLACE_EXISTING, StandardCopyOption.COPY_ATTRIBUTES); } diff --git a/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/payload/SubscriptionSessionDataSet.java b/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/payload/SubscriptionSessionDataSet.java index 8b5b244950459..ee2beafdd9619 100644 --- a/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/payload/SubscriptionSessionDataSet.java +++ b/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/payload/SubscriptionSessionDataSet.java @@ -25,10 +25,12 @@ import org.apache.tsfile.read.common.Field; import org.apache.tsfile.read.common.RowRecord; import org.apache.tsfile.utils.Binary; +import org.apache.tsfile.utils.DateUtils; import org.apache.tsfile.write.UnSupportedDataTypeException; import org.apache.tsfile.write.record.Tablet; import org.apache.tsfile.write.schema.IMeasurementSchema; +import java.time.LocalDate; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -84,7 +86,7 @@ public List getColumnTypes() { List schemas = tablet.getSchemas(); columnTypeList.addAll( - schemas.stream().map((schema) -> schema.getType().toString()).collect(Collectors.toList())); + schemas.stream().map(schema -> schema.getType().toString()).collect(Collectors.toList())); return columnTypeList; } @@ -149,10 +151,13 @@ private static Field generateFieldFromTabletValue( field.setBoolV(booleanValue); break; case INT32: - case DATE: final int intValue = ((int[]) value)[index]; field.setIntV(intValue); break; + case DATE: + final LocalDate dateValue = ((LocalDate[]) value)[index]; + field.setIntV(DateUtils.parseDateExpressionToInt(dateValue)); + break; case INT64: case TIMESTAMP: final long longValue = ((long[]) value)[index]; diff --git a/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/util/IdentifierUtils.java b/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/util/IdentifierUtils.java new file mode 100644 index 0000000000000..9f6d09ef44e0f --- /dev/null +++ b/iotdb-client/session/src/main/java/org/apache/iotdb/session/subscription/util/IdentifierUtils.java @@ -0,0 +1,51 @@ +/* + * 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.iotdb.session.subscription.util; + +import org.apache.iotdb.rpc.subscription.exception.SubscriptionIdentifierSemanticException; + +import org.apache.tsfile.common.constant.TsFileConstant; +import org.apache.tsfile.read.common.parser.PathVisitor; + +public class IdentifierUtils { + + /** + * refer org.apache.iotdb.db.queryengine.plan.parser.ASTVisitor#parseIdentifier(java.lang.String) + */ + public static String parseIdentifier(final String src) { + if (src.startsWith(TsFileConstant.BACK_QUOTE_STRING) + && src.endsWith(TsFileConstant.BACK_QUOTE_STRING)) { + return src.substring(1, src.length() - 1) + .replace(TsFileConstant.DOUBLE_BACK_QUOTE_STRING, TsFileConstant.BACK_QUOTE_STRING); + } + checkIdentifier(src); + return src; + } + + private static void checkIdentifier(final String src) { + if (!TsFileConstant.IDENTIFIER_PATTERN.matcher(src).matches() + || PathVisitor.isRealNumber(src)) { + throw new SubscriptionIdentifierSemanticException( + String.format( + "%s is illegal, identifier not enclosed with backticks can only consist of digits, characters and underscore.", + src)); + } + } +} diff --git a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4 b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4 index 29c36e881e7dc..c9cfc400dcee7 100644 --- a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4 +++ b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IdentifierParser.g4 @@ -63,6 +63,7 @@ keyWords | CONDITION | CONFIGNODES | CONFIGURATION + | CONNECTION | CONNECTOR | CONTAIN | CONTAINS diff --git a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 index 6d3ffe0b837d8..4cff4e12b8cb6 100644 --- a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 +++ b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/IoTDBSqlParser.g4 @@ -47,7 +47,7 @@ ddlStatement | setSchemaTemplate | unsetSchemaTemplate | alterSchemaTemplate // TTL - | setTTL | unsetTTL | showAllTTL + | setTTL | unsetTTL | showTTL | showAllTTL // Function | createFunction | dropFunction | showFunctions // Trigger @@ -64,7 +64,7 @@ ddlStatement | createContinuousQuery | dropContinuousQuery | showContinuousQueries // Cluster | showVariables | showCluster | showRegions | showDataNodes | showConfigNodes | showClusterId - | getRegionId | getTimeSlotList | countTimeSlotList | getSeriesSlotList | migrateRegion + | getRegionId | getTimeSlotList | countTimeSlotList | getSeriesSlotList | migrateRegion | verifyConnection // Quota | setSpaceQuota | showSpaceQuota | setThrottleQuota | showThrottleQuota // View @@ -325,6 +325,11 @@ unsetTTL : UNSET TTL TO path=prefixPath ; +// ---- Show TTL +showTTL + : SHOW TTL ON prefixPath (COMMA prefixPath)* + ; + // ---- Show All TTL showAllTTL : SHOW ALL TTL @@ -524,6 +529,10 @@ migrateRegion : MIGRATE REGION regionId=INTEGER_LITERAL FROM fromId=INTEGER_LITERAL TO toId=INTEGER_LITERAL ; +verifyConnection + : VERIFY CONNECTION (DETAILS)? + ; + // Pipe Task ========================================================================================= createPipe : CREATE PIPE pipeName=identifier diff --git a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4 b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4 index 29cbcdcd17dfe..d1865a1e20486 100644 --- a/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4 +++ b/iotdb-core/antlr/src/main/antlr4/org/apache/iotdb/db/qp/sql/SqlLexer.g4 @@ -165,6 +165,10 @@ CONFIGURATION : C O N F I G U R A T I O N ; +CONNECTION + : C O N N E C T I O N + ; + CONNECTOR : C O N N E C T O R ; diff --git a/iotdb-core/confignode/src/assembly/resources/sbin/stop-confignode.sh b/iotdb-core/confignode/src/assembly/resources/sbin/stop-confignode.sh index 5604afd3d32fa..5b2ccef01a514 100644 --- a/iotdb-core/confignode/src/assembly/resources/sbin/stop-confignode.sh +++ b/iotdb-core/confignode/src/assembly/resources/sbin/stop-confignode.sh @@ -18,6 +18,7 @@ # under the License. # +source "$(dirname "$0")/iotdb-common.sh" CONFIGNODE_CONF="$(dirname "$0")/../conf" if [ -f "${CONFIGNODE_CONF}/iotdb-system.properties" ]; then @@ -26,6 +27,7 @@ else cn_internal_port=$(sed '/^cn_internal_port=/!d;s/.*=//' "${CONFIGNODE_CONF}"/iotdb-confignode.properties) fi +check_config_unique "cn_internal_port" "$cn_internal_port" echo Check whether the internal_port is used..., port is "$cn_internal_port" diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/ConfigNodeRequestType.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/CnToCnNodeRequestType.java similarity index 92% rename from iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/ConfigNodeRequestType.java rename to iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/CnToCnNodeRequestType.java index 5f3064b4eed73..3864f26cbc8e1 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/ConfigNodeRequestType.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/CnToCnNodeRequestType.java @@ -19,7 +19,7 @@ package org.apache.iotdb.confignode.client; -public enum ConfigNodeRequestType { +public enum CnToCnNodeRequestType { ADD_CONSENSUS_GROUP, NOTIFY_REGISTER_SUCCESS, REGISTER_CONFIG_NODE, @@ -30,4 +30,6 @@ public enum ConfigNodeRequestType { STOP_CONFIG_NODE, SET_CONFIGURATION, SHOW_CONFIGURATION, + SUBMIT_TEST_CONNECTION_TASK, + TEST_CONNECTION, } diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/DataNodeRequestType.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/CnToDnRequestType.java similarity index 97% rename from iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/DataNodeRequestType.java rename to iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/CnToDnRequestType.java index b53035b29d5a6..82e5974f3c80e 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/DataNodeRequestType.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/CnToDnRequestType.java @@ -19,7 +19,7 @@ package org.apache.iotdb.confignode.client; -public enum DataNodeRequestType { +public enum CnToDnRequestType { // Node Maintenance DISABLE_DATA_NODE, @@ -35,6 +35,9 @@ public enum DataNodeRequestType { SET_CONFIGURATION, SHOW_CONFIGURATION, + SUBMIT_TEST_CONNECTION_TASK, + TEST_CONNECTION, + // Region Maintenance CREATE_DATA_REGION, CREATE_SCHEMA_REGION, diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/AsyncConfigNodeHeartbeatClientPool.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/AsyncConfigNodeHeartbeatClientPool.java index fdcd3b0d1e299..7b6bca5d0d9e7 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/AsyncConfigNodeHeartbeatClientPool.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/AsyncConfigNodeHeartbeatClientPool.java @@ -22,17 +22,17 @@ import org.apache.iotdb.common.rpc.thrift.TEndPoint; import org.apache.iotdb.commons.client.ClientPoolFactory; import org.apache.iotdb.commons.client.IClientManager; -import org.apache.iotdb.commons.client.async.AsyncConfigNodeIServiceClient; +import org.apache.iotdb.commons.client.async.AsyncConfigNodeInternalServiceClient; import org.apache.iotdb.confignode.client.async.handlers.heartbeat.ConfigNodeHeartbeatHandler; import org.apache.iotdb.confignode.rpc.thrift.TConfigNodeHeartbeatReq; public class AsyncConfigNodeHeartbeatClientPool { - private final IClientManager clientManager; + private final IClientManager clientManager; private AsyncConfigNodeHeartbeatClientPool() { clientManager = - new IClientManager.Factory() + new IClientManager.Factory() .createClientManager( new ClientPoolFactory.AsyncConfigNodeHeartbeatServiceClientPoolFactory()); } @@ -53,7 +53,6 @@ public void getConfigNodeHeartBeat( } } - // TODO: Is the ClientPool must be a singleton? private static class AsyncConfigNodeHeartbeatClientPoolHolder { private static final AsyncConfigNodeHeartbeatClientPool INSTANCE = diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/AsyncDataNodeClientPool.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/AsyncDataNodeClientPool.java deleted file mode 100644 index 31bc4074701c6..0000000000000 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/AsyncDataNodeClientPool.java +++ /dev/null @@ -1,559 +0,0 @@ -/* - * 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.iotdb.confignode.client.async; - -import org.apache.iotdb.common.rpc.thrift.TConsensusGroupId; -import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; -import org.apache.iotdb.common.rpc.thrift.TEndPoint; -import org.apache.iotdb.common.rpc.thrift.TFlushReq; -import org.apache.iotdb.common.rpc.thrift.TSetConfigurationReq; -import org.apache.iotdb.common.rpc.thrift.TSetSpaceQuotaReq; -import org.apache.iotdb.common.rpc.thrift.TSetTTLReq; -import org.apache.iotdb.common.rpc.thrift.TSetThrottleQuotaReq; -import org.apache.iotdb.commons.client.ClientPoolFactory; -import org.apache.iotdb.commons.client.IClientManager; -import org.apache.iotdb.commons.client.async.AsyncDataNodeInternalServiceClient; -import org.apache.iotdb.commons.client.exception.ClientManagerException; -import org.apache.iotdb.confignode.client.DataNodeRequestType; -import org.apache.iotdb.confignode.client.async.handlers.AsyncClientHandler; -import org.apache.iotdb.confignode.client.async.handlers.rpc.AsyncTSStatusRPCHandler; -import org.apache.iotdb.confignode.client.async.handlers.rpc.CheckTimeSeriesExistenceRPCHandler; -import org.apache.iotdb.confignode.client.async.handlers.rpc.CountPathsUsingTemplateRPCHandler; -import org.apache.iotdb.confignode.client.async.handlers.rpc.FetchSchemaBlackListRPCHandler; -import org.apache.iotdb.confignode.client.async.handlers.rpc.PipeHeartbeatRPCHandler; -import org.apache.iotdb.confignode.client.async.handlers.rpc.PipePushMetaRPCHandler; -import org.apache.iotdb.confignode.client.async.handlers.rpc.SchemaUpdateRPCHandler; -import org.apache.iotdb.confignode.client.async.handlers.rpc.TransferLeaderRPCHandler; -import org.apache.iotdb.confignode.client.async.handlers.rpc.subscription.CheckSchemaRegionUsingTemplateRPCHandler; -import org.apache.iotdb.confignode.client.async.handlers.rpc.subscription.ConsumerGroupPushMetaRPCHandler; -import org.apache.iotdb.confignode.client.async.handlers.rpc.subscription.TopicPushMetaRPCHandler; -import org.apache.iotdb.mpp.rpc.thrift.TActiveTriggerInstanceReq; -import org.apache.iotdb.mpp.rpc.thrift.TAlterViewReq; -import org.apache.iotdb.mpp.rpc.thrift.TCheckSchemaRegionUsingTemplateReq; -import org.apache.iotdb.mpp.rpc.thrift.TCheckTimeSeriesExistenceReq; -import org.apache.iotdb.mpp.rpc.thrift.TConstructSchemaBlackListReq; -import org.apache.iotdb.mpp.rpc.thrift.TConstructSchemaBlackListWithTemplateReq; -import org.apache.iotdb.mpp.rpc.thrift.TConstructViewSchemaBlackListReq; -import org.apache.iotdb.mpp.rpc.thrift.TCountPathsUsingTemplateReq; -import org.apache.iotdb.mpp.rpc.thrift.TCreateDataRegionReq; -import org.apache.iotdb.mpp.rpc.thrift.TCreateFunctionInstanceReq; -import org.apache.iotdb.mpp.rpc.thrift.TCreatePipePluginInstanceReq; -import org.apache.iotdb.mpp.rpc.thrift.TCreateSchemaRegionReq; -import org.apache.iotdb.mpp.rpc.thrift.TCreateTriggerInstanceReq; -import org.apache.iotdb.mpp.rpc.thrift.TDeactivateTemplateReq; -import org.apache.iotdb.mpp.rpc.thrift.TDeleteDataForDeleteSchemaReq; -import org.apache.iotdb.mpp.rpc.thrift.TDeleteTimeSeriesReq; -import org.apache.iotdb.mpp.rpc.thrift.TDeleteViewSchemaReq; -import org.apache.iotdb.mpp.rpc.thrift.TDropFunctionInstanceReq; -import org.apache.iotdb.mpp.rpc.thrift.TDropPipePluginInstanceReq; -import org.apache.iotdb.mpp.rpc.thrift.TDropTriggerInstanceReq; -import org.apache.iotdb.mpp.rpc.thrift.TFetchSchemaBlackListReq; -import org.apache.iotdb.mpp.rpc.thrift.TInactiveTriggerInstanceReq; -import org.apache.iotdb.mpp.rpc.thrift.TInvalidateMatchedSchemaCacheReq; -import org.apache.iotdb.mpp.rpc.thrift.TPipeHeartbeatReq; -import org.apache.iotdb.mpp.rpc.thrift.TPushConsumerGroupMetaReq; -import org.apache.iotdb.mpp.rpc.thrift.TPushMultiPipeMetaReq; -import org.apache.iotdb.mpp.rpc.thrift.TPushMultiTopicMetaReq; -import org.apache.iotdb.mpp.rpc.thrift.TPushPipeMetaReq; -import org.apache.iotdb.mpp.rpc.thrift.TPushSingleConsumerGroupMetaReq; -import org.apache.iotdb.mpp.rpc.thrift.TPushSinglePipeMetaReq; -import org.apache.iotdb.mpp.rpc.thrift.TPushSingleTopicMetaReq; -import org.apache.iotdb.mpp.rpc.thrift.TPushTopicMetaReq; -import org.apache.iotdb.mpp.rpc.thrift.TRegionLeaderChangeReq; -import org.apache.iotdb.mpp.rpc.thrift.TRegionRouteReq; -import org.apache.iotdb.mpp.rpc.thrift.TResetPeerListReq; -import org.apache.iotdb.mpp.rpc.thrift.TRollbackSchemaBlackListReq; -import org.apache.iotdb.mpp.rpc.thrift.TRollbackSchemaBlackListWithTemplateReq; -import org.apache.iotdb.mpp.rpc.thrift.TRollbackViewSchemaBlackListReq; -import org.apache.iotdb.mpp.rpc.thrift.TUpdateTableReq; -import org.apache.iotdb.mpp.rpc.thrift.TUpdateTemplateReq; -import org.apache.iotdb.mpp.rpc.thrift.TUpdateTriggerLocationReq; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.concurrent.TimeUnit; - -/** Asynchronously send RPC requests to DataNodes. See queryengine.thrift for more details. */ -public class AsyncDataNodeClientPool { - - private static final Logger LOGGER = LoggerFactory.getLogger(AsyncDataNodeClientPool.class); - - private final IClientManager clientManager; - - private static final int MAX_RETRY_NUM = 6; - - private AsyncDataNodeClientPool() { - clientManager = - new IClientManager.Factory() - .createClientManager( - new ClientPoolFactory.AsyncDataNodeInternalServiceClientPoolFactory()); - } - - /** - * Send asynchronous requests to the specified DataNodes with default retry num - * - *

Notice: The DataNodes that failed to receive the requests will be reconnected - * - * @param clientHandler which will also contain the result - * @param timeoutInMs timeout in milliseconds - */ - public void sendAsyncRequestToDataNodeWithRetryAndTimeoutInMs( - AsyncClientHandler clientHandler, long timeoutInMs) { - sendAsyncRequest(clientHandler, MAX_RETRY_NUM, timeoutInMs); - } - - /** - * Send asynchronous requests to the specified DataNodes with default retry num - * - *

Notice: The DataNodes that failed to receive the requests will be reconnected - * - * @param clientHandler which will also contain the result - */ - public void sendAsyncRequestToDataNodeWithRetry(AsyncClientHandler clientHandler) { - sendAsyncRequest(clientHandler, MAX_RETRY_NUM, null); - } - - public void sendAsyncRequestToDataNode(AsyncClientHandler clientHandler) { - sendAsyncRequest(clientHandler, 1, null); - } - - private void sendAsyncRequest( - AsyncClientHandler clientHandler, int retryNum, Long timeoutInMs) { - if (clientHandler.getRequestIndices().isEmpty()) { - return; - } - - DataNodeRequestType requestType = clientHandler.getRequestType(); - for (int retry = 0; retry < retryNum; retry++) { - // Always Reset CountDownLatch first - clientHandler.resetCountDownLatch(); - - // Send requests to all targetDataNodes - for (int requestId : clientHandler.getRequestIndices()) { - TDataNodeLocation targetDataNode = clientHandler.getDataNodeLocation(requestId); - sendAsyncRequestToDataNode(clientHandler, requestId, targetDataNode, retry); - } - - // Wait for this batch of asynchronous RPC requests finish - try { - if (timeoutInMs == null) { - clientHandler.getCountDownLatch().await(); - } else { - if (!clientHandler.getCountDownLatch().await(timeoutInMs, TimeUnit.MILLISECONDS)) { - LOGGER.warn( - "Timeout during {} on ConfigNode. Retry: {}/{}", requestType, retry, retryNum); - } - } - } catch (InterruptedException e) { - LOGGER.error( - "Interrupted during {} on ConfigNode. Retry: {}/{}", requestType, retry, retryNum); - Thread.currentThread().interrupt(); - } - - // Check if there is a DataNode that fails to execute the request, and retry if there exists - if (clientHandler.getRequestIndices().isEmpty()) { - return; - } - } - - if (!clientHandler.getRequestIndices().isEmpty()) { - LOGGER.warn( - "Failed to {} on ConfigNode after {} retries, requestIndices: {}", - requestType, - retryNum, - clientHandler.getRequestIndices()); - } - } - - private void sendAsyncRequestToDataNode( - AsyncClientHandler clientHandler, - int requestId, - TDataNodeLocation targetDataNode, - int retryCount) { - - try { - AsyncDataNodeInternalServiceClient client; - client = clientManager.borrowClient(targetDataNode.getInternalEndPoint()); - - switch (clientHandler.getRequestType()) { - case SET_TTL: - client.setTTL( - (TSetTTLReq) clientHandler.getRequest(requestId), - (AsyncTSStatusRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case CREATE_DATA_REGION: - client.createDataRegion( - (TCreateDataRegionReq) clientHandler.getRequest(requestId), - (AsyncTSStatusRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case DELETE_REGION: - client.deleteRegion( - (TConsensusGroupId) clientHandler.getRequest(requestId), - (AsyncTSStatusRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case CREATE_SCHEMA_REGION: - client.createSchemaRegion( - (TCreateSchemaRegionReq) clientHandler.getRequest(requestId), - (AsyncTSStatusRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case CREATE_FUNCTION: - client.createFunction( - (TCreateFunctionInstanceReq) clientHandler.getRequest(requestId), - (AsyncTSStatusRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case DROP_FUNCTION: - client.dropFunction( - (TDropFunctionInstanceReq) clientHandler.getRequest(requestId), - (AsyncTSStatusRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case CREATE_TRIGGER_INSTANCE: - client.createTriggerInstance( - (TCreateTriggerInstanceReq) clientHandler.getRequest(requestId), - (AsyncTSStatusRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case DROP_TRIGGER_INSTANCE: - client.dropTriggerInstance( - (TDropTriggerInstanceReq) clientHandler.getRequest(requestId), - (AsyncTSStatusRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case ACTIVE_TRIGGER_INSTANCE: - client.activeTriggerInstance( - (TActiveTriggerInstanceReq) clientHandler.getRequest(requestId), - (AsyncTSStatusRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case INACTIVE_TRIGGER_INSTANCE: - client.inactiveTriggerInstance( - (TInactiveTriggerInstanceReq) clientHandler.getRequest(requestId), - (AsyncTSStatusRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case UPDATE_TRIGGER_LOCATION: - client.updateTriggerLocation( - (TUpdateTriggerLocationReq) clientHandler.getRequest(requestId), - (AsyncTSStatusRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case CREATE_PIPE_PLUGIN: - client.createPipePlugin( - (TCreatePipePluginInstanceReq) clientHandler.getRequest(requestId), - (AsyncTSStatusRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case DROP_PIPE_PLUGIN: - client.dropPipePlugin( - (TDropPipePluginInstanceReq) clientHandler.getRequest(requestId), - (AsyncTSStatusRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case PIPE_PUSH_ALL_META: - client.pushPipeMeta( - (TPushPipeMetaReq) clientHandler.getRequest(requestId), - (PipePushMetaRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case PIPE_PUSH_SINGLE_META: - client.pushSinglePipeMeta( - (TPushSinglePipeMetaReq) clientHandler.getRequest(requestId), - (PipePushMetaRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case PIPE_PUSH_MULTI_META: - client.pushMultiPipeMeta( - (TPushMultiPipeMetaReq) clientHandler.getRequest(requestId), - (PipePushMetaRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case TOPIC_PUSH_ALL_META: - client.pushTopicMeta( - (TPushTopicMetaReq) clientHandler.getRequest(requestId), - (TopicPushMetaRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case TOPIC_PUSH_SINGLE_META: - client.pushSingleTopicMeta( - (TPushSingleTopicMetaReq) clientHandler.getRequest(requestId), - (TopicPushMetaRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case TOPIC_PUSH_MULTI_META: - client.pushMultiTopicMeta( - (TPushMultiTopicMetaReq) clientHandler.getRequest(requestId), - (TopicPushMetaRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case CONSUMER_GROUP_PUSH_ALL_META: - client.pushConsumerGroupMeta( - (TPushConsumerGroupMetaReq) clientHandler.getRequest(requestId), - (ConsumerGroupPushMetaRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case CONSUMER_GROUP_PUSH_SINGLE_META: - client.pushSingleConsumerGroupMeta( - (TPushSingleConsumerGroupMetaReq) clientHandler.getRequest(requestId), - (ConsumerGroupPushMetaRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case PIPE_HEARTBEAT: - client.pipeHeartbeat( - (TPipeHeartbeatReq) clientHandler.getRequest(requestId), - (PipeHeartbeatRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case MERGE: - case FULL_MERGE: - client.merge( - (AsyncTSStatusRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case FLUSH: - client.flush( - (TFlushReq) clientHandler.getRequest(requestId), - (AsyncTSStatusRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case CLEAR_CACHE: - client.clearCache( - (AsyncTSStatusRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case SET_CONFIGURATION: - client.setConfiguration( - (TSetConfigurationReq) clientHandler.getRequest(requestId), - (AsyncTSStatusRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case START_REPAIR_DATA: - client.startRepairData( - (AsyncTSStatusRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case STOP_REPAIR_DATA: - client.stopRepairData( - (AsyncTSStatusRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case LOAD_CONFIGURATION: - client.loadConfiguration( - (AsyncTSStatusRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case SET_SYSTEM_STATUS: - client.setSystemStatus( - (String) clientHandler.getRequest(requestId), - (AsyncTSStatusRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case UPDATE_REGION_ROUTE_MAP: - client.updateRegionCache( - (TRegionRouteReq) clientHandler.getRequest(requestId), - (AsyncTSStatusRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case CHANGE_REGION_LEADER: - client.changeRegionLeader( - (TRegionLeaderChangeReq) clientHandler.getRequest(requestId), - (TransferLeaderRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case CONSTRUCT_SCHEMA_BLACK_LIST: - client.constructSchemaBlackList( - (TConstructSchemaBlackListReq) clientHandler.getRequest(requestId), - (SchemaUpdateRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case ROLLBACK_SCHEMA_BLACK_LIST: - client.rollbackSchemaBlackList( - (TRollbackSchemaBlackListReq) clientHandler.getRequest(requestId), - (SchemaUpdateRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case FETCH_SCHEMA_BLACK_LIST: - client.fetchSchemaBlackList( - (TFetchSchemaBlackListReq) clientHandler.getRequest(requestId), - (FetchSchemaBlackListRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case INVALIDATE_MATCHED_SCHEMA_CACHE: - client.invalidateMatchedSchemaCache( - (TInvalidateMatchedSchemaCacheReq) clientHandler.getRequest(requestId), - (AsyncTSStatusRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case DELETE_DATA_FOR_DELETE_SCHEMA: - client.deleteDataForDeleteSchema( - (TDeleteDataForDeleteSchemaReq) clientHandler.getRequest(requestId), - (SchemaUpdateRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case DELETE_TIMESERIES: - client.deleteTimeSeries( - (TDeleteTimeSeriesReq) clientHandler.getRequest(requestId), - (SchemaUpdateRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case CONSTRUCT_SCHEMA_BLACK_LIST_WITH_TEMPLATE: - client.constructSchemaBlackListWithTemplate( - (TConstructSchemaBlackListWithTemplateReq) clientHandler.getRequest(requestId), - (SchemaUpdateRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case ROLLBACK_SCHEMA_BLACK_LIST_WITH_TEMPLATE: - client.rollbackSchemaBlackListWithTemplate( - (TRollbackSchemaBlackListWithTemplateReq) clientHandler.getRequest(requestId), - (SchemaUpdateRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case DEACTIVATE_TEMPLATE: - client.deactivateTemplate( - (TDeactivateTemplateReq) clientHandler.getRequest(requestId), - (SchemaUpdateRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case UPDATE_TEMPLATE: - client.updateTemplate( - (TUpdateTemplateReq) clientHandler.getRequest(requestId), - (AsyncTSStatusRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case COUNT_PATHS_USING_TEMPLATE: - client.countPathsUsingTemplate( - (TCountPathsUsingTemplateReq) clientHandler.getRequest(requestId), - (CountPathsUsingTemplateRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case CHECK_SCHEMA_REGION_USING_TEMPLATE: - client.checkSchemaRegionUsingTemplate( - (TCheckSchemaRegionUsingTemplateReq) clientHandler.getRequest(requestId), - (CheckSchemaRegionUsingTemplateRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case CHECK_TIMESERIES_EXISTENCE: - client.checkTimeSeriesExistence( - (TCheckTimeSeriesExistenceReq) clientHandler.getRequest(requestId), - (CheckTimeSeriesExistenceRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case CONSTRUCT_VIEW_SCHEMA_BLACK_LIST: - client.constructViewSchemaBlackList( - (TConstructViewSchemaBlackListReq) clientHandler.getRequest(requestId), - (SchemaUpdateRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case ROLLBACK_VIEW_SCHEMA_BLACK_LIST: - client.rollbackViewSchemaBlackList( - (TRollbackViewSchemaBlackListReq) clientHandler.getRequest(requestId), - (SchemaUpdateRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case DELETE_VIEW: - client.deleteViewSchema( - (TDeleteViewSchemaReq) clientHandler.getRequest(requestId), - (SchemaUpdateRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case ALTER_VIEW: - client.alterView( - (TAlterViewReq) clientHandler.getRequest(requestId), - (SchemaUpdateRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case KILL_QUERY_INSTANCE: - client.killQueryInstance( - (String) clientHandler.getRequest(requestId), - (AsyncTSStatusRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case SET_SPACE_QUOTA: - client.setSpaceQuota( - (TSetSpaceQuotaReq) clientHandler.getRequest(requestId), - (AsyncTSStatusRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case SET_THROTTLE_QUOTA: - client.setThrottleQuota( - (TSetThrottleQuotaReq) clientHandler.getRequest(requestId), - (AsyncTSStatusRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case RESET_PEER_LIST: - client.resetPeerList( - (TResetPeerListReq) clientHandler.getRequest(requestId), - (AsyncTSStatusRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - case UPDATE_TABLE: - client.updateTable( - (TUpdateTableReq) clientHandler.getRequest(requestId), - (AsyncTSStatusRPCHandler) - clientHandler.createAsyncRPCHandler(requestId, targetDataNode)); - break; - default: - LOGGER.error( - "Unexpected DataNode Request Type: {} when sendAsyncRequestToDataNode", - clientHandler.getRequestType()); - } - } catch (Exception e) { - LOGGER.warn( - "{} failed on DataNode {}, because {}, retrying {}...", - clientHandler.getRequestType(), - targetDataNode.getInternalEndPoint(), - e.getMessage(), - retryCount); - } - } - - /** - * Always call this interface when a DataNode is restarted or removed. - * - * @param endPoint The specific DataNode - */ - public void resetClient(TEndPoint endPoint) { - clientManager.clear(endPoint); - } - - public AsyncDataNodeInternalServiceClient getAsyncClient(TDataNodeLocation targetDataNode) - throws ClientManagerException { - return clientManager.borrowClient(targetDataNode.getInternalEndPoint()); - } - - // TODO: Is the ClientPool must be a singleton? - private static class ClientPoolHolder { - - private static final AsyncDataNodeClientPool INSTANCE = new AsyncDataNodeClientPool(); - - private ClientPoolHolder() { - // Empty constructor - } - } - - public static AsyncDataNodeClientPool getInstance() { - return ClientPoolHolder.INSTANCE; - } -} diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/CnToCnInternalServiceAsyncRequestManager.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/CnToCnInternalServiceAsyncRequestManager.java new file mode 100644 index 0000000000000..bd5ee3fe4995f --- /dev/null +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/CnToCnInternalServiceAsyncRequestManager.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.confignode.client.async; + +import org.apache.iotdb.common.rpc.thrift.TConfigNodeLocation; +import org.apache.iotdb.common.rpc.thrift.TNodeLocations; +import org.apache.iotdb.commons.client.request.AsyncRequestContext; +import org.apache.iotdb.commons.client.request.AsyncRequestRPCHandler; +import org.apache.iotdb.commons.client.request.ConfigNodeInternalServiceAsyncRequestManager; +import org.apache.iotdb.confignode.client.CnToCnNodeRequestType; +import org.apache.iotdb.confignode.client.async.handlers.rpc.ConfigNodeAsyncRequestRPCHandler; +import org.apache.iotdb.confignode.client.async.handlers.rpc.ConfigNodeTSStatusRPCHandler; +import org.apache.iotdb.confignode.client.async.handlers.rpc.SubmitTestConnectionTaskToConfigNodeRPCHandler; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class CnToCnInternalServiceAsyncRequestManager + extends ConfigNodeInternalServiceAsyncRequestManager { + + private static final Logger LOGGER = + LoggerFactory.getLogger(CnToCnInternalServiceAsyncRequestManager.class); + + @Override + protected void initActionMapBuilder() { + actionMapBuilder.put( + CnToCnNodeRequestType.SUBMIT_TEST_CONNECTION_TASK, + (req, client, handler) -> + client.submitTestConnectionTask( + (TNodeLocations) req, (SubmitTestConnectionTaskToConfigNodeRPCHandler) handler)); + actionMapBuilder.put( + CnToCnNodeRequestType.TEST_CONNECTION, + (req, client, handler) -> + client.testConnectionEmptyRPC((ConfigNodeTSStatusRPCHandler) handler)); + } + + @Override + protected AsyncRequestRPCHandler buildHandler( + AsyncRequestContext requestContext, + int requestId, + TConfigNodeLocation targetNode) { + return ConfigNodeAsyncRequestRPCHandler.buildHandler(requestContext, requestId, targetNode); + } + + private static class ClientPoolHolder { + private static final CnToCnInternalServiceAsyncRequestManager INSTANCE = + new CnToCnInternalServiceAsyncRequestManager(); + + private ClientPoolHolder() { + // Empty constructor + } + } + + public static CnToCnInternalServiceAsyncRequestManager getInstance() { + return ClientPoolHolder.INSTANCE; + } +} diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/CnToDnInternalServiceAsyncRequestManager.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/CnToDnInternalServiceAsyncRequestManager.java new file mode 100644 index 0000000000000..8f3e7c720fc63 --- /dev/null +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/CnToDnInternalServiceAsyncRequestManager.java @@ -0,0 +1,376 @@ +/* + * 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.iotdb.confignode.client.async; + +import org.apache.iotdb.common.rpc.thrift.TConsensusGroupId; +import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; +import org.apache.iotdb.common.rpc.thrift.TFlushReq; +import org.apache.iotdb.common.rpc.thrift.TNodeLocations; +import org.apache.iotdb.common.rpc.thrift.TSetConfigurationReq; +import org.apache.iotdb.common.rpc.thrift.TSetSpaceQuotaReq; +import org.apache.iotdb.common.rpc.thrift.TSetTTLReq; +import org.apache.iotdb.common.rpc.thrift.TSetThrottleQuotaReq; +import org.apache.iotdb.commons.client.request.AsyncRequestContext; +import org.apache.iotdb.commons.client.request.AsyncRequestRPCHandler; +import org.apache.iotdb.commons.client.request.DataNodeInternalServiceRequestManager; +import org.apache.iotdb.confignode.client.CnToDnRequestType; +import org.apache.iotdb.confignode.client.async.handlers.rpc.CheckTimeSeriesExistenceRPCHandler; +import org.apache.iotdb.confignode.client.async.handlers.rpc.CountPathsUsingTemplateRPCHandler; +import org.apache.iotdb.confignode.client.async.handlers.rpc.DataNodeAsyncRequestRPCHandler; +import org.apache.iotdb.confignode.client.async.handlers.rpc.DataNodeTSStatusRPCHandler; +import org.apache.iotdb.confignode.client.async.handlers.rpc.FetchSchemaBlackListRPCHandler; +import org.apache.iotdb.confignode.client.async.handlers.rpc.PipeHeartbeatRPCHandler; +import org.apache.iotdb.confignode.client.async.handlers.rpc.PipePushMetaRPCHandler; +import org.apache.iotdb.confignode.client.async.handlers.rpc.SchemaUpdateRPCHandler; +import org.apache.iotdb.confignode.client.async.handlers.rpc.SubmitTestConnectionTaskRPCHandler; +import org.apache.iotdb.confignode.client.async.handlers.rpc.TransferLeaderRPCHandler; +import org.apache.iotdb.confignode.client.async.handlers.rpc.subscription.CheckSchemaRegionUsingTemplateRPCHandler; +import org.apache.iotdb.confignode.client.async.handlers.rpc.subscription.ConsumerGroupPushMetaRPCHandler; +import org.apache.iotdb.confignode.client.async.handlers.rpc.subscription.TopicPushMetaRPCHandler; +import org.apache.iotdb.mpp.rpc.thrift.TActiveTriggerInstanceReq; +import org.apache.iotdb.mpp.rpc.thrift.TAlterViewReq; +import org.apache.iotdb.mpp.rpc.thrift.TCheckSchemaRegionUsingTemplateReq; +import org.apache.iotdb.mpp.rpc.thrift.TCheckTimeSeriesExistenceReq; +import org.apache.iotdb.mpp.rpc.thrift.TConstructSchemaBlackListReq; +import org.apache.iotdb.mpp.rpc.thrift.TConstructSchemaBlackListWithTemplateReq; +import org.apache.iotdb.mpp.rpc.thrift.TConstructViewSchemaBlackListReq; +import org.apache.iotdb.mpp.rpc.thrift.TCountPathsUsingTemplateReq; +import org.apache.iotdb.mpp.rpc.thrift.TCreateDataRegionReq; +import org.apache.iotdb.mpp.rpc.thrift.TCreateFunctionInstanceReq; +import org.apache.iotdb.mpp.rpc.thrift.TCreatePipePluginInstanceReq; +import org.apache.iotdb.mpp.rpc.thrift.TCreateSchemaRegionReq; +import org.apache.iotdb.mpp.rpc.thrift.TCreateTriggerInstanceReq; +import org.apache.iotdb.mpp.rpc.thrift.TDeactivateTemplateReq; +import org.apache.iotdb.mpp.rpc.thrift.TDeleteDataForDeleteSchemaReq; +import org.apache.iotdb.mpp.rpc.thrift.TDeleteTimeSeriesReq; +import org.apache.iotdb.mpp.rpc.thrift.TDeleteViewSchemaReq; +import org.apache.iotdb.mpp.rpc.thrift.TDropFunctionInstanceReq; +import org.apache.iotdb.mpp.rpc.thrift.TDropPipePluginInstanceReq; +import org.apache.iotdb.mpp.rpc.thrift.TDropTriggerInstanceReq; +import org.apache.iotdb.mpp.rpc.thrift.TFetchSchemaBlackListReq; +import org.apache.iotdb.mpp.rpc.thrift.TInactiveTriggerInstanceReq; +import org.apache.iotdb.mpp.rpc.thrift.TInvalidateMatchedSchemaCacheReq; +import org.apache.iotdb.mpp.rpc.thrift.TPipeHeartbeatReq; +import org.apache.iotdb.mpp.rpc.thrift.TPushConsumerGroupMetaReq; +import org.apache.iotdb.mpp.rpc.thrift.TPushMultiPipeMetaReq; +import org.apache.iotdb.mpp.rpc.thrift.TPushMultiTopicMetaReq; +import org.apache.iotdb.mpp.rpc.thrift.TPushPipeMetaReq; +import org.apache.iotdb.mpp.rpc.thrift.TPushSingleConsumerGroupMetaReq; +import org.apache.iotdb.mpp.rpc.thrift.TPushSinglePipeMetaReq; +import org.apache.iotdb.mpp.rpc.thrift.TPushSingleTopicMetaReq; +import org.apache.iotdb.mpp.rpc.thrift.TPushTopicMetaReq; +import org.apache.iotdb.mpp.rpc.thrift.TRegionLeaderChangeReq; +import org.apache.iotdb.mpp.rpc.thrift.TRegionRouteReq; +import org.apache.iotdb.mpp.rpc.thrift.TResetPeerListReq; +import org.apache.iotdb.mpp.rpc.thrift.TRollbackSchemaBlackListReq; +import org.apache.iotdb.mpp.rpc.thrift.TRollbackSchemaBlackListWithTemplateReq; +import org.apache.iotdb.mpp.rpc.thrift.TRollbackViewSchemaBlackListReq; +import org.apache.iotdb.mpp.rpc.thrift.TUpdateTemplateReq; +import org.apache.iotdb.mpp.rpc.thrift.TUpdateTriggerLocationReq; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +/** Asynchronously send RPC requests to DataNodes. See queryengine.thrift for more details. */ +public class CnToDnInternalServiceAsyncRequestManager + extends DataNodeInternalServiceRequestManager { + + private static final Logger LOGGER = + LoggerFactory.getLogger(CnToDnInternalServiceAsyncRequestManager.class); + + @Override + protected void initActionMapBuilder() { + actionMapBuilder.put( + CnToDnRequestType.SET_TTL, + (req, client, handler) -> + client.setTTL((TSetTTLReq) req, (DataNodeTSStatusRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.CREATE_DATA_REGION, + (req, client, handler) -> + client.createDataRegion( + (TCreateDataRegionReq) req, (DataNodeTSStatusRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.DELETE_REGION, + (req, client, handler) -> + client.deleteRegion((TConsensusGroupId) req, (DataNodeTSStatusRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.CREATE_SCHEMA_REGION, + (req, client, handler) -> + client.createSchemaRegion( + (TCreateSchemaRegionReq) req, (DataNodeTSStatusRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.CREATE_FUNCTION, + (req, client, handler) -> + client.createFunction( + (TCreateFunctionInstanceReq) req, (DataNodeTSStatusRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.DROP_FUNCTION, + (req, client, handler) -> + client.dropFunction( + (TDropFunctionInstanceReq) req, (DataNodeTSStatusRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.CREATE_TRIGGER_INSTANCE, + (req, client, handler) -> + client.createTriggerInstance( + (TCreateTriggerInstanceReq) req, (DataNodeTSStatusRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.DROP_TRIGGER_INSTANCE, + (req, client, handler) -> + client.dropTriggerInstance( + (TDropTriggerInstanceReq) req, (DataNodeTSStatusRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.ACTIVE_TRIGGER_INSTANCE, + (req, client, handler) -> + client.activeTriggerInstance( + (TActiveTriggerInstanceReq) req, (DataNodeTSStatusRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.INACTIVE_TRIGGER_INSTANCE, + (req, client, handler) -> + client.inactiveTriggerInstance( + (TInactiveTriggerInstanceReq) req, (DataNodeTSStatusRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.UPDATE_TRIGGER_LOCATION, + (req, client, handler) -> + client.updateTriggerLocation( + (TUpdateTriggerLocationReq) req, (DataNodeTSStatusRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.CREATE_PIPE_PLUGIN, + (req, client, handler) -> + client.createPipePlugin( + (TCreatePipePluginInstanceReq) req, (DataNodeTSStatusRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.DROP_PIPE_PLUGIN, + (req, client, handler) -> + client.dropPipePlugin( + (TDropPipePluginInstanceReq) req, (DataNodeTSStatusRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.PIPE_PUSH_ALL_META, + (req, client, handler) -> + client.pushPipeMeta((TPushPipeMetaReq) req, (PipePushMetaRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.PIPE_PUSH_SINGLE_META, + (req, client, handler) -> + client.pushSinglePipeMeta( + (TPushSinglePipeMetaReq) req, (PipePushMetaRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.PIPE_PUSH_MULTI_META, + (req, client, handler) -> + client.pushMultiPipeMeta( + (TPushMultiPipeMetaReq) req, (PipePushMetaRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.TOPIC_PUSH_ALL_META, + (req, client, handler) -> + client.pushTopicMeta((TPushTopicMetaReq) req, (TopicPushMetaRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.TOPIC_PUSH_SINGLE_META, + (req, client, handler) -> + client.pushSingleTopicMeta( + (TPushSingleTopicMetaReq) req, (TopicPushMetaRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.TOPIC_PUSH_MULTI_META, + (req, client, handler) -> + client.pushMultiTopicMeta( + (TPushMultiTopicMetaReq) req, (TopicPushMetaRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.CONSUMER_GROUP_PUSH_ALL_META, + (req, client, handler) -> + client.pushConsumerGroupMeta( + (TPushConsumerGroupMetaReq) req, (ConsumerGroupPushMetaRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.CONSUMER_GROUP_PUSH_SINGLE_META, + (req, client, handler) -> + client.pushSingleConsumerGroupMeta( + (TPushSingleConsumerGroupMetaReq) req, (ConsumerGroupPushMetaRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.PIPE_HEARTBEAT, + (req, client, handler) -> + client.pipeHeartbeat((TPipeHeartbeatReq) req, (PipeHeartbeatRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.MERGE, + (req, client, handler) -> client.merge((DataNodeTSStatusRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.FULL_MERGE, + (req, client, handler) -> client.merge((DataNodeTSStatusRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.FLUSH, + (req, client, handler) -> + client.flush((TFlushReq) req, (DataNodeTSStatusRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.CLEAR_CACHE, + (req, client, handler) -> client.clearCache((DataNodeTSStatusRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.START_REPAIR_DATA, + (req, client, handler) -> client.startRepairData((DataNodeTSStatusRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.STOP_REPAIR_DATA, + (req, client, handler) -> client.stopRepairData((DataNodeTSStatusRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.LOAD_CONFIGURATION, + (req, client, handler) -> client.loadConfiguration((DataNodeTSStatusRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.SET_SYSTEM_STATUS, + (req, client, handler) -> + client.setSystemStatus((String) req, (DataNodeTSStatusRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.SET_CONFIGURATION, + (req, client, handler) -> + client.setConfiguration( + (TSetConfigurationReq) req, (DataNodeTSStatusRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.UPDATE_REGION_ROUTE_MAP, + (req, client, handler) -> + client.updateRegionCache((TRegionRouteReq) req, (DataNodeTSStatusRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.CHANGE_REGION_LEADER, + (req, client, handler) -> + client.changeRegionLeader( + (TRegionLeaderChangeReq) req, (TransferLeaderRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.CONSTRUCT_SCHEMA_BLACK_LIST, + (req, client, handler) -> + client.constructSchemaBlackList( + (TConstructSchemaBlackListReq) req, (SchemaUpdateRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.ROLLBACK_SCHEMA_BLACK_LIST, + (req, client, handler) -> + client.rollbackSchemaBlackList( + (TRollbackSchemaBlackListReq) req, (SchemaUpdateRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.FETCH_SCHEMA_BLACK_LIST, + (req, client, handler) -> + client.fetchSchemaBlackList( + (TFetchSchemaBlackListReq) req, (FetchSchemaBlackListRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.INVALIDATE_MATCHED_SCHEMA_CACHE, + (req, client, handler) -> + client.invalidateMatchedSchemaCache( + (TInvalidateMatchedSchemaCacheReq) req, (DataNodeTSStatusRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.DELETE_DATA_FOR_DELETE_SCHEMA, + (req, client, handler) -> + client.deleteDataForDeleteSchema( + (TDeleteDataForDeleteSchemaReq) req, (SchemaUpdateRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.DELETE_TIMESERIES, + (req, client, handler) -> + client.deleteTimeSeries((TDeleteTimeSeriesReq) req, (SchemaUpdateRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.CONSTRUCT_SCHEMA_BLACK_LIST_WITH_TEMPLATE, + (req, client, handler) -> + client.constructSchemaBlackListWithTemplate( + (TConstructSchemaBlackListWithTemplateReq) req, (SchemaUpdateRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.ROLLBACK_SCHEMA_BLACK_LIST_WITH_TEMPLATE, + (req, client, handler) -> + client.rollbackSchemaBlackListWithTemplate( + (TRollbackSchemaBlackListWithTemplateReq) req, (SchemaUpdateRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.DEACTIVATE_TEMPLATE, + (req, client, handler) -> + client.deactivateTemplate( + (TDeactivateTemplateReq) req, (SchemaUpdateRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.UPDATE_TEMPLATE, + (req, client, handler) -> + client.updateTemplate((TUpdateTemplateReq) req, (DataNodeTSStatusRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.COUNT_PATHS_USING_TEMPLATE, + (req, client, handler) -> + client.countPathsUsingTemplate( + (TCountPathsUsingTemplateReq) req, (CountPathsUsingTemplateRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.CHECK_SCHEMA_REGION_USING_TEMPLATE, + (req, client, handler) -> + client.checkSchemaRegionUsingTemplate( + (TCheckSchemaRegionUsingTemplateReq) req, + (CheckSchemaRegionUsingTemplateRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.CHECK_TIMESERIES_EXISTENCE, + (req, client, handler) -> + client.checkTimeSeriesExistence( + (TCheckTimeSeriesExistenceReq) req, (CheckTimeSeriesExistenceRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.CONSTRUCT_VIEW_SCHEMA_BLACK_LIST, + (req, client, handler) -> + client.constructViewSchemaBlackList( + (TConstructViewSchemaBlackListReq) req, (SchemaUpdateRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.ROLLBACK_VIEW_SCHEMA_BLACK_LIST, + (req, client, handler) -> + client.rollbackViewSchemaBlackList( + (TRollbackViewSchemaBlackListReq) req, (SchemaUpdateRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.DELETE_VIEW, + (req, client, handler) -> + client.deleteViewSchema((TDeleteViewSchemaReq) req, (SchemaUpdateRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.ALTER_VIEW, + (req, client, handler) -> + client.alterView((TAlterViewReq) req, (SchemaUpdateRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.KILL_QUERY_INSTANCE, + (req, client, handler) -> + client.killQueryInstance((String) req, (DataNodeTSStatusRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.SET_SPACE_QUOTA, + (req, client, handler) -> + client.setSpaceQuota((TSetSpaceQuotaReq) req, (DataNodeTSStatusRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.SET_THROTTLE_QUOTA, + (req, client, handler) -> + client.setThrottleQuota( + (TSetThrottleQuotaReq) req, (DataNodeTSStatusRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.RESET_PEER_LIST, + (req, client, handler) -> + client.resetPeerList((TResetPeerListReq) req, (DataNodeTSStatusRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.SUBMIT_TEST_CONNECTION_TASK, + (req, client, handler) -> + client.submitTestConnectionTask( + (TNodeLocations) req, (SubmitTestConnectionTaskRPCHandler) handler)); + actionMapBuilder.put( + CnToDnRequestType.TEST_CONNECTION, + (req, client, handler) -> + client.testConnectionEmptyRPC((DataNodeTSStatusRPCHandler) handler)); + } + + @Override + protected AsyncRequestRPCHandler buildHandler( + AsyncRequestContext requestContext, + int requestId, + TDataNodeLocation targetNode) { + return DataNodeAsyncRequestRPCHandler.buildHandler(requestContext, requestId, targetNode); + } + + private static class ClientPoolHolder { + + private static final CnToDnInternalServiceAsyncRequestManager INSTANCE = + new CnToDnInternalServiceAsyncRequestManager(); + + private ClientPoolHolder() { + // Empty constructor + } + } + + public static CnToDnInternalServiceAsyncRequestManager getInstance() { + return ClientPoolHolder.INSTANCE; + } +} diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/ConfigNodeAsyncRequestContext.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/ConfigNodeAsyncRequestContext.java new file mode 100644 index 0000000000000..cde2cf1c8ec2f --- /dev/null +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/ConfigNodeAsyncRequestContext.java @@ -0,0 +1,43 @@ +/* + * 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.iotdb.confignode.client.async.handlers; + +import org.apache.iotdb.common.rpc.thrift.TConfigNodeLocation; +import org.apache.iotdb.commons.client.request.AsyncRequestContext; +import org.apache.iotdb.confignode.client.CnToCnNodeRequestType; + +import java.util.Map; + +/** + * Asynchronous Client handler. + * + * @param ClassName of RPC request + * @param ClassName of RPC response + */ +public class ConfigNodeAsyncRequestContext + extends AsyncRequestContext { + + public ConfigNodeAsyncRequestContext( + CnToCnNodeRequestType configNodeRequestType, + Q q, + Map integerTConfigNodeLocationMap) { + super(configNodeRequestType, q, integerTConfigNodeLocationMap); + } +} diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/DataNodeAsyncRequestContext.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/DataNodeAsyncRequestContext.java new file mode 100644 index 0000000000000..2b813c081d7e7 --- /dev/null +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/DataNodeAsyncRequestContext.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.confignode.client.async.handlers; + +import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; +import org.apache.iotdb.commons.client.request.AsyncRequestContext; +import org.apache.iotdb.confignode.client.CnToDnRequestType; + +import java.util.Map; + +/** + * Asynchronous Client handler. + * + * @param ClassName of RPC request + * @param ClassName of RPC response + */ +public class DataNodeAsyncRequestContext + extends AsyncRequestContext { + + public DataNodeAsyncRequestContext(CnToDnRequestType requestType) { + super(requestType); + } + + public DataNodeAsyncRequestContext( + CnToDnRequestType requestType, Map dataNodeLocationMap) { + super(requestType, dataNodeLocationMap); + } + + public DataNodeAsyncRequestContext( + CnToDnRequestType requestType, Q q, Map dataNodeLocationMap) { + super(requestType, q, dataNodeLocationMap); + } +} diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/CheckTimeSeriesExistenceRPCHandler.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/CheckTimeSeriesExistenceRPCHandler.java index 150947f1b97b1..b12ba289f1c2a 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/CheckTimeSeriesExistenceRPCHandler.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/CheckTimeSeriesExistenceRPCHandler.java @@ -21,7 +21,7 @@ import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; import org.apache.iotdb.common.rpc.thrift.TSStatus; -import org.apache.iotdb.confignode.client.DataNodeRequestType; +import org.apache.iotdb.confignode.client.CnToDnRequestType; import org.apache.iotdb.mpp.rpc.thrift.TCheckTimeSeriesExistenceResp; import org.apache.iotdb.rpc.RpcUtils; import org.apache.iotdb.rpc.TSStatusCode; @@ -33,13 +33,13 @@ import java.util.concurrent.CountDownLatch; public class CheckTimeSeriesExistenceRPCHandler - extends AbstractAsyncRPCHandler { + extends DataNodeAsyncRequestRPCHandler { private static final Logger LOGGER = LoggerFactory.getLogger(CheckTimeSeriesExistenceRPCHandler.class); public CheckTimeSeriesExistenceRPCHandler( - DataNodeRequestType requestType, + CnToDnRequestType requestType, int requestId, TDataNodeLocation targetDataNode, Map dataNodeLocationMap, @@ -53,15 +53,13 @@ public void onComplete(TCheckTimeSeriesExistenceResp response) { TSStatus tsStatus = response.getStatus(); responseMap.put(requestId, response); if (tsStatus.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { - dataNodeLocationMap.remove(requestId); - LOGGER.info("Successfully check timeseries existence on DataNode: {}", targetDataNode); + nodeLocationMap.remove(requestId); + LOGGER.info("Successfully check timeseries existence on DataNode: {}", targetNode); } else if (tsStatus.getCode() == TSStatusCode.MULTIPLE_ERROR.getStatusCode()) { - dataNodeLocationMap.remove(requestId); - LOGGER.error( - "Failed to check timeseries existence on DataNode {}, {}", targetDataNode, tsStatus); + nodeLocationMap.remove(requestId); + LOGGER.error("Failed to check timeseries existence on DataNode {}, {}", targetNode, tsStatus); } else { - LOGGER.error( - "Failed to check timeseries existence on DataNode {}, {}", targetDataNode, tsStatus); + LOGGER.error("Failed to check timeseries existence on DataNode {}, {}", targetNode, tsStatus); } countDownLatch.countDown(); } @@ -70,9 +68,9 @@ public void onComplete(TCheckTimeSeriesExistenceResp response) { public void onError(Exception e) { String errorMsg = "Check timeseries existence error on DataNode: {id=" - + targetDataNode.getDataNodeId() + + targetNode.getDataNodeId() + ", internalEndPoint=" - + targetDataNode.getInternalEndPoint() + + targetNode.getInternalEndPoint() + "}" + e.getMessage(); LOGGER.error(errorMsg); diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/ConfigNodeAsyncRequestRPCHandler.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/ConfigNodeAsyncRequestRPCHandler.java new file mode 100644 index 0000000000000..4825629ee5591 --- /dev/null +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/ConfigNodeAsyncRequestRPCHandler.java @@ -0,0 +1,88 @@ +/* + * 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.iotdb.confignode.client.async.handlers.rpc; + +import org.apache.iotdb.common.rpc.thrift.TConfigNodeLocation; +import org.apache.iotdb.common.rpc.thrift.TSStatus; +import org.apache.iotdb.common.rpc.thrift.TTestConnectionResp; +import org.apache.iotdb.commons.client.request.AsyncRequestContext; +import org.apache.iotdb.commons.client.request.AsyncRequestRPCHandler; +import org.apache.iotdb.confignode.client.CnToCnNodeRequestType; + +import java.util.Map; +import java.util.concurrent.CountDownLatch; + +public abstract class ConfigNodeAsyncRequestRPCHandler + extends AsyncRequestRPCHandler { + + protected ConfigNodeAsyncRequestRPCHandler( + CnToCnNodeRequestType configNodeRequestType, + int requestId, + TConfigNodeLocation targetNode, + Map integerTConfigNodeLocationMap, + Map integerResponseMap, + CountDownLatch countDownLatch) { + super( + configNodeRequestType, + requestId, + targetNode, + integerTConfigNodeLocationMap, + integerResponseMap, + countDownLatch); + } + + @Override + protected String generateFormattedTargetLocation(TConfigNodeLocation configNodeLocation) { + return "{id=" + + targetNode.getConfigNodeId() + + ", internalEndPoint=" + + targetNode.getInternalEndPoint() + + "}"; + } + + public static ConfigNodeAsyncRequestRPCHandler buildHandler( + AsyncRequestContext context, + int requestId, + TConfigNodeLocation targetConfigNode) { + CnToCnNodeRequestType requestType = context.getRequestType(); + Map nodeLocationMap = context.getNodeLocationMap(); + Map responseMap = context.getResponseMap(); + CountDownLatch countDownLatch = context.getCountDownLatch(); + switch (requestType) { + case SUBMIT_TEST_CONNECTION_TASK: + return new SubmitTestConnectionTaskToConfigNodeRPCHandler( + requestType, + requestId, + targetConfigNode, + nodeLocationMap, + (Map) responseMap, + countDownLatch); + case TEST_CONNECTION: + default: + return new ConfigNodeTSStatusRPCHandler( + requestType, + requestId, + targetConfigNode, + nodeLocationMap, + (Map) responseMap, + countDownLatch); + } + } +} diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/ConfigNodeTSStatusRPCHandler.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/ConfigNodeTSStatusRPCHandler.java new file mode 100644 index 0000000000000..a28acb3496267 --- /dev/null +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/ConfigNodeTSStatusRPCHandler.java @@ -0,0 +1,95 @@ +/* + * 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.iotdb.confignode.client.async.handlers.rpc; + +import org.apache.iotdb.common.rpc.thrift.TConfigNodeLocation; +import org.apache.iotdb.common.rpc.thrift.TSStatus; +import org.apache.iotdb.confignode.client.CnToCnNodeRequestType; +import org.apache.iotdb.rpc.RpcUtils; +import org.apache.iotdb.rpc.TSStatusCode; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; +import java.util.concurrent.CountDownLatch; + +/** General RPC handler for TSStatus response type. */ +public class ConfigNodeTSStatusRPCHandler extends ConfigNodeAsyncRequestRPCHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(ConfigNodeTSStatusRPCHandler.class); + + public ConfigNodeTSStatusRPCHandler( + CnToCnNodeRequestType requestType, + int requestId, + TConfigNodeLocation targetConfigNode, + Map configNodeLocationMap, + Map responseMap, + CountDownLatch countDownLatch) { + super( + requestType, + requestId, + targetConfigNode, + configNodeLocationMap, + responseMap, + countDownLatch); + } + + @Override + public void onComplete(TSStatus response) { + // Put response + responseMap.put(requestId, response); + + if (response.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { + // Remove only if success + nodeLocationMap.remove(requestId); + LOGGER.info("Successfully {} on ConfigNode: {}", requestType, formattedTargetLocation); + } else { + LOGGER.error( + "Failed to {} on ConfigNode: {}, response: {}", + requestType, + formattedTargetLocation, + response); + } + + // Always CountDown + countDownLatch.countDown(); + } + + @Override + public void onError(Exception e) { + String errorMsg = + "Failed to " + + requestType + + " on ConfigNode: " + + formattedTargetLocation + + ", exception: " + + e.getMessage(); + LOGGER.error(errorMsg); + + responseMap.put( + requestId, + new TSStatus( + RpcUtils.getStatus(TSStatusCode.EXECUTE_STATEMENT_ERROR.getStatusCode(), errorMsg))); + + // Always CountDown + countDownLatch.countDown(); + } +} diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/CountPathsUsingTemplateRPCHandler.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/CountPathsUsingTemplateRPCHandler.java index 168208d86b976..f2ed0cc425c57 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/CountPathsUsingTemplateRPCHandler.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/CountPathsUsingTemplateRPCHandler.java @@ -21,7 +21,7 @@ import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; import org.apache.iotdb.common.rpc.thrift.TSStatus; -import org.apache.iotdb.confignode.client.DataNodeRequestType; +import org.apache.iotdb.confignode.client.CnToDnRequestType; import org.apache.iotdb.mpp.rpc.thrift.TCountPathsUsingTemplateResp; import org.apache.iotdb.rpc.RpcUtils; import org.apache.iotdb.rpc.TSStatusCode; @@ -33,13 +33,13 @@ import java.util.concurrent.CountDownLatch; public class CountPathsUsingTemplateRPCHandler - extends AbstractAsyncRPCHandler { + extends DataNodeAsyncRequestRPCHandler { private static final Logger LOGGER = LoggerFactory.getLogger(CountPathsUsingTemplateRPCHandler.class); public CountPathsUsingTemplateRPCHandler( - DataNodeRequestType requestType, + CnToDnRequestType requestType, int requestId, TDataNodeLocation targetDataNode, Map dataNodeLocationMap, @@ -53,15 +53,13 @@ public void onComplete(TCountPathsUsingTemplateResp response) { TSStatus tsStatus = response.getStatus(); responseMap.put(requestId, response); if (tsStatus.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { - dataNodeLocationMap.remove(requestId); - LOGGER.info("Successfully count paths using template on DataNode: {}", targetDataNode); + nodeLocationMap.remove(requestId); + LOGGER.info("Successfully count paths using template on DataNode: {}", targetNode); } else if (tsStatus.getCode() == TSStatusCode.MULTIPLE_ERROR.getStatusCode()) { - dataNodeLocationMap.remove(requestId); - LOGGER.error( - "Failed to count paths using template on DataNode {}, {}", targetDataNode, tsStatus); + nodeLocationMap.remove(requestId); + LOGGER.error("Failed to count paths using template on DataNode {}, {}", targetNode, tsStatus); } else { - LOGGER.error( - "Failed to count paths using template on DataNode {}, {}", targetDataNode, tsStatus); + LOGGER.error("Failed to count paths using template on DataNode {}, {}", targetNode, tsStatus); } countDownLatch.countDown(); } @@ -70,9 +68,9 @@ public void onComplete(TCountPathsUsingTemplateResp response) { public void onError(Exception e) { String errorMsg = "Count paths using template error on DataNode: {id=" - + targetDataNode.getDataNodeId() + + targetNode.getDataNodeId() + ", internalEndPoint=" - + targetDataNode.getInternalEndPoint() + + targetNode.getInternalEndPoint() + "}" + e.getMessage(); LOGGER.error(errorMsg); diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/AsyncClientHandler.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/DataNodeAsyncRequestRPCHandler.java similarity index 58% rename from iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/AsyncClientHandler.java rename to iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/DataNodeAsyncRequestRPCHandler.java index 1d5183fed5d59..5b26f4800b1e7 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/AsyncClientHandler.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/DataNodeAsyncRequestRPCHandler.java @@ -17,20 +17,14 @@ * under the License. */ -package org.apache.iotdb.confignode.client.async.handlers; +package org.apache.iotdb.confignode.client.async.handlers.rpc; import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; import org.apache.iotdb.common.rpc.thrift.TSStatus; -import org.apache.iotdb.confignode.client.DataNodeRequestType; -import org.apache.iotdb.confignode.client.async.handlers.rpc.AbstractAsyncRPCHandler; -import org.apache.iotdb.confignode.client.async.handlers.rpc.AsyncTSStatusRPCHandler; -import org.apache.iotdb.confignode.client.async.handlers.rpc.CheckTimeSeriesExistenceRPCHandler; -import org.apache.iotdb.confignode.client.async.handlers.rpc.CountPathsUsingTemplateRPCHandler; -import org.apache.iotdb.confignode.client.async.handlers.rpc.FetchSchemaBlackListRPCHandler; -import org.apache.iotdb.confignode.client.async.handlers.rpc.PipeHeartbeatRPCHandler; -import org.apache.iotdb.confignode.client.async.handlers.rpc.PipePushMetaRPCHandler; -import org.apache.iotdb.confignode.client.async.handlers.rpc.SchemaUpdateRPCHandler; -import org.apache.iotdb.confignode.client.async.handlers.rpc.TransferLeaderRPCHandler; +import org.apache.iotdb.common.rpc.thrift.TTestConnectionResp; +import org.apache.iotdb.commons.client.request.AsyncRequestContext; +import org.apache.iotdb.commons.client.request.AsyncRequestRPCHandler; +import org.apache.iotdb.confignode.client.CnToDnRequestType; import org.apache.iotdb.confignode.client.async.handlers.rpc.subscription.CheckSchemaRegionUsingTemplateRPCHandler; import org.apache.iotdb.confignode.client.async.handlers.rpc.subscription.ConsumerGroupPushMetaRPCHandler; import org.apache.iotdb.confignode.client.async.handlers.rpc.subscription.TopicPushMetaRPCHandler; @@ -44,129 +38,45 @@ import org.apache.iotdb.mpp.rpc.thrift.TPushTopicMetaResp; import org.apache.iotdb.mpp.rpc.thrift.TRegionLeaderChangeResp; -import java.util.ArrayList; -import java.util.List; import java.util.Map; -import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.CountDownLatch; -/** - * Asynchronous Client handler. - * - * @param ClassName of RPC request - * @param ClassName of RPC response - */ -public class AsyncClientHandler { - - // Type of RPC request - protected final DataNodeRequestType requestType; - - /** - * Map key: The indices of asynchronous RPC requests. - * - *

Map value: The corresponding RPC request - */ - private final Map requestMap; - - /** - * Map key: The indices of asynchronous RPC requests. - * - *

Map value: The target DataNodes of corresponding indices - * - *

All kinds of AsyncHandler will remove its targetDataNode from the dataNodeLocationMap only - * if its corresponding RPC request success - */ - private final Map dataNodeLocationMap; - - /** - * Map key: The indices(targetDataNode's ID) of asynchronous RPC requests. - * - *

Map value: The response of corresponding indices - * - *

All kinds of AsyncHandler will add response to the responseMap after its corresponding RPC - * request finished - */ - private final Map responseMap; - - private CountDownLatch countDownLatch; - - /** Custom constructor. */ - public AsyncClientHandler(DataNodeRequestType requestType) { - this.requestType = requestType; - this.requestMap = new ConcurrentHashMap<>(); - this.dataNodeLocationMap = new ConcurrentHashMap<>(); - this.responseMap = new ConcurrentHashMap<>(); - } - - public void putRequest(int requestId, Q request) { - requestMap.put(requestId, request); - } - - public void putDataNodeLocation(int requestId, TDataNodeLocation dataNodeLocation) { - dataNodeLocationMap.put(requestId, dataNodeLocation); - } - - /** Constructor for null requests. */ - public AsyncClientHandler( - DataNodeRequestType requestType, Map dataNodeLocationMap) { - this.requestType = requestType; - this.dataNodeLocationMap = dataNodeLocationMap; - - this.requestMap = new ConcurrentHashMap<>(); - this.responseMap = new ConcurrentHashMap<>(); - } - - /** Constructor for unique request. */ - public AsyncClientHandler( - DataNodeRequestType requestType, - Q request, - Map dataNodeLocationMap) { - this.requestType = requestType; - this.dataNodeLocationMap = dataNodeLocationMap; - - this.requestMap = new ConcurrentHashMap<>(); - this.dataNodeLocationMap - .keySet() - .forEach(dataNodeId -> this.requestMap.put(dataNodeId, request)); - - this.responseMap = new ConcurrentHashMap<>(); +public abstract class DataNodeAsyncRequestRPCHandler + extends AsyncRequestRPCHandler { + + protected DataNodeAsyncRequestRPCHandler( + CnToDnRequestType requestType, + int requestId, + TDataNodeLocation targetNode, + Map dataNodeLocationMap, + Map integerResponseMap, + CountDownLatch countDownLatch) { + super( + requestType, + requestId, + targetNode, + dataNodeLocationMap, + integerResponseMap, + countDownLatch); } - public DataNodeRequestType getRequestType() { - return requestType; + @Override + protected String generateFormattedTargetLocation(TDataNodeLocation dataNodeLocation) { + return "{id=" + + targetNode.getDataNodeId() + + ", internalEndPoint=" + + targetNode.getInternalEndPoint() + + "}"; } - public List getRequestIndices() { - return new ArrayList<>(dataNodeLocationMap.keySet()); - } - - public Q getRequest(int requestId) { - return requestMap.get(requestId); - } - - public TDataNodeLocation getDataNodeLocation(int requestId) { - return dataNodeLocationMap.get(requestId); - } - - public List getResponseList() { - return new ArrayList<>(responseMap.values()); - } - - public Map getResponseMap() { - return responseMap; - } - - /** Always reset CountDownLatch before retry. */ - public void resetCountDownLatch() { - countDownLatch = new CountDownLatch(dataNodeLocationMap.size()); - } - - public CountDownLatch getCountDownLatch() { - return countDownLatch; - } - - public AbstractAsyncRPCHandler createAsyncRPCHandler( - int requestId, TDataNodeLocation targetDataNode) { + public static DataNodeAsyncRequestRPCHandler buildHandler( + AsyncRequestContext context, + int requestId, + TDataNodeLocation targetDataNode) { + CnToDnRequestType requestType = context.getRequestType(); + Map dataNodeLocationMap = context.getNodeLocationMap(); + Map responseMap = context.getResponseMap(); + CountDownLatch countDownLatch = context.getCountDownLatch(); switch (requestType) { case CONSTRUCT_SCHEMA_BLACK_LIST: case ROLLBACK_SCHEMA_BLACK_LIST: @@ -263,6 +173,14 @@ public AbstractAsyncRPCHandler createAsyncRPCHandler( dataNodeLocationMap, (Map) responseMap, countDownLatch); + case SUBMIT_TEST_CONNECTION_TASK: + return new SubmitTestConnectionTaskRPCHandler( + requestType, + requestId, + targetDataNode, + dataNodeLocationMap, + (Map) responseMap, + countDownLatch); case SET_TTL: case CREATE_DATA_REGION: case CREATE_SCHEMA_REGION: @@ -287,8 +205,9 @@ public AbstractAsyncRPCHandler createAsyncRPCHandler( case UPDATE_TABLE: case KILL_QUERY_INSTANCE: case RESET_PEER_LIST: + case TEST_CONNECTION: default: - return new AsyncTSStatusRPCHandler( + return new DataNodeTSStatusRPCHandler( requestType, requestId, targetDataNode, diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/DataNodeTSStatusRPCHandler.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/DataNodeTSStatusRPCHandler.java new file mode 100644 index 0000000000000..19d451eb671fb --- /dev/null +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/DataNodeTSStatusRPCHandler.java @@ -0,0 +1,89 @@ +/* + * 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.iotdb.confignode.client.async.handlers.rpc; + +import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; +import org.apache.iotdb.common.rpc.thrift.TSStatus; +import org.apache.iotdb.confignode.client.CnToDnRequestType; +import org.apache.iotdb.rpc.RpcUtils; +import org.apache.iotdb.rpc.TSStatusCode; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; +import java.util.concurrent.CountDownLatch; + +/** General RPC handler for TSStatus response type. */ +public class DataNodeTSStatusRPCHandler extends DataNodeAsyncRequestRPCHandler { + + private static final Logger LOGGER = LoggerFactory.getLogger(DataNodeTSStatusRPCHandler.class); + + public DataNodeTSStatusRPCHandler( + CnToDnRequestType requestType, + int requestId, + TDataNodeLocation targetDataNode, + Map dataNodeLocationMap, + Map responseMap, + CountDownLatch countDownLatch) { + super(requestType, requestId, targetDataNode, dataNodeLocationMap, responseMap, countDownLatch); + } + + @Override + public void onComplete(TSStatus response) { + // Put response + responseMap.put(requestId, response); + + if (response.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { + // Remove only if success + nodeLocationMap.remove(requestId); + LOGGER.info("Successfully {} on DataNode: {}", requestType, formattedTargetLocation); + } else { + LOGGER.error( + "Failed to {} on DataNode: {}, response: {}", + requestType, + formattedTargetLocation, + response); + } + + // Always CountDown + countDownLatch.countDown(); + } + + @Override + public void onError(Exception e) { + String errorMsg = + "Failed to " + + requestType + + " on DataNode: " + + formattedTargetLocation + + ", exception: " + + e.getMessage(); + LOGGER.error(errorMsg); + + responseMap.put( + requestId, + new TSStatus( + RpcUtils.getStatus(TSStatusCode.EXECUTE_STATEMENT_ERROR.getStatusCode(), errorMsg))); + + // Always CountDown + countDownLatch.countDown(); + } +} diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/FetchSchemaBlackListRPCHandler.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/FetchSchemaBlackListRPCHandler.java index e73e41322065f..45c659298ca30 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/FetchSchemaBlackListRPCHandler.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/FetchSchemaBlackListRPCHandler.java @@ -21,7 +21,7 @@ import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; import org.apache.iotdb.common.rpc.thrift.TSStatus; -import org.apache.iotdb.confignode.client.DataNodeRequestType; +import org.apache.iotdb.confignode.client.CnToDnRequestType; import org.apache.iotdb.mpp.rpc.thrift.TFetchSchemaBlackListResp; import org.apache.iotdb.rpc.RpcUtils; import org.apache.iotdb.rpc.TSStatusCode; @@ -33,13 +33,13 @@ import java.util.concurrent.CountDownLatch; public class FetchSchemaBlackListRPCHandler - extends AbstractAsyncRPCHandler { + extends DataNodeAsyncRequestRPCHandler { private static final Logger LOGGER = LoggerFactory.getLogger(FetchSchemaBlackListRPCHandler.class); public FetchSchemaBlackListRPCHandler( - DataNodeRequestType requestType, + CnToDnRequestType requestType, int requestId, TDataNodeLocation targetDataNode, Map dataNodeLocationMap, @@ -53,15 +53,15 @@ public void onComplete(TFetchSchemaBlackListResp tFetchSchemaBlackListResp) { TSStatus tsStatus = tFetchSchemaBlackListResp.getStatus(); responseMap.put(requestId, tFetchSchemaBlackListResp); if (tsStatus.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { - dataNodeLocationMap.remove(requestId); - LOGGER.info("Successfully fetch schemaengine black list on DataNode: {}", targetDataNode); + nodeLocationMap.remove(requestId); + LOGGER.info("Successfully fetch schemaengine black list on DataNode: {}", targetNode); } else if (tsStatus.getCode() == TSStatusCode.MULTIPLE_ERROR.getStatusCode()) { - dataNodeLocationMap.remove(requestId); + nodeLocationMap.remove(requestId); LOGGER.error( - "Failed to fetch schemaengine black list on DataNode {}, {}", targetDataNode, tsStatus); + "Failed to fetch schemaengine black list on DataNode {}, {}", targetNode, tsStatus); } else { LOGGER.error( - "Failed to fetch schemaengine black list on DataNode {}, {}", targetDataNode, tsStatus); + "Failed to fetch schemaengine black list on DataNode {}, {}", targetNode, tsStatus); } countDownLatch.countDown(); } @@ -70,9 +70,9 @@ public void onComplete(TFetchSchemaBlackListResp tFetchSchemaBlackListResp) { public void onError(Exception e) { String errorMsg = "Fetch schemaengine black list error on DataNode: {id=" - + targetDataNode.getDataNodeId() + + targetNode.getDataNodeId() + ", internalEndPoint=" - + targetDataNode.getInternalEndPoint() + + targetNode.getInternalEndPoint() + "}" + e.getMessage(); LOGGER.error(errorMsg); diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/PipeHeartbeatRPCHandler.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/PipeHeartbeatRPCHandler.java index ff235a38bd084..ec4968cfa06dd 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/PipeHeartbeatRPCHandler.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/PipeHeartbeatRPCHandler.java @@ -20,7 +20,7 @@ package org.apache.iotdb.confignode.client.async.handlers.rpc; import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; -import org.apache.iotdb.confignode.client.DataNodeRequestType; +import org.apache.iotdb.confignode.client.CnToDnRequestType; import org.apache.iotdb.mpp.rpc.thrift.TPipeHeartbeatResp; import org.slf4j.Logger; @@ -29,12 +29,12 @@ import java.util.Map; import java.util.concurrent.CountDownLatch; -public class PipeHeartbeatRPCHandler extends AbstractAsyncRPCHandler { +public class PipeHeartbeatRPCHandler extends DataNodeAsyncRequestRPCHandler { private static final Logger LOGGER = LoggerFactory.getLogger(PipeHeartbeatRPCHandler.class); public PipeHeartbeatRPCHandler( - DataNodeRequestType requestType, + CnToDnRequestType requestType, int requestId, TDataNodeLocation targetDataNode, Map dataNodeLocationMap, @@ -47,7 +47,7 @@ public PipeHeartbeatRPCHandler( public void onComplete(TPipeHeartbeatResp response) { // Put response responseMap.put(requestId, response); - dataNodeLocationMap.remove(requestId); + nodeLocationMap.remove(requestId); LOGGER.info("Successfully {} on DataNode: {}", requestType, formattedTargetLocation); // Always CountDown diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/PipePushMetaRPCHandler.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/PipePushMetaRPCHandler.java index 774e914de367e..3517bbeb93ea3 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/PipePushMetaRPCHandler.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/PipePushMetaRPCHandler.java @@ -20,7 +20,7 @@ package org.apache.iotdb.confignode.client.async.handlers.rpc; import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; -import org.apache.iotdb.confignode.client.DataNodeRequestType; +import org.apache.iotdb.confignode.client.CnToDnRequestType; import org.apache.iotdb.mpp.rpc.thrift.TPushPipeMetaResp; import org.apache.iotdb.rpc.RpcUtils; import org.apache.iotdb.rpc.TSStatusCode; @@ -31,11 +31,11 @@ import java.util.Map; import java.util.concurrent.CountDownLatch; -public class PipePushMetaRPCHandler extends AbstractAsyncRPCHandler { +public class PipePushMetaRPCHandler extends DataNodeAsyncRequestRPCHandler { private static final Logger LOGGER = LoggerFactory.getLogger(PipePushMetaRPCHandler.class); public PipePushMetaRPCHandler( - DataNodeRequestType requestType, + CnToDnRequestType requestType, int requestId, TDataNodeLocation targetDataNode, Map dataNodeLocationMap, @@ -60,7 +60,7 @@ public void onComplete(TPushPipeMetaResp response) { } // Always remove to avoid retrying - dataNodeLocationMap.remove(requestId); + nodeLocationMap.remove(requestId); // Always CountDown countDownLatch.countDown(); diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/SchemaUpdateRPCHandler.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/SchemaUpdateRPCHandler.java index 3980e6e0c1b52..db8458a948ce3 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/SchemaUpdateRPCHandler.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/SchemaUpdateRPCHandler.java @@ -21,7 +21,7 @@ import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; import org.apache.iotdb.common.rpc.thrift.TSStatus; -import org.apache.iotdb.confignode.client.DataNodeRequestType; +import org.apache.iotdb.confignode.client.CnToDnRequestType; import org.apache.iotdb.rpc.RpcUtils; import org.apache.iotdb.rpc.TSStatusCode; @@ -31,12 +31,12 @@ import java.util.Map; import java.util.concurrent.CountDownLatch; -public class SchemaUpdateRPCHandler extends AsyncTSStatusRPCHandler { +public class SchemaUpdateRPCHandler extends DataNodeTSStatusRPCHandler { private static final Logger LOGGER = LoggerFactory.getLogger(SchemaUpdateRPCHandler.class); public SchemaUpdateRPCHandler( - DataNodeRequestType requestType, + CnToDnRequestType requestType, int requestId, TDataNodeLocation targetDataNode, Map dataNodeLocationMap, @@ -50,10 +50,10 @@ public void onComplete(TSStatus tsStatus) { responseMap.put(requestId, tsStatus); LOGGER.info("{} for {} receives: {}", requestType, requestId, tsStatus); if (tsStatus.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { - dataNodeLocationMap.remove(requestId); + nodeLocationMap.remove(requestId); LOGGER.info("Successfully {} on DataNode: {}", requestType, formattedTargetLocation); } else if (tsStatus.getCode() == TSStatusCode.MULTIPLE_ERROR.getStatusCode()) { - dataNodeLocationMap.remove(requestId); + nodeLocationMap.remove(requestId); LOGGER.warn( "Failed to {} on DataNode {}, {}", requestType, formattedTargetLocation, tsStatus); } else { @@ -68,9 +68,9 @@ public void onError(Exception e) { String errorMsg = requestType + " error on DataNode: {id=" - + targetDataNode.getDataNodeId() + + targetNode.getDataNodeId() + ", internalEndPoint=" - + targetDataNode.getInternalEndPoint() + + targetNode.getInternalEndPoint() + "}" + e.getMessage(); LOGGER.warn(errorMsg); diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/SubmitTestConnectionTaskRPCHandler.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/SubmitTestConnectionTaskRPCHandler.java new file mode 100644 index 0000000000000..4abf0a0eca114 --- /dev/null +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/SubmitTestConnectionTaskRPCHandler.java @@ -0,0 +1,68 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.confignode.client.async.handlers.rpc; + +import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; +import org.apache.iotdb.common.rpc.thrift.TSStatus; +import org.apache.iotdb.common.rpc.thrift.TTestConnectionResp; +import org.apache.iotdb.confignode.client.CnToDnRequestType; +import org.apache.iotdb.rpc.TSStatusCode; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; +import java.util.concurrent.CountDownLatch; + +public class SubmitTestConnectionTaskRPCHandler + extends DataNodeAsyncRequestRPCHandler { + + private static final Logger LOGGER = + LoggerFactory.getLogger(SubmitTestConnectionTaskRPCHandler.class); + + public SubmitTestConnectionTaskRPCHandler( + CnToDnRequestType requestType, + int requestId, + TDataNodeLocation targetDataNode, + Map dataNodeLocationMap, + Map responseMap, + CountDownLatch countDownLatch) { + super(requestType, requestId, targetDataNode, dataNodeLocationMap, responseMap, countDownLatch); + } + + @Override + public void onComplete(TTestConnectionResp resp) { + responseMap.put(requestId, resp); + nodeLocationMap.remove(requestId); + countDownLatch.countDown(); + } + + @Override + public void onError(Exception e) { + responseMap.put( + requestId, + new TTestConnectionResp() + .setStatus( + new TSStatus(TSStatusCode.CAN_NOT_CONNECT_DATANODE.getStatusCode()) + .setMessage(e.getMessage()))); + nodeLocationMap.remove(requestId); + countDownLatch.countDown(); + } +} diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/SubmitTestConnectionTaskToConfigNodeRPCHandler.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/SubmitTestConnectionTaskToConfigNodeRPCHandler.java new file mode 100644 index 0000000000000..d26984fd0a70d --- /dev/null +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/SubmitTestConnectionTaskToConfigNodeRPCHandler.java @@ -0,0 +1,74 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.confignode.client.async.handlers.rpc; + +import org.apache.iotdb.common.rpc.thrift.TConfigNodeLocation; +import org.apache.iotdb.common.rpc.thrift.TSStatus; +import org.apache.iotdb.common.rpc.thrift.TTestConnectionResp; +import org.apache.iotdb.confignode.client.CnToCnNodeRequestType; +import org.apache.iotdb.rpc.TSStatusCode; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; +import java.util.concurrent.CountDownLatch; + +public class SubmitTestConnectionTaskToConfigNodeRPCHandler + extends ConfigNodeAsyncRequestRPCHandler { + + private static final Logger LOGGER = + LoggerFactory.getLogger(SubmitTestConnectionTaskToConfigNodeRPCHandler.class); + + public SubmitTestConnectionTaskToConfigNodeRPCHandler( + CnToCnNodeRequestType requestType, + int requestId, + TConfigNodeLocation targetConfigNode, + Map configNodeLocationMap, + Map responseMap, + CountDownLatch countDownLatch) { + super( + requestType, + requestId, + targetConfigNode, + configNodeLocationMap, + responseMap, + countDownLatch); + } + + @Override + public void onComplete(TTestConnectionResp resp) { + responseMap.put(requestId, resp); + nodeLocationMap.remove(requestId); + countDownLatch.countDown(); + } + + @Override + public void onError(Exception e) { + responseMap.put( + requestId, + new TTestConnectionResp() + .setStatus( + new TSStatus(TSStatusCode.CAN_NOT_CONNECT_CONFIGNODE.getStatusCode()) + .setMessage(e.getMessage()))); + nodeLocationMap.remove(requestId); + countDownLatch.countDown(); + } +} diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/TransferLeaderRPCHandler.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/TransferLeaderRPCHandler.java index d5107e315cf19..352cc0694e2bf 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/TransferLeaderRPCHandler.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/TransferLeaderRPCHandler.java @@ -20,7 +20,7 @@ package org.apache.iotdb.confignode.client.async.handlers.rpc; import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; -import org.apache.iotdb.confignode.client.DataNodeRequestType; +import org.apache.iotdb.confignode.client.CnToDnRequestType; import org.apache.iotdb.mpp.rpc.thrift.TRegionLeaderChangeResp; import org.apache.iotdb.rpc.RpcUtils; import org.apache.iotdb.rpc.TSStatusCode; @@ -31,12 +31,13 @@ import java.util.Map; import java.util.concurrent.CountDownLatch; -public class TransferLeaderRPCHandler extends AbstractAsyncRPCHandler { +public class TransferLeaderRPCHandler + extends DataNodeAsyncRequestRPCHandler { private static final Logger LOGGER = LoggerFactory.getLogger(TransferLeaderRPCHandler.class); public TransferLeaderRPCHandler( - DataNodeRequestType requestType, + CnToDnRequestType requestType, int requestId, TDataNodeLocation targetDataNode, Map dataNodeLocationMap, @@ -52,7 +53,7 @@ public void onComplete(TRegionLeaderChangeResp response) { if (response.getStatus().getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { // Remove only if success - dataNodeLocationMap.remove(requestId); + nodeLocationMap.remove(requestId); LOGGER.info("Successfully {} on DataNode: {}", requestType, formattedTargetLocation); } else { LOGGER.error( diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/subscription/CheckSchemaRegionUsingTemplateRPCHandler.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/subscription/CheckSchemaRegionUsingTemplateRPCHandler.java index ad69516299219..14898dcdc6c9c 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/subscription/CheckSchemaRegionUsingTemplateRPCHandler.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/subscription/CheckSchemaRegionUsingTemplateRPCHandler.java @@ -21,8 +21,8 @@ import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; import org.apache.iotdb.common.rpc.thrift.TSStatus; -import org.apache.iotdb.confignode.client.DataNodeRequestType; -import org.apache.iotdb.confignode.client.async.handlers.rpc.AbstractAsyncRPCHandler; +import org.apache.iotdb.confignode.client.CnToDnRequestType; +import org.apache.iotdb.confignode.client.async.handlers.rpc.DataNodeAsyncRequestRPCHandler; import org.apache.iotdb.mpp.rpc.thrift.TCheckSchemaRegionUsingTemplateResp; import org.apache.iotdb.rpc.RpcUtils; import org.apache.iotdb.rpc.TSStatusCode; @@ -34,13 +34,13 @@ import java.util.concurrent.CountDownLatch; public class CheckSchemaRegionUsingTemplateRPCHandler - extends AbstractAsyncRPCHandler { + extends DataNodeAsyncRequestRPCHandler { private static final Logger LOGGER = LoggerFactory.getLogger(CheckSchemaRegionUsingTemplateRPCHandler.class); public CheckSchemaRegionUsingTemplateRPCHandler( - DataNodeRequestType requestType, + CnToDnRequestType requestType, int requestId, TDataNodeLocation targetDataNode, Map dataNodeLocationMap, @@ -54,20 +54,15 @@ public void onComplete(TCheckSchemaRegionUsingTemplateResp response) { TSStatus tsStatus = response.getStatus(); responseMap.put(requestId, response); if (tsStatus.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { - dataNodeLocationMap.remove(requestId); - LOGGER.info( - "Successfully check schema region using template on DataNode: {}", targetDataNode); + nodeLocationMap.remove(requestId); + LOGGER.info("Successfully check schema region using template on DataNode: {}", targetNode); } else if (tsStatus.getCode() == TSStatusCode.MULTIPLE_ERROR.getStatusCode()) { - dataNodeLocationMap.remove(requestId); + nodeLocationMap.remove(requestId); LOGGER.error( - "Failed to check schema region using template on DataNode {}, {}", - targetDataNode, - tsStatus); + "Failed to check schema region using template on DataNode {}, {}", targetNode, tsStatus); } else { LOGGER.error( - "Failed to check schema region using template on DataNode {}, {}", - targetDataNode, - tsStatus); + "Failed to check schema region using template on DataNode {}, {}", targetNode, tsStatus); } countDownLatch.countDown(); } @@ -76,9 +71,9 @@ public void onComplete(TCheckSchemaRegionUsingTemplateResp response) { public void onError(Exception e) { String errorMsg = "Count paths using template error on DataNode: {id=" - + targetDataNode.getDataNodeId() + + targetNode.getDataNodeId() + ", internalEndPoint=" - + targetDataNode.getInternalEndPoint() + + targetNode.getInternalEndPoint() + "}" + e.getMessage(); LOGGER.error(errorMsg); diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/subscription/ConsumerGroupPushMetaRPCHandler.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/subscription/ConsumerGroupPushMetaRPCHandler.java index 52f5063101f2d..ee3c11eeb427b 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/subscription/ConsumerGroupPushMetaRPCHandler.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/subscription/ConsumerGroupPushMetaRPCHandler.java @@ -20,8 +20,8 @@ package org.apache.iotdb.confignode.client.async.handlers.rpc.subscription; import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; -import org.apache.iotdb.confignode.client.DataNodeRequestType; -import org.apache.iotdb.confignode.client.async.handlers.rpc.AbstractAsyncRPCHandler; +import org.apache.iotdb.confignode.client.CnToDnRequestType; +import org.apache.iotdb.confignode.client.async.handlers.rpc.DataNodeAsyncRequestRPCHandler; import org.apache.iotdb.mpp.rpc.thrift.TPushConsumerGroupMetaResp; import org.apache.iotdb.rpc.RpcUtils; import org.apache.iotdb.rpc.TSStatusCode; @@ -33,12 +33,12 @@ import java.util.concurrent.CountDownLatch; public class ConsumerGroupPushMetaRPCHandler - extends AbstractAsyncRPCHandler { + extends DataNodeAsyncRequestRPCHandler { private static final Logger LOGGER = LoggerFactory.getLogger(ConsumerGroupPushMetaRPCHandler.class); public ConsumerGroupPushMetaRPCHandler( - DataNodeRequestType requestType, + CnToDnRequestType requestType, int requestId, TDataNodeLocation targetDataNode, Map dataNodeLocationMap, @@ -63,7 +63,7 @@ public void onComplete(TPushConsumerGroupMetaResp response) { } // Always remove to avoid retrying - dataNodeLocationMap.remove(requestId); + nodeLocationMap.remove(requestId); // Always CountDown countDownLatch.countDown(); diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/subscription/TopicPushMetaRPCHandler.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/subscription/TopicPushMetaRPCHandler.java index 39cb9cd23e975..cf8451feaacad 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/subscription/TopicPushMetaRPCHandler.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/subscription/TopicPushMetaRPCHandler.java @@ -20,8 +20,8 @@ package org.apache.iotdb.confignode.client.async.handlers.rpc.subscription; import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; -import org.apache.iotdb.confignode.client.DataNodeRequestType; -import org.apache.iotdb.confignode.client.async.handlers.rpc.AbstractAsyncRPCHandler; +import org.apache.iotdb.confignode.client.CnToDnRequestType; +import org.apache.iotdb.confignode.client.async.handlers.rpc.DataNodeAsyncRequestRPCHandler; import org.apache.iotdb.mpp.rpc.thrift.TPushTopicMetaResp; import org.apache.iotdb.rpc.RpcUtils; import org.apache.iotdb.rpc.TSStatusCode; @@ -32,12 +32,12 @@ import java.util.Map; import java.util.concurrent.CountDownLatch; -public class TopicPushMetaRPCHandler extends AbstractAsyncRPCHandler { +public class TopicPushMetaRPCHandler extends DataNodeAsyncRequestRPCHandler { private static final Logger LOGGER = LoggerFactory.getLogger(TopicPushMetaRPCHandler.class); public TopicPushMetaRPCHandler( - DataNodeRequestType requestType, + CnToDnRequestType requestType, int requestId, TDataNodeLocation targetDataNode, Map dataNodeLocationMap, @@ -62,7 +62,7 @@ public void onComplete(TPushTopicMetaResp response) { } // Always remove to avoid retrying - dataNodeLocationMap.remove(requestId); + nodeLocationMap.remove(requestId); // Always CountDown countDownLatch.countDown(); diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/sync/SyncConfigNodeClientPool.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/sync/SyncConfigNodeClientPool.java index ab85a9badcb9e..cc26be000a8eb 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/sync/SyncConfigNodeClientPool.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/sync/SyncConfigNodeClientPool.java @@ -21,13 +21,14 @@ import org.apache.iotdb.common.rpc.thrift.TConfigNodeLocation; import org.apache.iotdb.common.rpc.thrift.TEndPoint; +import org.apache.iotdb.common.rpc.thrift.TNodeLocations; import org.apache.iotdb.common.rpc.thrift.TSStatus; import org.apache.iotdb.common.rpc.thrift.TSetConfigurationReq; import org.apache.iotdb.commons.client.ClientPoolFactory; import org.apache.iotdb.commons.client.IClientManager; import org.apache.iotdb.commons.client.exception.ClientManagerException; import org.apache.iotdb.commons.client.sync.SyncConfigNodeIServiceClient; -import org.apache.iotdb.confignode.client.ConfigNodeRequestType; +import org.apache.iotdb.confignode.client.CnToCnNodeRequestType; import org.apache.iotdb.confignode.rpc.thrift.TAddConsensusGroupReq; import org.apache.iotdb.confignode.rpc.thrift.TConfigNodeRegisterReq; import org.apache.iotdb.rpc.RpcUtils; @@ -66,7 +67,7 @@ private void updateConfigNodeLeader(TSStatus status) { } public Object sendSyncRequestToConfigNodeWithRetry( - TEndPoint endPoint, Object req, ConfigNodeRequestType requestType) { + TEndPoint endPoint, Object req, CnToCnNodeRequestType requestType) { Throwable lastException = null; for (int retry = 0; retry < MAX_RETRY_NUM; retry++) { @@ -91,6 +92,12 @@ public Object sendSyncRequestToConfigNodeWithRetry( return client.stopConfigNode((TConfigNodeLocation) req); case SET_CONFIGURATION: return client.setConfiguration((TSetConfigurationReq) req); + case SHOW_CONFIGURATION: + return client.showConfiguration((int) req); + case SUBMIT_TEST_CONNECTION_TASK: + return client.submitTestConnectionTask((TNodeLocations) req); + case TEST_CONNECTION: + return client.testConnectionEmptyRPC(); default: return RpcUtils.getStatus( TSStatusCode.EXECUTE_STATEMENT_ERROR, "Unknown request type: " + requestType); @@ -145,7 +152,6 @@ private void doRetryWait(int retryNum) { } } - // TODO: Is the ClientPool must be a singleton? private static class SyncConfigNodeClientPoolHolder { private static final SyncConfigNodeClientPool INSTANCE = new SyncConfigNodeClientPool(); diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/sync/SyncDataNodeClientPool.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/sync/SyncDataNodeClientPool.java index 86afa20d6acc2..be366b5772bc4 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/sync/SyncDataNodeClientPool.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/sync/SyncDataNodeClientPool.java @@ -27,7 +27,7 @@ import org.apache.iotdb.commons.client.IClientManager; import org.apache.iotdb.commons.client.exception.ClientManagerException; import org.apache.iotdb.commons.client.sync.SyncDataNodeInternalServiceClient; -import org.apache.iotdb.confignode.client.DataNodeRequestType; +import org.apache.iotdb.confignode.client.CnToDnRequestType; import org.apache.iotdb.mpp.rpc.thrift.TCreateDataRegionReq; import org.apache.iotdb.mpp.rpc.thrift.TCreatePeerReq; import org.apache.iotdb.mpp.rpc.thrift.TCreateSchemaRegionReq; @@ -66,7 +66,7 @@ private SyncDataNodeClientPool() { } public Object sendSyncRequestToDataNodeWithRetry( - TEndPoint endPoint, Object req, DataNodeRequestType requestType) { + TEndPoint endPoint, Object req, CnToDnRequestType requestType) { Throwable lastException = new TException(); for (int retry = 0; retry < DEFAULT_RETRY_NUM; retry++) { try (SyncDataNodeInternalServiceClient client = clientManager.borrowClient(endPoint)) { @@ -85,7 +85,7 @@ public Object sendSyncRequestToDataNodeWithRetry( } public Object sendSyncRequestToDataNodeWithGivenRetry( - TEndPoint endPoint, Object req, DataNodeRequestType requestType, int retryNum) { + TEndPoint endPoint, Object req, CnToDnRequestType requestType, int retryNum) { Throwable lastException = new TException(); for (int retry = 0; retry < retryNum; retry++) { try (SyncDataNodeInternalServiceClient client = clientManager.borrowClient(endPoint)) { @@ -104,7 +104,7 @@ public Object sendSyncRequestToDataNodeWithGivenRetry( } private Object executeSyncRequest( - DataNodeRequestType requestType, SyncDataNodeInternalServiceClient client, Object req) + CnToDnRequestType requestType, SyncDataNodeInternalServiceClient client, Object req) throws TException { switch (requestType) { case INVALIDATE_PARTITION_CACHE: @@ -192,7 +192,6 @@ public TRegionLeaderChangeResp changeRegionLeader( return new TRegionLeaderChangeResp(status, -1L); } - // TODO: Is the ClientPool must be a singleton? private static class ClientPoolHolder { private static final SyncDataNodeClientPool INSTANCE = new SyncDataNodeClientPool(); diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConfig.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConfig.java index 99017b4f10c8d..603892e368114 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConfig.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConfig.java @@ -19,6 +19,7 @@ package org.apache.iotdb.confignode.conf; +import org.apache.iotdb.common.rpc.thrift.TConfigNodeLocation; import org.apache.iotdb.common.rpc.thrift.TEndPoint; import org.apache.iotdb.commons.client.property.ClientPoolProperty.DefaultProperty; import org.apache.iotdb.commons.conf.IoTDBConstant; @@ -1196,4 +1197,18 @@ public void setDataRegionRatisPeriodicSnapshotInterval( long dataRegionRatisPeriodicSnapshotInterval) { this.dataRegionRatisPeriodicSnapshotInterval = dataRegionRatisPeriodicSnapshotInterval; } + + public TConfigNodeLocation generateLocalConfigNodeLocationWithSpecifiedNodeId(int configNodeId) { + return new TConfigNodeLocation( + configNodeId, + new TEndPoint(getInternalAddress(), getInternalPort()), + new TEndPoint(getInternalAddress(), getConsensusPort())); + } + + public TConfigNodeLocation generateLocalConfigNodeLocation() { + return new TConfigNodeLocation( + getConfigNodeId(), + new TEndPoint(getInternalAddress(), getInternalPort()), + new TEndPoint(getInternalAddress(), getConsensusPort())); + } } diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeRemoveCheck.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeRemoveCheck.java index bdbbdc43c7a96..9c4c480b02cea 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeRemoveCheck.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeRemoveCheck.java @@ -25,7 +25,7 @@ import org.apache.iotdb.commons.conf.IoTDBConstant; import org.apache.iotdb.commons.exception.BadNodeUrlException; import org.apache.iotdb.commons.utils.NodeUrlUtils; -import org.apache.iotdb.confignode.client.ConfigNodeRequestType; +import org.apache.iotdb.confignode.client.CnToCnNodeRequestType; import org.apache.iotdb.confignode.client.sync.SyncConfigNodeClientPool; import org.apache.iotdb.rpc.TSStatusCode; @@ -112,7 +112,7 @@ public void removeConfigNode(TConfigNodeLocation removedNode) .sendSyncRequestToConfigNodeWithRetry( configNodeLocation.getInternalEndPoint(), removedNode, - ConfigNodeRequestType.REMOVE_CONFIG_NODE); + CnToCnNodeRequestType.REMOVE_CONFIG_NODE); if (status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { break; } diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeStartupCheck.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeStartupCheck.java index 88be42eb417f0..9a42264ed937e 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeStartupCheck.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeStartupCheck.java @@ -146,7 +146,7 @@ private void checkGlobalConfig() throws ConfigurationException { // When the schemaengine region consensus protocol is set to PipeConsensus, // we should report an error if (CONF.getSchemaRegionConsensusProtocolClass().equals(ConsensusFactory.FAST_IOT_CONSENSUS) - || CONF.getSchemaRegionConsensusProtocolClass().equals(ConsensusFactory.IOTV2_CONSENSUS)) { + || CONF.getSchemaRegionConsensusProtocolClass().equals(ConsensusFactory.IOT_CONSENSUS_V2)) { throw new ConfigurationException( "schema_region_consensus_protocol_class", String.valueOf(CONF.getSchemaRegionConsensusProtocolClass()), diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeSystemPropertiesHandler.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeSystemPropertiesHandler.java new file mode 100644 index 0000000000000..b92e2e57e05d6 --- /dev/null +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeSystemPropertiesHandler.java @@ -0,0 +1,50 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.confignode.conf; + +import org.apache.iotdb.commons.file.SystemPropertiesHandler; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; + +public class ConfigNodeSystemPropertiesHandler extends SystemPropertiesHandler { + private static final Logger LOGGER = + LoggerFactory.getLogger(ConfigNodeSystemPropertiesHandler.class); + + private static ConfigNodeSystemPropertiesHandler INSTANCE; + + private ConfigNodeSystemPropertiesHandler(String filePath) { + super(filePath); + } + + public static synchronized SystemPropertiesHandler getInstance() { + if (INSTANCE == null) { + INSTANCE = + new ConfigNodeSystemPropertiesHandler( + ConfigNodeDescriptor.getInstance().getConf().getSystemDir() + + File.separator + + ConfigNodeConstant.SYSTEM_FILE_NAME); + INSTANCE.recover(); + } + return INSTANCE; + } +} diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/SystemPropertiesUtils.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/SystemPropertiesUtils.java index ba9d74a641cd4..a56f4a63f7296 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/SystemPropertiesUtils.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/SystemPropertiesUtils.java @@ -24,18 +24,14 @@ import org.apache.iotdb.commons.conf.CommonDescriptor; import org.apache.iotdb.commons.conf.IoTDBConstant; import org.apache.iotdb.commons.exception.BadNodeUrlException; +import org.apache.iotdb.commons.file.SystemPropertiesHandler; import org.apache.iotdb.commons.utils.NodeUrlUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import java.util.Objects; @@ -48,11 +44,8 @@ public class SystemPropertiesUtils { private static final Logger LOGGER = LoggerFactory.getLogger(SystemPropertiesUtils.class); - private static File systemPropertiesFile = - new File( - ConfigNodeDescriptor.getInstance().getConf().getSystemDir() - + File.separator - + ConfigNodeConstant.SYSTEM_FILE_NAME); + private static SystemPropertiesHandler systemPropertiesHandler = + ConfigNodeSystemPropertiesHandler.getInstance(); private static final ConfigNodeConfig conf = ConfigNodeDescriptor.getInstance().getConf(); private static final CommonConfig COMMON_CONFIG = CommonDescriptor.getInstance().getConfig(); @@ -74,11 +67,10 @@ private SystemPropertiesUtils() { // TODO: This needs removal of statics ... public static void reinitializeStatics() { - systemPropertiesFile = - new File( - ConfigNodeDescriptor.getInstance().getConf().getSystemDir() - + File.separator - + ConfigNodeConstant.SYSTEM_FILE_NAME); + systemPropertiesHandler.resetFilePath( + ConfigNodeDescriptor.getInstance().getConf().getSystemDir() + + File.separator + + ConfigNodeConstant.SYSTEM_FILE_NAME); } /** @@ -87,7 +79,7 @@ public static void reinitializeStatics() { * @return True if confignode-system.properties file exist. */ public static boolean isRestarted() { - return systemPropertiesFile.exists(); + return !systemPropertiesHandler.isFirstStart(); } /** @@ -97,7 +89,7 @@ public static boolean isRestarted() { * @throws IOException When read the confignode-system.properties file failed */ public static void checkSystemProperties() throws IOException { - Properties systemProperties = getSystemProperties(); + Properties systemProperties = systemPropertiesHandler.read(); boolean needReWrite = false; final String format = "[SystemProperties] The parameter \"{}\" can't be modified after first startup." @@ -234,11 +226,6 @@ public static void checkSystemProperties() throws IOException { COMMON_CONFIG.setTimePartitionInterval(timePartitionInterval); } } - - if (needReWrite) { - // Re-write special parameters if necessary - storeSystemParameters(); - } } /** @@ -251,7 +238,7 @@ public static void checkSystemProperties() throws IOException { */ public static List loadConfigNodeList() throws IOException, BadNodeUrlException { - Properties systemProperties = getSystemProperties(); + Properties systemProperties = systemPropertiesHandler.read(); String addresses = systemProperties.getProperty("config_node_list", null); if (addresses != null && !addresses.isEmpty()) { @@ -265,10 +252,10 @@ public static List loadConfigNodeList() * The system parameters can't be changed after the ConfigNode first started. Therefore, store * them in confignode-system.properties during the first startup. * - * @throws IOException getSystemProperties() + * @throws IOException systemPropertiesHandler.read() */ public static void storeSystemParameters() throws IOException { - Properties systemProperties = getSystemProperties(); + Properties systemProperties = systemPropertiesHandler.read(); systemProperties.setProperty("iotdb_version", IoTDBConstant.VERSION); systemProperties.setProperty("commit_id", IoTDBConstant.BUILD_INFO); @@ -311,7 +298,7 @@ public static void storeSystemParameters() throws IOException { systemProperties.setProperty( "tag_attribute_total_size", String.valueOf(COMMON_CONFIG.getTagAttributeTotalSize())); - storeSystemProperties(systemProperties); + systemPropertiesHandler.overwrite(systemProperties); } /** @@ -321,7 +308,7 @@ public static void storeSystemParameters() throws IOException { * @throws IOException When store confignode-system.properties file failed */ public static void storeConfigNodeList(List configNodes) throws IOException { - if (!systemPropertiesFile.exists()) { + if (!systemPropertiesHandler.fileExist()) { // Avoid creating confignode-system.properties files during // synchronizing the ApplyConfigNode logs from the ConsensusLayer. // 1. For the Non-Seed-ConfigNode, We don't need to create confignode-system.properties file @@ -330,12 +317,8 @@ public static void storeConfigNodeList(List configNodes) th // in which case the latest config_node_list will be updated. return; } - - Properties systemProperties = getSystemProperties(); - systemProperties.setProperty( + systemPropertiesHandler.put( "config_node_list", NodeUrlUtils.convertTConfigNodeUrls(configNodes)); - - storeSystemProperties(systemProperties); } /** @@ -346,7 +329,7 @@ public static void storeConfigNodeList(List configNodes) th * @throws IOException When load confignode-system.properties file failed */ public static String loadClusterNameWhenRestarted() throws IOException { - Properties systemProperties = getSystemProperties(); + Properties systemProperties = systemPropertiesHandler.read(); String clusterName = systemProperties.getProperty(CLUSTER_NAME, null); if (clusterName == null) { LOGGER.warn( @@ -366,7 +349,7 @@ public static String loadClusterNameWhenRestarted() throws IOException { * @throws IOException When load confignode-system.properties file failed */ public static int loadConfigNodeIdWhenRestarted() throws IOException { - Properties systemProperties = getSystemProperties(); + Properties systemProperties = systemPropertiesHandler.read(); try { return Integer.parseInt(systemProperties.getProperty("config_node_id", null)); } catch (NumberFormatException e) { @@ -387,7 +370,7 @@ public static int loadConfigNodeIdWhenRestarted() throws IOException { */ public static boolean isSeedConfigNode() { try { - Properties systemProperties = getSystemProperties(); + Properties systemProperties = systemPropertiesHandler.read(); boolean isSeedConfigNode = Boolean.parseBoolean(systemProperties.getProperty("is_seed_config_node", null)); if (isSeedConfigNode) { @@ -399,37 +382,4 @@ public static boolean isSeedConfigNode() { return false; } } - - private static synchronized Properties getSystemProperties() throws IOException { - // Create confignode-system.properties file if necessary - if (!systemPropertiesFile.exists()) { - if (systemPropertiesFile.createNewFile()) { - LOGGER.info( - "System properties file {} for ConfigNode is created.", - systemPropertiesFile.getAbsolutePath()); - } else { - LOGGER.error( - "Can't create the system properties file {} for ConfigNode. " - + "IoTDB-ConfigNode is shutdown.", - systemPropertiesFile.getAbsolutePath()); - throw new IOException("Can't create system properties file"); - } - } - - Properties systemProperties = new Properties(); - try (FileInputStream inputStream = new FileInputStream(systemPropertiesFile)) { - systemProperties.load(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); - } - return systemProperties; - } - - private static synchronized void storeSystemProperties(Properties systemProperties) - throws IOException { - try (FileOutputStream fileOutputStream = new FileOutputStream(systemPropertiesFile)) { - systemProperties.store( - new OutputStreamWriter(fileOutputStream, StandardCharsets.UTF_8), - " THIS FILE IS AUTOMATICALLY GENERATED. PLEASE DO NOT MODIFY THIS FILE !!!"); - fileOutputStream.getFD().sync(); - } - } } diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/read/ttl/ShowTTLPlan.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/read/ttl/ShowTTLPlan.java index c37c93a907659..9dd9eded31eb8 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/read/ttl/ShowTTLPlan.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/request/read/ttl/ShowTTLPlan.java @@ -20,14 +20,27 @@ import org.apache.iotdb.confignode.consensus.request.ConfigPhysicalPlan; import org.apache.iotdb.confignode.consensus.request.ConfigPhysicalPlanType; +import org.apache.iotdb.db.utils.constant.SqlConstant; import java.io.DataOutputStream; import java.io.IOException; import java.nio.ByteBuffer; public class ShowTTLPlan extends ConfigPhysicalPlan { + private String[] pathPattern; + + public String[] getPathPattern() { + return pathPattern; + } + public ShowTTLPlan() { super(ConfigPhysicalPlanType.ShowTTL); + this.pathPattern = SqlConstant.getSingleRootArray(); + } + + public ShowTTLPlan(String[] pathPattern) { + super(ConfigPhysicalPlanType.ShowTTL); + this.pathPattern = pathPattern; } @Override diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/response/datanode/DataNodeRegisterResp.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/response/datanode/DataNodeRegisterResp.java index ef7d4f212b261..2cbcb15a90129 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/response/datanode/DataNodeRegisterResp.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/consensus/response/datanode/DataNodeRegisterResp.java @@ -32,13 +32,13 @@ import java.io.IOException; import java.util.List; import java.util.Map; +import java.util.Optional; public class DataNodeRegisterResp implements DataSet { private TSStatus status; private List configNodeList; private Integer dataNodeId; - private TRuntimeConfiguration runtimeConfiguration; public DataNodeRegisterResp() { @@ -85,8 +85,8 @@ public TDataNodeRegisterResp convertToRpcDataNodeRegisterResp() { resp.setConfigNodeList(configNodeList); if (status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { - resp.setDataNodeId(dataNodeId); - resp.setRuntimeConfiguration(runtimeConfiguration); + Optional.ofNullable(dataNodeId).ifPresent(resp::setDataNodeId); + Optional.ofNullable(runtimeConfiguration).ifPresent(resp::setRuntimeConfiguration); } return resp; diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ClusterManager.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ClusterManager.java index 9781f77c02448..808112cff4cd4 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ClusterManager.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ClusterManager.java @@ -19,14 +19,41 @@ package org.apache.iotdb.confignode.manager; +import org.apache.iotdb.common.rpc.thrift.TConfigNodeLocation; +import org.apache.iotdb.common.rpc.thrift.TDataNodeConfiguration; +import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; +import org.apache.iotdb.common.rpc.thrift.TEndPoint; +import org.apache.iotdb.common.rpc.thrift.TNodeLocations; +import org.apache.iotdb.common.rpc.thrift.TSStatus; +import org.apache.iotdb.common.rpc.thrift.TSender; +import org.apache.iotdb.common.rpc.thrift.TServiceProvider; +import org.apache.iotdb.common.rpc.thrift.TServiceType; +import org.apache.iotdb.common.rpc.thrift.TTestConnectionResp; +import org.apache.iotdb.common.rpc.thrift.TTestConnectionResult; +import org.apache.iotdb.commons.client.request.AsyncRequestContext; +import org.apache.iotdb.commons.client.request.Utils; +import org.apache.iotdb.confignode.client.CnToCnNodeRequestType; +import org.apache.iotdb.confignode.client.CnToDnRequestType; +import org.apache.iotdb.confignode.client.async.CnToCnInternalServiceAsyncRequestManager; +import org.apache.iotdb.confignode.client.async.CnToDnInternalServiceAsyncRequestManager; +import org.apache.iotdb.confignode.client.async.handlers.ConfigNodeAsyncRequestContext; +import org.apache.iotdb.confignode.client.async.handlers.DataNodeAsyncRequestContext; +import org.apache.iotdb.confignode.conf.ConfigNodeDescriptor; import org.apache.iotdb.confignode.consensus.request.write.confignode.UpdateClusterIdPlan; import org.apache.iotdb.confignode.persistence.ClusterInfo; import org.apache.iotdb.consensus.exception.ConsensusException; +import org.apache.iotdb.rpc.TSStatusCode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; +import java.util.Map; import java.util.UUID; +import java.util.stream.Collectors; +import java.util.stream.Stream; public class ClusterManager { @@ -79,4 +106,198 @@ private void generateClusterId() { LOGGER.warn(CONSENSUS_WRITE_ERROR, e); } } + + // TODO: Parallel test ConfigNode and DataNode + public TTestConnectionResp submitTestConnectionTaskToEveryNode() { + TTestConnectionResp resp = new TTestConnectionResp(); + resp.resultList = new ArrayList<>(); + resp.setStatus(new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode())); + TNodeLocations nodeLocations = new TNodeLocations(); + nodeLocations.setConfigNodeLocations(configManager.getNodeManager().getRegisteredConfigNodes()); + nodeLocations.setDataNodeLocations( + configManager.getNodeManager().getRegisteredDataNodes().stream() + .map(TDataNodeConfiguration::getLocation) + .collect(Collectors.toList())); + // For ConfigNode + Map configNodeLocationMap = + configManager.getNodeManager().getRegisteredConfigNodes().stream() + .collect(Collectors.toMap(TConfigNodeLocation::getConfigNodeId, location -> location)); + ConfigNodeAsyncRequestContext + configNodeAsyncRequestContext = + new ConfigNodeAsyncRequestContext<>( + CnToCnNodeRequestType.SUBMIT_TEST_CONNECTION_TASK, + nodeLocations, + configNodeLocationMap); + CnToCnInternalServiceAsyncRequestManager.getInstance() + .sendAsyncRequest(configNodeAsyncRequestContext); + Map anotherConfigNodeLocationMap = + configManager.getNodeManager().getRegisteredConfigNodes().stream() + .collect(Collectors.toMap(TConfigNodeLocation::getConfigNodeId, location -> location)); + configNodeAsyncRequestContext + .getResponseMap() + .forEach( + (nodeId, configNodeResp) -> { + if (configNodeResp.isSetResultList()) { + resp.getResultList().addAll(configNodeResp.getResultList()); + } else { + resp.getResultList() + .addAll( + badConfigNodeConnectionResult( + configNodeResp.getStatus(), + anotherConfigNodeLocationMap.get(nodeId), + nodeLocations)); + } + }); + // For DataNode + Map dataNodeLocationMap = + configManager.getNodeManager().getRegisteredDataNodes().stream() + .map(TDataNodeConfiguration::getLocation) + .collect(Collectors.toMap(TDataNodeLocation::getDataNodeId, location -> location)); + DataNodeAsyncRequestContext dataNodeAsyncRequestContext = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.SUBMIT_TEST_CONNECTION_TASK, nodeLocations, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance() + .sendAsyncRequest(dataNodeAsyncRequestContext); + Map anotherDataNodeLocationMap = + configManager.getNodeManager().getRegisteredDataNodes().stream() + .map(TDataNodeConfiguration::getLocation) + .collect(Collectors.toMap(TDataNodeLocation::getDataNodeId, location -> location)); + dataNodeAsyncRequestContext + .getResponseMap() + .forEach( + (nodeId, dataNodeResp) -> { + if (dataNodeResp.isSetResultList()) { + resp.getResultList().addAll(dataNodeResp.getResultList()); + } else { + resp.getResultList() + .addAll( + badDataNodeConnectionResult( + dataNodeResp.getStatus(), + anotherDataNodeLocationMap.get(nodeId), + nodeLocations)); + } + }); + return resp; + } + + public TTestConnectionResp doConnectionTest(TNodeLocations nodeLocations) { + return new TTestConnectionResp( + new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()), + Stream.of( + testAllConfigNodeConnection(nodeLocations.getConfigNodeLocations()), + testAllDataNodeConnection(nodeLocations.getDataNodeLocations())) + .flatMap(Collection::stream) + .collect(Collectors.toList())); + } + + private List testAllConfigNodeConnection( + List configNodeLocations) { + final TSender sender = + new TSender() + .setConfigNodeLocation( + ConfigNodeDescriptor.getInstance().getConf().generateLocalConfigNodeLocation()); + return Utils.testConnectionsImpl( + configNodeLocations, + sender, + TConfigNodeLocation::getConfigNodeId, + TConfigNodeLocation::getInternalEndPoint, + TServiceType.ConfigNodeInternalService, + CnToCnNodeRequestType.TEST_CONNECTION, + (AsyncRequestContext + handler) -> + CnToCnInternalServiceAsyncRequestManager.getInstance() + .sendAsyncRequestWithRetry(handler)); + } + + private List badConfigNodeConnectionResult( + TSStatus badStatus, TConfigNodeLocation sourceConfigNode, TNodeLocations nodeLocations) { + final TSender sender = new TSender().setConfigNodeLocation(sourceConfigNode); + return badNodeConnectionResult(badStatus, nodeLocations, sender); + } + + private List testAllDataNodeConnection( + List dataNodeLocations) { + final TSender sender = + new TSender() + .setConfigNodeLocation( + ConfigNodeDescriptor.getInstance().getConf().generateLocalConfigNodeLocation()); + return Utils.testConnectionsImpl( + dataNodeLocations, + sender, + TDataNodeLocation::getDataNodeId, + TDataNodeLocation::getInternalEndPoint, + TServiceType.DataNodeInternalService, + CnToDnRequestType.TEST_CONNECTION, + (AsyncRequestContext handler) -> + CnToDnInternalServiceAsyncRequestManager.getInstance() + .sendAsyncRequestWithRetry(handler)); + } + + private List badDataNodeConnectionResult( + TSStatus badStatus, TDataNodeLocation sourceDataNode, TNodeLocations nodeLocations) { + final TSender sender = new TSender().setDataNodeLocation(sourceDataNode); + return badNodeConnectionResult(badStatus, nodeLocations, sender); + } + + private List badNodeConnectionResult( + TSStatus badStatus, TNodeLocations nodeLocations, TSender sender) { + final String errorMessage = + "ConfigNode leader cannot connect to the sender: " + badStatus.getMessage(); + List results = new ArrayList<>(); + nodeLocations + .getConfigNodeLocations() + .forEach( + location -> { + TEndPoint endPoint = location.getInternalEndPoint(); + TServiceProvider serviceProvider = + new TServiceProvider(endPoint, TServiceType.ConfigNodeInternalService); + TTestConnectionResult result = + new TTestConnectionResult().setServiceProvider(serviceProvider).setSender(sender); + result.setSuccess(false).setReason(errorMessage); + results.add(result); + }); + nodeLocations + .getDataNodeLocations() + .forEach( + location -> { + TEndPoint endPoint = location.getInternalEndPoint(); + TServiceProvider serviceProvider = + new TServiceProvider(endPoint, TServiceType.DataNodeInternalService); + TTestConnectionResult result = + new TTestConnectionResult().setServiceProvider(serviceProvider).setSender(sender); + result.setSuccess(false).setReason(errorMessage); + results.add(result); + }); + if (sender.isSetDataNodeLocation()) { + nodeLocations + .getDataNodeLocations() + .forEach( + location -> { + TEndPoint endPoint = location.getMPPDataExchangeEndPoint(); + TServiceProvider serviceProvider = + new TServiceProvider(endPoint, TServiceType.DataNodeMPPService); + TTestConnectionResult result = + new TTestConnectionResult() + .setServiceProvider(serviceProvider) + .setSender(sender); + result.setSuccess(false).setReason(errorMessage); + results.add(result); + }); + nodeLocations + .getDataNodeLocations() + .forEach( + location -> { + TEndPoint endPoint = location.getClientRpcEndPoint(); + TServiceProvider serviceProvider = + new TServiceProvider(endPoint, TServiceType.DataNodeExternalService); + TTestConnectionResult result = + new TTestConnectionResult() + .setServiceProvider(serviceProvider) + .setSender(sender); + result.setSuccess(false).setReason(errorMessage); + results.add(result); + }); + } + return results; + } } diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ClusterQuotaManager.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ClusterQuotaManager.java index 0c00005fc1b34..b0150b349d80e 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ClusterQuotaManager.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ClusterQuotaManager.java @@ -26,9 +26,9 @@ import org.apache.iotdb.common.rpc.thrift.TSpaceQuota; import org.apache.iotdb.common.rpc.thrift.TThrottleQuota; import org.apache.iotdb.commons.conf.IoTDBConstant; -import org.apache.iotdb.confignode.client.DataNodeRequestType; -import org.apache.iotdb.confignode.client.async.AsyncDataNodeClientPool; -import org.apache.iotdb.confignode.client.async.handlers.AsyncClientHandler; +import org.apache.iotdb.confignode.client.CnToDnRequestType; +import org.apache.iotdb.confignode.client.async.CnToDnInternalServiceAsyncRequestManager; +import org.apache.iotdb.confignode.client.async.handlers.DataNodeAsyncRequestContext; import org.apache.iotdb.confignode.consensus.request.write.quota.SetSpaceQuotaPlan; import org.apache.iotdb.confignode.consensus.request.write.quota.SetThrottleQuotaPlan; import org.apache.iotdb.confignode.manager.partition.PartitionManager; @@ -87,9 +87,11 @@ public TSStatus setSpaceQuota(TSetSpaceQuotaReq req) { if (response.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { Map dataNodeLocationMap = configManager.getNodeManager().getRegisteredDataNodeLocations(); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>(DataNodeRequestType.SET_SPACE_QUOTA, req, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.SET_SPACE_QUOTA, req, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance() + .sendAsyncRequestWithRetry(clientHandler); return RpcUtils.squashResponseStatusList(clientHandler.getResponseList()); } return response; @@ -192,10 +194,11 @@ public TSStatus setThrottleQuota(TSetThrottleQuotaReq req) { if (response.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { Map dataNodeLocationMap = configManager.getNodeManager().getRegisteredDataNodeLocations(); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.SET_THROTTLE_QUOTA, req, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.SET_THROTTLE_QUOTA, req, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance() + .sendAsyncRequestWithRetry(clientHandler); return RpcUtils.squashResponseStatusList(clientHandler.getResponseList()); } return response; diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java index f87fa380e2593..fddc92e40e935 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java @@ -406,13 +406,8 @@ public DataSet getSystemConfiguration() { public DataSet registerDataNode(TDataNodeRegisterReq req) { TSStatus status = confirmLeader(); if (status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { - status = - ClusterNodeStartUtils.confirmNodeRegistration( - NodeType.DataNode, - req.getClusterName(), - req.getDataNodeConfiguration().getLocation(), - this); - if (status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { + status = ClusterNodeStartUtils.confirmDataNodeRegistration(req, this); + if (!req.isPreCheck() && status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { return nodeManager.registerDataNode(req); } } @@ -631,10 +626,10 @@ public DataSet getMatchedDatabaseSchemas(GetDatabasePlan getDatabaseReq) { } @Override - public DataSet showAllTTL(ShowTTLPlan showTTLPlan) { + public DataSet showTTL(ShowTTLPlan showTTLPlan) { TSStatus status = confirmLeader(); if (status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { - return ttlManager.showAllTTL(showTTLPlan); + return ttlManager.showTTL(showTTLPlan); } else { ShowTTLResp resp = new ShowTTLResp(); resp.setStatus(status); @@ -1216,12 +1211,7 @@ public TConfigNodeRegisterResp registerConfigNode(TConfigNodeRegisterReq req) { // Make sure the global configurations are consist status = checkConfigNodeGlobalConfig(req); if (status == null) { - status = - ClusterNodeStartUtils.confirmNodeRegistration( - NodeType.ConfigNode, - req.getClusterParameters().getClusterName(), - req.getConfigNodeLocation(), - this); + status = ClusterNodeStartUtils.confirmConfigNodeRegistration(req, this); if (status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { return nodeManager.registerConfigNode(req); } diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/IManager.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/IManager.java index 919e876bac213..98695d1eb7ba7 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/IManager.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/IManager.java @@ -304,7 +304,7 @@ public interface IManager { TSStatus setTTL(SetTTLPlan configRequest); - DataSet showAllTTL(ShowTTLPlan showTTLPlan); + DataSet showTTL(ShowTTLPlan showTTLPlan); TSStatus setSchemaReplicationFactor(SetSchemaReplicationFactorPlan configPhysicalPlan); diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/TTLManager.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/TTLManager.java index af4fb49a0cb09..6bebe7c686474 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/TTLManager.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/TTLManager.java @@ -119,7 +119,7 @@ public TSStatus unsetTTL(SetTTLPlan setTTLPlan, final boolean isGeneratedByPipe) return configManager.getProcedureManager().setTTL(setTTLPlan, isGeneratedByPipe); } - public DataSet showAllTTL(ShowTTLPlan showTTLPlan) { + public DataSet showTTL(ShowTTLPlan showTTLPlan) { try { return configManager.getConsensusManager().read(showTTLPlan); } catch (ConsensusException e) { @@ -133,7 +133,7 @@ public DataSet showAllTTL(ShowTTLPlan showTTLPlan) { } public Map getAllTTL() { - return ((ShowTTLResp) showAllTTL(new ShowTTLPlan())).getPathTTLMap(); + return ((ShowTTLResp) showTTL(new ShowTTLPlan())).getPathTTLMap(); } public int getTTLCount() { diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/TriggerManager.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/TriggerManager.java index 0b4bb73102f9b..b1a96d029af2a 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/TriggerManager.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/TriggerManager.java @@ -24,9 +24,9 @@ import org.apache.iotdb.commons.path.PartialPath; import org.apache.iotdb.commons.path.PathDeserializeUtil; import org.apache.iotdb.commons.trigger.TriggerInformation; -import org.apache.iotdb.confignode.client.DataNodeRequestType; -import org.apache.iotdb.confignode.client.async.AsyncDataNodeClientPool; -import org.apache.iotdb.confignode.client.async.handlers.AsyncClientHandler; +import org.apache.iotdb.confignode.client.CnToDnRequestType; +import org.apache.iotdb.confignode.client.async.CnToDnInternalServiceAsyncRequestManager; +import org.apache.iotdb.confignode.client.async.handlers.DataNodeAsyncRequestContext; import org.apache.iotdb.confignode.consensus.request.read.trigger.GetTransferringTriggersPlan; import org.apache.iotdb.confignode.consensus.request.read.trigger.GetTriggerJarPlan; import org.apache.iotdb.confignode.consensus.request.read.trigger.GetTriggerLocationPlan; @@ -248,10 +248,10 @@ public List updateTriggerLocation( final TUpdateTriggerLocationReq request = new TUpdateTriggerLocationReq(triggerName, dataNodeLocation); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.UPDATE_TRIGGER_LOCATION, request, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.UPDATE_TRIGGER_LOCATION, request, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); return clientHandler.getResponseList(); } } diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/UDFManager.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/UDFManager.java index a84eb8359eadf..ad86879d8280f 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/UDFManager.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/UDFManager.java @@ -23,9 +23,9 @@ import org.apache.iotdb.common.rpc.thrift.TSStatus; import org.apache.iotdb.commons.conf.IoTDBConstant; import org.apache.iotdb.commons.udf.UDFInformation; -import org.apache.iotdb.confignode.client.DataNodeRequestType; -import org.apache.iotdb.confignode.client.async.AsyncDataNodeClientPool; -import org.apache.iotdb.confignode.client.async.handlers.AsyncClientHandler; +import org.apache.iotdb.confignode.client.CnToDnRequestType; +import org.apache.iotdb.confignode.client.async.CnToDnInternalServiceAsyncRequestManager; +import org.apache.iotdb.confignode.client.async.handlers.DataNodeAsyncRequestContext; import org.apache.iotdb.confignode.conf.ConfigNodeDescriptor; import org.apache.iotdb.confignode.consensus.request.read.function.GetFunctionTablePlan; import org.apache.iotdb.confignode.consensus.request.read.function.GetUDFJarPlan; @@ -127,9 +127,10 @@ private List createFunctionOnDataNodes(UDFInformation udfInformation, configManager.getNodeManager().getRegisteredDataNodeLocations(); final TCreateFunctionInstanceReq req = new TCreateFunctionInstanceReq(udfInformation.serialize()).setJarFile(jarFile); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>(DataNodeRequestType.CREATE_FUNCTION, req, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.CREATE_FUNCTION, req, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); return clientHandler.getResponseList(); } @@ -160,9 +161,10 @@ private List dropFunctionOnDataNodes(String functionName) { final TDropFunctionInstanceReq request = new TDropFunctionInstanceReq(functionName, false); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>(DataNodeRequestType.DROP_FUNCTION, request, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.DROP_FUNCTION, request, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); return clientHandler.getResponseList(); } diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/cq/CQScheduleTask.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/cq/CQScheduleTask.java index 9ccd02f128119..6125edc1ef7bd 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/cq/CQScheduleTask.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/cq/CQScheduleTask.java @@ -24,7 +24,7 @@ import org.apache.iotdb.commons.client.async.AsyncDataNodeInternalServiceClient; import org.apache.iotdb.commons.conf.CommonDescriptor; import org.apache.iotdb.commons.cq.TimeoutPolicy; -import org.apache.iotdb.confignode.client.async.AsyncDataNodeClientPool; +import org.apache.iotdb.confignode.client.async.CnToDnInternalServiceAsyncRequestManager; import org.apache.iotdb.confignode.consensus.request.write.cq.UpdateCQLastExecTimePlan; import org.apache.iotdb.confignode.manager.ConfigManager; import org.apache.iotdb.confignode.persistence.cq.CQInfo; @@ -188,7 +188,8 @@ public void run() { new TExecuteCQ(queryBody, startTime, endTime, everyInterval, zoneId, cqId, username); try { AsyncDataNodeInternalServiceClient client = - AsyncDataNodeClientPool.getInstance().getAsyncClient(targetDataNode.get()); + CnToDnInternalServiceAsyncRequestManager.getInstance() + .getAsyncClient(targetDataNode.get()); client.executeCQ(executeCQReq, new AsyncExecuteCQCallback(startTime, endTime)); } catch (Exception t) { LOGGER.warn("Execute CQ {} failed", cqId, t); diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/load/balancer/RouteBalancer.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/load/balancer/RouteBalancer.java index 5640721fba1ae..36f85afcbef60 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/load/balancer/RouteBalancer.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/load/balancer/RouteBalancer.java @@ -25,9 +25,9 @@ import org.apache.iotdb.common.rpc.thrift.TRegionReplicaSet; import org.apache.iotdb.common.rpc.thrift.TSStatus; import org.apache.iotdb.commons.cluster.NodeStatus; -import org.apache.iotdb.confignode.client.DataNodeRequestType; -import org.apache.iotdb.confignode.client.async.AsyncDataNodeClientPool; -import org.apache.iotdb.confignode.client.async.handlers.AsyncClientHandler; +import org.apache.iotdb.confignode.client.CnToDnRequestType; +import org.apache.iotdb.confignode.client.async.CnToDnInternalServiceAsyncRequestManager; +import org.apache.iotdb.confignode.client.async.handlers.DataNodeAsyncRequestContext; import org.apache.iotdb.confignode.conf.ConfigNodeConfig; import org.apache.iotdb.confignode.conf.ConfigNodeDescriptor; import org.apache.iotdb.confignode.manager.IManager; @@ -83,7 +83,7 @@ public class RouteBalancer implements IClusterStatusSubscriber { || (CONF.isEnableAutoLeaderBalanceForIoTConsensus() && ConsensusFactory.FAST_IOT_CONSENSUS.equals(DATA_REGION_CONSENSUS_PROTOCOL_CLASS)) || (CONF.isEnableAutoLeaderBalanceForIoTConsensus() - && ConsensusFactory.IOTV2_CONSENSUS.equals(DATA_REGION_CONSENSUS_PROTOCOL_CLASS)) + && ConsensusFactory.IOT_CONSENSUS_V2.equals(DATA_REGION_CONSENSUS_PROTOCOL_CLASS)) // The simple consensus protocol will always automatically designate itself as the leader || ConsensusFactory.SIMPLE_CONSENSUS.equals(DATA_REGION_CONSENSUS_PROTOCOL_CLASS); private static final boolean IS_ENABLE_AUTO_LEADER_BALANCE_FOR_SCHEMA_REGION = @@ -167,8 +167,8 @@ private void balanceRegionLeader( // Transfer leader to the optimal distribution long currentTime = System.nanoTime(); AtomicInteger requestId = new AtomicInteger(0); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>(DataNodeRequestType.CHANGE_REGION_LEADER); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>(CnToDnRequestType.CHANGE_REGION_LEADER); Map successTransferMap = new TreeMap<>(); optimalLeaderMap.forEach( (regionGroupId, newLeaderId) -> { @@ -185,7 +185,7 @@ private void balanceRegionLeader( newLeaderId); switch (consensusProtocolClass) { case ConsensusFactory.FAST_IOT_CONSENSUS: - case ConsensusFactory.IOTV2_CONSENSUS: + case ConsensusFactory.IOT_CONSENSUS_V2: case ConsensusFactory.IOT_CONSENSUS: case ConsensusFactory.SIMPLE_CONSENSUS: // For IoTConsensus or SimpleConsensus or PipeConsensus protocol, change @@ -217,7 +217,7 @@ private void balanceRegionLeader( new TRegionLeaderChangeReq(regionGroupId, newLeader); int requestIndex = requestId.getAndIncrement(); clientHandler.putRequest(requestIndex, regionLeaderChangeReq); - clientHandler.putDataNodeLocation(requestIndex, newLeader); + clientHandler.putNodeLocation(requestIndex, newLeader); } break; } @@ -225,7 +225,7 @@ private void balanceRegionLeader( }); if (requestId.get() > 0) { // Don't retry ChangeLeader request - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNode(clientHandler); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequest(clientHandler); for (int i = 0; i < requestId.get(); i++) { if (clientHandler.getResponseMap().get(i).getStatus().getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { @@ -307,12 +307,12 @@ private void broadcastLatestRegionPriorityMap() { long broadcastTime = System.currentTimeMillis(); Map tmpPriorityMap = getRegionPriorityMap(); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.UPDATE_REGION_ROUTE_MAP, + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.UPDATE_REGION_ROUTE_MAP, new TRegionRouteReq(broadcastTime, tmpPriorityMap), dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); } private void recordRegionPriorityMap( diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/node/ClusterNodeStartUtils.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/node/ClusterNodeStartUtils.java index 13cd42393fab2..1230746e3577d 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/node/ClusterNodeStartUtils.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/node/ClusterNodeStartUtils.java @@ -26,8 +26,11 @@ import org.apache.iotdb.common.rpc.thrift.TSStatus; import org.apache.iotdb.commons.cluster.NodeType; import org.apache.iotdb.commons.conf.CommonConfig; +import org.apache.iotdb.commons.conf.CommonDescriptor; import org.apache.iotdb.confignode.conf.ConfigNodeDescriptor; import org.apache.iotdb.confignode.manager.ConfigManager; +import org.apache.iotdb.confignode.rpc.thrift.TConfigNodeRegisterReq; +import org.apache.iotdb.confignode.rpc.thrift.TDataNodeRegisterReq; import org.apache.iotdb.rpc.TSStatusCode; import java.util.ArrayList; @@ -53,11 +56,8 @@ private ClusterNodeStartUtils() { // Empty constructor } - public static TSStatus confirmNodeRegistration( - NodeType nodeType, String clusterName, Object nodeLocation, ConfigManager configManager) { + private static TSStatus confirmClusterName(NodeType nodeType, String clusterName) { TSStatus status = new TSStatus(); - - /* Reject start if the cluster name is error */ if (!CLUSTER_NAME.equals(clusterName)) { status.setCode(TSStatusCode.REJECT_NODE_START.getStatusCode()); status.setMessage( @@ -75,47 +75,88 @@ public static TSStatus confirmNodeRegistration( CommonConfig.SYSTEM_CONFIG_NAME)); return status; } + return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()); + } - /* Check if there exist conflict TEndPoints */ - List conflictEndPoints = null; - switch (nodeType) { - case ConfigNode: - if (nodeLocation instanceof TConfigNodeLocation) { - conflictEndPoints = - checkConflictTEndPointForNewConfigNode( - (TConfigNodeLocation) nodeLocation, - configManager.getNodeManager().getRegisteredConfigNodes()); - } - break; - case DataNode: - default: - if (nodeLocation instanceof TDataNodeLocation) { - conflictEndPoints = - checkConflictTEndPointForNewDataNode( - (TDataNodeLocation) nodeLocation, - configManager.getNodeManager().getRegisteredDataNodes()); - } - break; + private static TSStatus rejectRegistrationBecauseConflictEndPoints( + NodeType nodeType, List conflictEndPoints) { + TSStatus status = new TSStatus(); + status.setCode(TSStatusCode.REJECT_NODE_START.getStatusCode()); + status.setMessage( + String.format( + "Reject %s registration. Because the following ip:port: %s of the current %s is conflicted with other registered Nodes in the cluster." + + POSSIBLE_SOLUTIONS + + "\t1. Use SQL: \"show cluster details\" to find out the conflict Nodes. Remove them and retry start." + + "\n\t2. Change the conflict ip:port configurations in %s file and retry start.", + nodeType.getNodeType(), + conflictEndPoints, + nodeType.getNodeType(), + CommonConfig.SYSTEM_CONFIG_NAME)); + return status; + } + + public static TSStatus confirmClusterId(ConfigManager configManager) { + TSStatus status = new TSStatus(); + final String clusterId = + configManager + .getClusterManager() + .getClusterIdWithRetry( + CommonDescriptor.getInstance().getConfig().getConnectionTimeoutInMS() / 2); + if (clusterId == null) { + status + .setCode(TSStatusCode.GET_CLUSTER_ID_ERROR.getStatusCode()) + .setMessage("cluster id has not generated, please try again later"); + return status; } + return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()); + } - if (conflictEndPoints != null && !conflictEndPoints.isEmpty()) { - /* Reject Node registration because there exist conflict TEndPoints */ - status.setCode(TSStatusCode.REJECT_NODE_START.getStatusCode()); - status.setMessage( - String.format( - "Reject %s registration. Because the following ip:port: %s of the current %s is conflicted with other registered Nodes in the cluster." - + POSSIBLE_SOLUTIONS - + "\t1. Use SQL: \"show cluster details\" to find out the conflict Nodes. Remove them and retry start." - + "\n\t2. Change the conflict ip:port configurations in %s file and retry start.", - nodeType.getNodeType(), - conflictEndPoints, - nodeType.getNodeType(), - CommonConfig.SYSTEM_CONFIG_NAME)); + public static TSStatus confirmDataNodeRegistration( + TDataNodeRegisterReq req, ConfigManager configManager) { + // Confirm cluster name + TSStatus status = confirmClusterName(NodeType.DataNode, req.getClusterName()); + if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { + return status; + } + // Confirm end point conflicts + List conflictEndPoints = + checkConflictTEndPointForNewDataNode( + req.getDataNodeConfiguration().getLocation(), + configManager.getNodeManager().getRegisteredDataNodes()); + if (!conflictEndPoints.isEmpty()) { + return rejectRegistrationBecauseConflictEndPoints(NodeType.DataNode, conflictEndPoints); + } + // Confirm whether cluster id has been generated + status = confirmClusterId(configManager); + if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { + return status; + } + // Success + return ACCEPT_NODE_REGISTRATION; + } + + public static TSStatus confirmConfigNodeRegistration( + TConfigNodeRegisterReq req, ConfigManager configManager) { + // Confirm cluster name + TSStatus status = + confirmClusterName(NodeType.ConfigNode, req.getClusterParameters().getClusterName()); + if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { + return status; + } + // Confirm end point conflicts + List conflictEndPoints = + checkConflictTEndPointForNewConfigNode( + req.getConfigNodeLocation(), configManager.getNodeManager().getRegisteredConfigNodes()); + if (!conflictEndPoints.isEmpty()) { + return rejectRegistrationBecauseConflictEndPoints(NodeType.ConfigNode, conflictEndPoints); + } + // Confirm whether cluster id has been generated + status = confirmClusterId(configManager); + if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { return status; - } else { - /* Accept registration if all TEndPoints aren't conflict */ - return ACCEPT_NODE_REGISTRATION; } + // Success + return ACCEPT_NODE_REGISTRATION; } public static TSStatus confirmNodeRestart( diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/node/NodeManager.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/node/NodeManager.java index a0af5578b59b3..2e16c339ab680 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/node/NodeManager.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/node/NodeManager.java @@ -35,10 +35,10 @@ import org.apache.iotdb.commons.conf.CommonDescriptor; import org.apache.iotdb.commons.consensus.ConsensusGroupId; import org.apache.iotdb.commons.service.metric.MetricService; -import org.apache.iotdb.confignode.client.ConfigNodeRequestType; -import org.apache.iotdb.confignode.client.DataNodeRequestType; -import org.apache.iotdb.confignode.client.async.AsyncDataNodeClientPool; -import org.apache.iotdb.confignode.client.async.handlers.AsyncClientHandler; +import org.apache.iotdb.confignode.client.CnToCnNodeRequestType; +import org.apache.iotdb.confignode.client.CnToDnRequestType; +import org.apache.iotdb.confignode.client.async.CnToDnInternalServiceAsyncRequestManager; +import org.apache.iotdb.confignode.client.async.handlers.DataNodeAsyncRequestContext; import org.apache.iotdb.confignode.client.sync.SyncConfigNodeClientPool; import org.apache.iotdb.confignode.client.sync.SyncDataNodeClientPool; import org.apache.iotdb.confignode.conf.ConfigNodeConfig; @@ -267,17 +267,6 @@ private TRuntimeConfiguration getRuntimeConfiguration() { public DataSet registerDataNode(TDataNodeRegisterReq req) { DataNodeRegisterResp resp = new DataNodeRegisterResp(); resp.setConfigNodeList(getRegisteredConfigNodes()); - final String clusterId = - configManager - .getClusterManager() - .getClusterIdWithRetry( - CommonDescriptor.getInstance().getConfig().getConnectionTimeoutInMS() / 2); - if (clusterId == null) { - resp.setStatus( - new TSStatus(TSStatusCode.GET_CLUSTER_ID_ERROR.getStatusCode()) - .setMessage("clusterId has not generated, please try again later")); - return resp; - } // Create a new DataNodeHeartbeatCache and force update NodeStatus int dataNodeId = nodeInfo.generateNextNodeId(); @@ -313,6 +302,7 @@ public DataSet registerDataNode(TDataNodeRegisterReq req) { resp.setStatus(ClusterNodeStartUtils.ACCEPT_NODE_REGISTRATION); resp.setDataNodeId( registerDataNodePlan.getDataNodeConfiguration().getLocation().getDataNodeId()); + String clusterId = configManager.getClusterManager().getClusterId(); resp.setRuntimeConfiguration(getRuntimeConfiguration().setClusterId(clusterId)); return resp; } @@ -707,27 +697,27 @@ private TSStatus transferLeader( public List merge() { Map dataNodeLocationMap = configManager.getNodeManager().getRegisteredDataNodeLocations(); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>(DataNodeRequestType.MERGE, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>(CnToDnRequestType.MERGE, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); return clientHandler.getResponseList(); } public List flush(TFlushReq req) { Map dataNodeLocationMap = configManager.getNodeManager().getRegisteredDataNodeLocations(); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>(DataNodeRequestType.FLUSH, req, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>(CnToDnRequestType.FLUSH, req, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); return clientHandler.getResponseList(); } public List clearCache() { Map dataNodeLocationMap = configManager.getNodeManager().getRegisteredDataNodeLocations(); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>(DataNodeRequestType.CLEAR_CACHE, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>(CnToDnRequestType.CLEAR_CACHE, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); return clientHandler.getResponseList(); } @@ -745,9 +735,11 @@ public List setConfiguration(TSetConfigurationReq req) { targetDataNodes.putAll(dataNodeLocationMap); } if (!targetDataNodes.isEmpty()) { - AsyncClientHandler clientHandler = - new AsyncClientHandler<>(DataNodeRequestType.SET_CONFIGURATION, req, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.SET_CONFIGURATION, req, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance() + .sendAsyncRequestWithRetry(clientHandler); responseList.addAll(clientHandler.getResponseList()); } @@ -768,7 +760,7 @@ public List setConfiguration(TSetConfigurationReq req) { .sendSyncRequestToConfigNodeWithRetry( configNode.getInternalEndPoint(), new TSetConfigurationReq(req.getConfigs(), configNode.getConfigNodeId()), - ConfigNodeRequestType.SET_CONFIGURATION); + CnToCnNodeRequestType.SET_CONFIGURATION); } catch (Exception e) { status = RpcUtils.getStatus( @@ -782,27 +774,28 @@ public List setConfiguration(TSetConfigurationReq req) { public List startRpairData() { Map dataNodeLocationMap = configManager.getNodeManager().getRegisteredDataNodeLocations(); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>(DataNodeRequestType.START_REPAIR_DATA, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>(CnToDnRequestType.START_REPAIR_DATA, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); return clientHandler.getResponseList(); } public List stopRepairData() { Map dataNodeLocationMap = configManager.getNodeManager().getRegisteredDataNodeLocations(); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>(DataNodeRequestType.STOP_REPAIR_DATA, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>(CnToDnRequestType.STOP_REPAIR_DATA, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); return clientHandler.getResponseList(); } public List loadConfiguration() { Map dataNodeLocationMap = configManager.getNodeManager().getRegisteredDataNodeLocations(); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>(DataNodeRequestType.LOAD_CONFIGURATION, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.LOAD_CONFIGURATION, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); return clientHandler.getResponseList(); } @@ -819,7 +812,7 @@ public TShowConfigurationResp showConfiguration(int nodeId) { .sendSyncRequestToDataNodeWithRetry( dataNodeLocation.getInternalEndPoint(), null, - DataNodeRequestType.SHOW_CONFIGURATION); + CnToDnRequestType.SHOW_CONFIGURATION); } // other config node @@ -833,7 +826,7 @@ public TShowConfigurationResp showConfiguration(int nodeId) { .sendSyncRequestToConfigNodeWithRetry( registeredConfigNode.getInternalEndPoint(), nodeId, - ConfigNodeRequestType.SHOW_CONFIGURATION); + CnToCnNodeRequestType.SHOW_CONFIGURATION); return resp; } return resp; @@ -842,10 +835,10 @@ public TShowConfigurationResp showConfiguration(int nodeId) { public List setSystemStatus(String status) { Map dataNodeLocationMap = configManager.getNodeManager().getRegisteredDataNodeLocations(); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.SET_SYSTEM_STATUS, status, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.SET_SYSTEM_STATUS, status, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); return clientHandler.getResponseList(); } @@ -855,7 +848,7 @@ public TSStatus setDataNodeStatus(TSetDataNodeStatusReq setDataNodeStatusReq) { .sendSyncRequestToDataNodeWithRetry( setDataNodeStatusReq.getTargetDataNode().getInternalEndPoint(), setDataNodeStatusReq.getStatus(), - DataNodeRequestType.SET_SYSTEM_STATUS); + CnToDnRequestType.SET_SYSTEM_STATUS); } /** @@ -876,9 +869,10 @@ public TSStatus killQuery(String queryId, int dataNodeId) { private TSStatus killAllQueries() { Map dataNodeLocationMap = configManager.getNodeManager().getRegisteredDataNodeLocations(); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>(DataNodeRequestType.KILL_QUERY_INSTANCE, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.KILL_QUERY_INSTANCE, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); return RpcUtils.squashResponseStatusList(clientHandler.getResponseList()); } @@ -893,7 +887,7 @@ private TSStatus killSpecificQuery(String queryId, TDataNodeLocation dataNodeLoc .sendSyncRequestToDataNodeWithRetry( dataNodeLocation.getInternalEndPoint(), queryId, - DataNodeRequestType.KILL_QUERY_INSTANCE); + CnToDnRequestType.KILL_QUERY_INSTANCE); } } diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/partition/PartitionManager.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/partition/PartitionManager.java index 60744f80ec2c0..e1a04a29007e1 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/partition/PartitionManager.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/partition/PartitionManager.java @@ -34,9 +34,9 @@ import org.apache.iotdb.commons.partition.SchemaPartitionTable; import org.apache.iotdb.commons.partition.executor.SeriesPartitionExecutor; import org.apache.iotdb.commons.path.PartialPath; -import org.apache.iotdb.confignode.client.DataNodeRequestType; -import org.apache.iotdb.confignode.client.async.AsyncDataNodeClientPool; -import org.apache.iotdb.confignode.client.async.handlers.AsyncClientHandler; +import org.apache.iotdb.confignode.client.CnToDnRequestType; +import org.apache.iotdb.confignode.client.async.CnToDnInternalServiceAsyncRequestManager; +import org.apache.iotdb.confignode.client.async.handlers.DataNodeAsyncRequestContext; import org.apache.iotdb.confignode.conf.ConfigNodeConfig; import org.apache.iotdb.confignode.conf.ConfigNodeDescriptor; import org.apache.iotdb.confignode.consensus.request.ConfigPhysicalPlan; @@ -1264,10 +1264,10 @@ public void maintainRegionReplicas() { switch (selectedRegionMaintainTask.get(0).getRegionId().getType()) { case SchemaRegion: // create SchemaRegion - AsyncClientHandler + DataNodeAsyncRequestContext createSchemaRegionHandler = - new AsyncClientHandler<>( - DataNodeRequestType.CREATE_SCHEMA_REGION); + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.CREATE_SCHEMA_REGION); for (RegionMaintainTask regionMaintainTask : selectedRegionMaintainTask) { RegionCreateTask schemaRegionCreateTask = (RegionCreateTask) regionMaintainTask; @@ -1280,13 +1280,13 @@ public void maintainRegionReplicas() { new TCreateSchemaRegionReq( schemaRegionCreateTask.getRegionReplicaSet(), schemaRegionCreateTask.getStorageGroup())); - createSchemaRegionHandler.putDataNodeLocation( + createSchemaRegionHandler.putNodeLocation( schemaRegionCreateTask.getRegionId().getId(), schemaRegionCreateTask.getTargetDataNode()); } - AsyncDataNodeClientPool.getInstance() - .sendAsyncRequestToDataNodeWithRetry(createSchemaRegionHandler); + CnToDnInternalServiceAsyncRequestManager.getInstance() + .sendAsyncRequestWithRetry(createSchemaRegionHandler); for (Map.Entry entry : createSchemaRegionHandler.getResponseMap().entrySet()) { @@ -1300,9 +1300,10 @@ public void maintainRegionReplicas() { break; case DataRegion: // Create DataRegion - AsyncClientHandler + DataNodeAsyncRequestContext createDataRegionHandler = - new AsyncClientHandler<>(DataNodeRequestType.CREATE_DATA_REGION); + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.CREATE_DATA_REGION); for (RegionMaintainTask regionMaintainTask : selectedRegionMaintainTask) { RegionCreateTask dataRegionCreateTask = (RegionCreateTask) regionMaintainTask; @@ -1315,13 +1316,13 @@ public void maintainRegionReplicas() { new TCreateDataRegionReq( dataRegionCreateTask.getRegionReplicaSet(), dataRegionCreateTask.getStorageGroup())); - createDataRegionHandler.putDataNodeLocation( + createDataRegionHandler.putNodeLocation( dataRegionCreateTask.getRegionId().getId(), dataRegionCreateTask.getTargetDataNode()); } - AsyncDataNodeClientPool.getInstance() - .sendAsyncRequestToDataNodeWithRetry(createDataRegionHandler); + CnToDnInternalServiceAsyncRequestManager.getInstance() + .sendAsyncRequestWithRetry(createDataRegionHandler); for (Map.Entry entry : createDataRegionHandler.getResponseMap().entrySet()) { @@ -1337,8 +1338,8 @@ public void maintainRegionReplicas() { break; case DELETE: // delete region - AsyncClientHandler deleteRegionHandler = - new AsyncClientHandler<>(DataNodeRequestType.DELETE_REGION); + DataNodeAsyncRequestContext deleteRegionHandler = + new DataNodeAsyncRequestContext<>(CnToDnRequestType.DELETE_REGION); Map regionIdMap = new HashMap<>(); for (RegionMaintainTask regionMaintainTask : selectedRegionMaintainTask) { RegionDeleteTask regionDeleteTask = (RegionDeleteTask) regionMaintainTask; @@ -1348,7 +1349,7 @@ public void maintainRegionReplicas() { regionDeleteTask.getTargetDataNode()); deleteRegionHandler.putRequest( regionDeleteTask.getRegionId().getId(), regionDeleteTask.getRegionId()); - deleteRegionHandler.putDataNodeLocation( + deleteRegionHandler.putNodeLocation( regionDeleteTask.getRegionId().getId(), regionDeleteTask.getTargetDataNode()); regionIdMap.put( @@ -1356,8 +1357,8 @@ public void maintainRegionReplicas() { } long startTime = System.currentTimeMillis(); - AsyncDataNodeClientPool.getInstance() - .sendAsyncRequestToDataNodeWithRetry(deleteRegionHandler); + CnToDnInternalServiceAsyncRequestManager.getInstance() + .sendAsyncRequestWithRetry(deleteRegionHandler); LOGGER.info( "Deleting regions costs {}ms", (System.currentTimeMillis() - startTime)); diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/agent/task/PipeConfigNodeTaskAgent.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/agent/task/PipeConfigNodeTaskAgent.java index fb8507be9d401..abfea097dbffa 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/agent/task/PipeConfigNodeTaskAgent.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/agent/task/PipeConfigNodeTaskAgent.java @@ -64,6 +64,16 @@ protected boolean isShutdown() { return PipeConfigNodeAgent.runtime().isShutdown(); } + @Override + protected void thawRate(final String pipeName, final long creationTime) { + PipeConfigNodeRemainingTimeMetrics.getInstance().thawRate(pipeName + "_" + creationTime); + } + + @Override + protected void freezeRate(final String pipeName, final long creationTime) { + PipeConfigNodeRemainingTimeMetrics.getInstance().freezeRate(pipeName + "_" + creationTime); + } + @Override protected Map buildPipeTasks(final PipeMeta pipeMetaFromConfigNode) throws IllegalPathException { diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/connector/protocol/IoTDBConfigRegionAirGapConnector.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/connector/protocol/IoTDBConfigRegionAirGapConnector.java index 9ea34939864c6..1c5febcb4bf51 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/connector/protocol/IoTDBConfigRegionAirGapConnector.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/connector/protocol/IoTDBConfigRegionAirGapConnector.java @@ -151,6 +151,7 @@ private void doTransfer( throws PipeException, IOException { if (!send( pipeConfigRegionWritePlanEvent.getPipeName(), + pipeConfigRegionWritePlanEvent.getCreationTime(), socket, PipeTransferConfigPlanReq.toTPipeTransferBytes( pipeConfigRegionWritePlanEvent.getConfigPhysicalPlan()))) { @@ -189,17 +190,19 @@ private void doTransfer( final AirGapSocket socket, final PipeConfigRegionSnapshotEvent pipeConfigRegionSnapshotEvent) throws PipeException, IOException { final String pipeName = pipeConfigRegionSnapshotEvent.getPipeName(); + final long creationTime = pipeConfigRegionSnapshotEvent.getCreationTime(); final File snapshot = pipeConfigRegionSnapshotEvent.getSnapshotFile(); final File templateFile = pipeConfigRegionSnapshotEvent.getTemplateFile(); // 1. Transfer snapshotFile, and template file if exists - transferFilePieces(pipeName, snapshot, socket, true); + transferFilePieces(pipeName, creationTime, snapshot, socket, true); if (Objects.nonNull(templateFile)) { - transferFilePieces(pipeName, templateFile, socket, true); + transferFilePieces(pipeName, creationTime, templateFile, socket, true); } // 2. Transfer file seal signal, which means the snapshots are transferred completely if (!send( pipeName, + creationTime, socket, PipeTransferConfigSnapshotSealReq.toTPipeTransferBytes( // The pattern is surely Non-null diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/connector/protocol/IoTDBConfigRegionConnector.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/connector/protocol/IoTDBConfigRegionConnector.java index 00279bf22d9f6..25fc9de720a37 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/connector/protocol/IoTDBConfigRegionConnector.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/connector/protocol/IoTDBConfigRegionConnector.java @@ -130,6 +130,7 @@ private void doTransfer(final PipeConfigRegionWritePlanEvent pipeConfigRegionWri pipeConfigRegionWritePlanEvent.getConfigPhysicalPlan())); rateLimitIfNeeded( pipeConfigRegionWritePlanEvent.getPipeName(), + pipeConfigRegionWritePlanEvent.getCreationTime(), clientAndStatus.getLeft().getEndPoint(), req.getBody().length); resp = clientAndStatus.getLeft().pipeTransfer(req); @@ -181,14 +182,15 @@ private void doTransferWrapper(final PipeConfigRegionSnapshotEvent pipeConfigReg private void doTransfer(final PipeConfigRegionSnapshotEvent snapshotEvent) throws PipeException, IOException { final String pipeName = snapshotEvent.getPipeName(); + final long creationTime = snapshotEvent.getCreationTime(); final File snapshotFile = snapshotEvent.getSnapshotFile(); final File templateFile = snapshotEvent.getTemplateFile(); final Pair clientAndStatus = clientManager.getClient(); // 1. Transfer snapshotFile, and template File if exists - transferFilePieces(pipeName, snapshotFile, clientAndStatus, true); + transferFilePieces(pipeName, creationTime, snapshotFile, clientAndStatus, true); if (Objects.nonNull(templateFile)) { - transferFilePieces(pipeName, templateFile, clientAndStatus, true); + transferFilePieces(pipeName, creationTime, templateFile, clientAndStatus, true); } // 2. Transfer file seal signal, which means the snapshots are transferred completely final TPipeTransferResp resp; @@ -206,6 +208,7 @@ private void doTransfer(final PipeConfigRegionSnapshotEvent snapshotEvent) snapshotEvent.toSealTypeString())); rateLimitIfNeeded( snapshotEvent.getPipeName(), + snapshotEvent.getCreationTime(), clientAndStatus.getLeft().getEndPoint(), req.getBody().length); resp = clientAndStatus.getLeft().pipeTransfer(req); diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/coordinator/runtime/heartbeat/PipeHeartbeatScheduler.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/coordinator/runtime/heartbeat/PipeHeartbeatScheduler.java index ad691ea856576..b21fbc815f98c 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/coordinator/runtime/heartbeat/PipeHeartbeatScheduler.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/coordinator/runtime/heartbeat/PipeHeartbeatScheduler.java @@ -24,9 +24,9 @@ import org.apache.iotdb.commons.concurrent.ThreadName; import org.apache.iotdb.commons.concurrent.threadpool.ScheduledExecutorUtil; import org.apache.iotdb.commons.pipe.config.PipeConfig; -import org.apache.iotdb.confignode.client.DataNodeRequestType; -import org.apache.iotdb.confignode.client.async.AsyncDataNodeClientPool; -import org.apache.iotdb.confignode.client.async.handlers.AsyncClientHandler; +import org.apache.iotdb.confignode.client.CnToDnRequestType; +import org.apache.iotdb.confignode.client.async.CnToDnInternalServiceAsyncRequestManager; +import org.apache.iotdb.confignode.client.async.handlers.DataNodeAsyncRequestContext; import org.apache.iotdb.confignode.conf.ConfigNodeDescriptor; import org.apache.iotdb.confignode.manager.ConfigManager; import org.apache.iotdb.confignode.manager.pipe.agent.PipeConfigNodeAgent; @@ -94,10 +94,11 @@ private synchronized void heartbeat() { final TPipeHeartbeatReq request = new TPipeHeartbeatReq(System.currentTimeMillis()); LOGGER.info("Collecting pipe heartbeat {} from data nodes", request.heartbeatId); - final AsyncClientHandler clientHandler = - new AsyncClientHandler<>(DataNodeRequestType.PIPE_HEARTBEAT, request, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance() - .sendAsyncRequestToDataNodeWithRetryAndTimeoutInMs( + final DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.PIPE_HEARTBEAT, request, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance() + .sendAsyncRequestToNodeWithRetryAndTimeoutInMs( clientHandler, PipeConfig.getInstance().getPipeHeartbeatIntervalSecondsForCollectingPipeMeta() * 1000L diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/event/PipeConfigRegionSnapshotEvent.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/event/PipeConfigRegionSnapshotEvent.java index dcdc0f8f81d9c..56c9d012c3ca4 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/event/PipeConfigRegionSnapshotEvent.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/event/PipeConfigRegionSnapshotEvent.java @@ -90,7 +90,7 @@ public PipeConfigRegionSnapshotEvent() { public PipeConfigRegionSnapshotEvent( final String snapshotPath, final String templateFilePath, final CNSnapshotFileType type) { - this(snapshotPath, templateFilePath, type, null, null, null); + this(snapshotPath, templateFilePath, type, null, 0, null, null); } public PipeConfigRegionSnapshotEvent( @@ -98,9 +98,15 @@ public PipeConfigRegionSnapshotEvent( final String templateFilePath, final CNSnapshotFileType type, final String pipeName, + final long creationTime, final PipeTaskMeta pipeTaskMeta, final PipePattern pattern) { - super(pipeName, pipeTaskMeta, pattern, PipeConfigNodeSnapshotResourceManager.getInstance()); + super( + pipeName, + creationTime, + pipeTaskMeta, + pattern, + PipeConfigNodeSnapshotResourceManager.getInstance()); this.snapshotPath = snapshotPath; this.templateFilePath = Objects.nonNull(templateFilePath) ? templateFilePath : ""; this.fileType = type; @@ -157,12 +163,13 @@ public boolean internallyDecreaseResourceReferenceCount(final String holderMessa @Override public EnrichedEvent shallowCopySelfAndBindPipeTaskMetaForProgressReport( final String pipeName, + final long creationTime, final PipeTaskMeta pipeTaskMeta, final PipePattern pattern, final long startTime, final long endTime) { return new PipeConfigRegionSnapshotEvent( - snapshotPath, templateFilePath, fileType, pipeName, pipeTaskMeta, pattern); + snapshotPath, templateFilePath, fileType, pipeName, creationTime, pipeTaskMeta, pattern); } @Override diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/event/PipeConfigRegionWritePlanEvent.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/event/PipeConfigRegionWritePlanEvent.java index c699690746056..0d780bafca1e5 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/event/PipeConfigRegionWritePlanEvent.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/event/PipeConfigRegionWritePlanEvent.java @@ -41,16 +41,17 @@ public PipeConfigRegionWritePlanEvent() { public PipeConfigRegionWritePlanEvent( final ConfigPhysicalPlan configPhysicalPlan, final boolean isGeneratedByPipe) { - this(configPhysicalPlan, null, null, null, isGeneratedByPipe); + this(configPhysicalPlan, null, 0, null, null, isGeneratedByPipe); } public PipeConfigRegionWritePlanEvent( final ConfigPhysicalPlan configPhysicalPlan, final String pipeName, + final long creationTime, final PipeTaskMeta pipeTaskMeta, final PipePattern pattern, final boolean isGeneratedByPipe) { - super(pipeName, pipeTaskMeta, pattern, isGeneratedByPipe); + super(pipeName, creationTime, pipeTaskMeta, pattern, isGeneratedByPipe); this.configPhysicalPlan = configPhysicalPlan; } @@ -61,12 +62,13 @@ public ConfigPhysicalPlan getConfigPhysicalPlan() { @Override public EnrichedEvent shallowCopySelfAndBindPipeTaskMetaForProgressReport( final String pipeName, + final long creationTime, final PipeTaskMeta pipeTaskMeta, final PipePattern pattern, final long startTime, final long endTime) { return new PipeConfigRegionWritePlanEvent( - configPhysicalPlan, pipeName, pipeTaskMeta, pattern, false); + configPhysicalPlan, pipeName, creationTime, pipeTaskMeta, pattern, false); } @Override diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/execution/PipeConfigNodeSubtaskExecutor.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/execution/PipeConfigNodeSubtaskExecutor.java index 9a82e72ece3d7..6041c5bf82da8 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/execution/PipeConfigNodeSubtaskExecutor.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/execution/PipeConfigNodeSubtaskExecutor.java @@ -28,15 +28,15 @@ public class PipeConfigNodeSubtaskExecutor extends PipeSubtaskExecutor { private static final int THREAD_NUM = 1; private PipeConfigNodeSubtaskExecutor() { - super(THREAD_NUM, ThreadName.PIPE_CONFIGNODE_EXECUTOR_POOL); + super(THREAD_NUM, ThreadName.PIPE_CONFIGNODE_EXECUTOR_POOL, true); } /** * @param ignored Used to distinguish this constructor from the default constructor. */ @TestOnly - public PipeConfigNodeSubtaskExecutor(Object ignored) { - super(THREAD_NUM, ThreadName.PIPE_CONFIGNODE_EXECUTOR_POOL); + public PipeConfigNodeSubtaskExecutor(final Object ignored) { + super(THREAD_NUM, ThreadName.PIPE_CONFIGNODE_EXECUTOR_POOL, true); } private static class PipeSchemaSubtaskExecutorHolder { diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/metric/PipeConfigNodeRemainingTimeMetrics.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/metric/PipeConfigNodeRemainingTimeMetrics.java index 378251eb45c2e..bf974744b21b6 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/metric/PipeConfigNodeRemainingTimeMetrics.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/metric/PipeConfigNodeRemainingTimeMetrics.java @@ -19,7 +19,6 @@ package org.apache.iotdb.confignode.manager.pipe.metric; -import org.apache.iotdb.commons.pipe.config.plugin.env.PipeTaskRuntimeEnvironment; import org.apache.iotdb.commons.pipe.progress.PipeEventCommitManager; import org.apache.iotdb.commons.service.metric.enums.Metric; import org.apache.iotdb.commons.service.metric.enums.Tag; @@ -110,6 +109,22 @@ public void register(final IoTDBConfigRegionExtractor extractor) { } } + public void thawRate(final String pipeID) { + if (!remainingTimeOperatorMap.containsKey(pipeID)) { + // The configNode may have no pipe task after "startPipe" + return; + } + remainingTimeOperatorMap.get(pipeID).thawRate(true); + } + + public void freezeRate(final String pipeID) { + if (!remainingTimeOperatorMap.containsKey(pipeID)) { + // The configNode may have no pipe task after "stopPipe" + return; + } + remainingTimeOperatorMap.get(pipeID).freezeRate(true); + } + public void deregister(final String pipeID) { if (!remainingTimeOperatorMap.containsKey(pipeID)) { LOGGER.warn( @@ -122,27 +137,16 @@ public void deregister(final String pipeID) { } } - public void markRegionCommit(final PipeTaskRuntimeEnvironment pipeTaskRuntimeEnvironment) { - // Filter commit attempt from assigner - final String pipeName = pipeTaskRuntimeEnvironment.getPipeName(); - final long creationTime = pipeTaskRuntimeEnvironment.getCreationTime(); - final String pipeID = pipeName + "_" + creationTime; - + public void markRegionCommit(final String pipeID, final boolean isDataRegion) { if (Objects.isNull(metricService)) { return; } final PipeConfigNodeRemainingTimeOperator operator = remainingTimeOperatorMap.get(pipeID); if (Objects.isNull(operator)) { - LOGGER.warn( + LOGGER.info( "Failed to mark pipe region commit, RemainingTimeOperator({}) does not exist", pipeID); return; } - // Prevent not set pipeName / creation times & potential differences between pipeNames and - // creation times - if (!Objects.equals(pipeName, operator.getPipeName()) - || !Objects.equals(creationTime, operator.getCreationTime())) { - return; - } operator.markConfigRegionCommit(); } diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/metric/PipeConfigNodeRemainingTimeOperator.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/metric/PipeConfigNodeRemainingTimeOperator.java index 201aa775de5e2..7a5044b0c6162 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/metric/PipeConfigNodeRemainingTimeOperator.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/metric/PipeConfigNodeRemainingTimeOperator.java @@ -19,77 +19,72 @@ package org.apache.iotdb.confignode.manager.pipe.metric; +import org.apache.iotdb.commons.enums.PipeRemainingTimeRateAverageTime; import org.apache.iotdb.commons.pipe.config.PipeConfig; +import org.apache.iotdb.commons.pipe.metric.PipeRemainingOperator; +import org.apache.iotdb.confignode.manager.pipe.execution.PipeConfigNodeSubtask; import org.apache.iotdb.confignode.manager.pipe.extractor.IoTDBConfigRegionExtractor; import com.codahale.metrics.Clock; import com.codahale.metrics.ExponentialMovingAverages; import com.codahale.metrics.Meter; +import java.util.Collections; +import java.util.Objects; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.atomic.AtomicReference; -class PipeConfigNodeRemainingTimeOperator { +class PipeConfigNodeRemainingTimeOperator extends PipeRemainingOperator { - private static final long CONFIG_NODE_REMAINING_MAX_SECONDS = 365 * 24 * 60 * 60L; // 1 year + private final Set configRegionExtractors = + Collections.newSetFromMap(new ConcurrentHashMap<>()); + private final AtomicReference configRegionCommitMeter = new AtomicReference<>(null); - private String pipeName; - private long creationTime = 0; - - private final ConcurrentMap - configRegionExtractors = new ConcurrentHashMap<>(); - private final Meter configRegionCommitMeter = - new Meter(new ExponentialMovingAverages(), Clock.defaultClock()); - - private double lastConfigRegionCommitSmoothingValue = Long.MIN_VALUE; - - //////////////////////////// Tags //////////////////////////// - - String getPipeName() { - return pipeName; - } - - long getCreationTime() { - return creationTime; - } + private double lastConfigRegionCommitSmoothingValue = Long.MAX_VALUE; //////////////////////////// Remaining time calculation //////////////////////////// /** - * This will calculate the estimated remaining time of the given pipe's config region subTask. + * This will calculate the estimated remaining time of the given pipe's {@link + * PipeConfigNodeSubtask}. * * @return The estimated remaining time */ double getRemainingTime() { - final double pipeRemainingTimeCommitRateSmoothingFactor = - PipeConfig.getInstance().getPipeRemainingTimeCommitRateSmoothingFactor(); + final PipeRemainingTimeRateAverageTime pipeRemainingTimeCommitRateAverageTime = + PipeConfig.getInstance().getPipeRemainingTimeCommitRateAverageTime(); // Do not calculate heartbeat event final long totalConfigRegionWriteEventCount = - configRegionExtractors.keySet().stream() + configRegionExtractors.stream() .map(IoTDBConfigRegionExtractor::getUnTransferredEventCount) .reduce(Long::sum) .orElse(0L); - lastConfigRegionCommitSmoothingValue = - lastConfigRegionCommitSmoothingValue == Long.MIN_VALUE - ? configRegionCommitMeter.getOneMinuteRate() - : pipeRemainingTimeCommitRateSmoothingFactor - * configRegionCommitMeter.getOneMinuteRate() - + (1 - pipeRemainingTimeCommitRateSmoothingFactor) - * lastConfigRegionCommitSmoothingValue; + configRegionCommitMeter.updateAndGet( + meter -> { + if (Objects.nonNull(meter)) { + lastConfigRegionCommitSmoothingValue = + pipeRemainingTimeCommitRateAverageTime.getMeterRate(meter); + } + return meter; + }); + final double configRegionRemainingTime; if (totalConfigRegionWriteEventCount <= 0) { + notifyEmpty(); configRegionRemainingTime = 0; } else { + notifyNonEmpty(); configRegionRemainingTime = lastConfigRegionCommitSmoothingValue <= 0 ? Double.MAX_VALUE : totalConfigRegionWriteEventCount / lastConfigRegionCommitSmoothingValue; } - return configRegionRemainingTime >= CONFIG_NODE_REMAINING_MAX_SECONDS - ? CONFIG_NODE_REMAINING_MAX_SECONDS + return configRegionRemainingTime >= REMAINING_MAX_SECONDS + ? REMAINING_MAX_SECONDS : configRegionRemainingTime; } @@ -97,17 +92,37 @@ long getCreationTime() { void register(final IoTDBConfigRegionExtractor extractor) { setNameAndCreationTime(extractor.getPipeName(), extractor.getCreationTime()); - configRegionExtractors.put(extractor, extractor); - } - - private void setNameAndCreationTime(final String pipeName, final long creationTime) { - this.pipeName = pipeName; - this.creationTime = creationTime; + configRegionExtractors.add(extractor); } //////////////////////////// Rate //////////////////////////// void markConfigRegionCommit() { - configRegionCommitMeter.mark(); + configRegionCommitMeter.updateAndGet( + meter -> { + if (Objects.nonNull(meter)) { + meter.mark(); + } + return meter; + }); + } + + //////////////////////////// Switch //////////////////////////// + + @Override + public synchronized void thawRate(final boolean isStartPipe) { + super.thawRate(isStartPipe); + // The stopped pipe's rate should only be thawed by "startPipe" command + if (isStopped) { + return; + } + configRegionCommitMeter.compareAndSet( + null, new Meter(new ExponentialMovingAverages(), Clock.defaultClock())); + } + + @Override + public synchronized void freezeRate(final boolean isStopPipe) { + super.freezeRate(isStopPipe); + configRegionCommitMeter.set(null); } } diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/metric/PipeConfigRegionConnectorMetrics.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/metric/PipeConfigRegionConnectorMetrics.java index 01d9b4bb4d33e..0900d9d4628be 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/metric/PipeConfigRegionConnectorMetrics.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/metric/PipeConfigRegionConnectorMetrics.java @@ -127,7 +127,7 @@ public void markConfigEvent(final String taskID) { } final Rate rate = configRateMap.get(taskID); if (rate == null) { - LOGGER.warn( + LOGGER.info( "Failed to mark pipe config region write plan event, PipeConfigNodeSubtask({}) does not exist", taskID); return; diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/task/PipeConfigNodeTaskStage.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/task/PipeConfigNodeTaskStage.java index 36eec65b69e82..7e676903857ea 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/task/PipeConfigNodeTaskStage.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/pipe/task/PipeConfigNodeTaskStage.java @@ -32,12 +32,12 @@ public class PipeConfigNodeTaskStage extends PipeTaskStage { private final PipeConfigNodeSubtask subtask; public PipeConfigNodeTaskStage( - String pipeName, - long creationTime, - Map extractorAttributes, - Map processorAttributes, - Map connectorAttributes, - PipeTaskMeta pipeTaskMeta) { + final String pipeName, + final long creationTime, + final Map extractorAttributes, + final Map processorAttributes, + final Map connectorAttributes, + final PipeTaskMeta pipeTaskMeta) { try { subtask = @@ -48,7 +48,7 @@ public PipeConfigNodeTaskStage( processorAttributes, connectorAttributes, pipeTaskMeta); - } catch (Exception e) { + } catch (final Exception e) { throw new PipeException( String.format( "Failed to create subtask for pipe %s, creation time %d", pipeName, creationTime), @@ -63,8 +63,6 @@ public void createSubtask() throws PipeException { @Override public void startSubtask() throws PipeException { - // IoTDBConfigRegionExtractor is started by executor because starting - // here may cause deadlock when triggering snapshot PipeConfigNodeSubtaskExecutor.getInstance().start(subtask.getTaskID()); } diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/schema/ClusterSchemaManager.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/schema/ClusterSchemaManager.java index 4425a469dfa04..e7787c8ad80e7 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/schema/ClusterSchemaManager.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/schema/ClusterSchemaManager.java @@ -35,9 +35,9 @@ import org.apache.iotdb.commons.utils.CommonDateTimeUtils; import org.apache.iotdb.commons.utils.PathUtils; import org.apache.iotdb.commons.utils.StatusUtils; -import org.apache.iotdb.confignode.client.DataNodeRequestType; -import org.apache.iotdb.confignode.client.async.AsyncDataNodeClientPool; -import org.apache.iotdb.confignode.client.async.handlers.AsyncClientHandler; +import org.apache.iotdb.confignode.client.CnToDnRequestType; +import org.apache.iotdb.confignode.client.async.CnToDnInternalServiceAsyncRequestManager; +import org.apache.iotdb.confignode.client.async.handlers.DataNodeAsyncRequestContext; import org.apache.iotdb.confignode.conf.ConfigNodeConfig; import org.apache.iotdb.confignode.conf.ConfigNodeDescriptor; import org.apache.iotdb.confignode.consensus.request.read.database.CountDatabasePlan; @@ -1044,10 +1044,10 @@ public synchronized TSStatus extendSchemaTemplate( Map dataNodeLocationMap = configManager.getNodeManager().getRegisteredDataNodeLocations(); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.UPDATE_TEMPLATE, updateTemplateReq, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.UPDATE_TEMPLATE, updateTemplateReq, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); Map statusMap = clientHandler.getResponseMap(); for (Map.Entry entry : statusMap.entrySet()) { if (entry.getValue().getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/ProcedureInfo.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/ProcedureInfo.java index 44be0571e28f5..0f6b55f74998b 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/ProcedureInfo.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/ProcedureInfo.java @@ -135,7 +135,7 @@ public void upgrade() { public TSStatus updateProcedure(UpdateProcedurePlan updateProcedurePlan) { Procedure procedure = updateProcedurePlan.getProcedure(); procedureMap.put(procedure.getProcId(), procedure); - lastProcId.set(Math.max(lastProcId.get(), procedure.getProcId())); + lastProcId.updateAndGet(id -> Math.max(id, procedure.getProcId())); return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()); } diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/TTLInfo.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/TTLInfo.java index 539a6ac0ffe3b..4cb75bcec4f41 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/TTLInfo.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/TTLInfo.java @@ -27,6 +27,7 @@ import org.apache.iotdb.commons.snapshot.SnapshotProcessor; import org.apache.iotdb.commons.utils.PathUtils; import org.apache.iotdb.commons.utils.TestOnly; +import org.apache.iotdb.confignode.consensus.request.read.ttl.ShowTTLPlan; import org.apache.iotdb.confignode.consensus.request.write.database.SetTTLPlan; import org.apache.iotdb.confignode.consensus.response.ttl.ShowTTLResp; import org.apache.iotdb.rpc.RpcUtils; @@ -43,6 +44,7 @@ import java.io.FileOutputStream; import java.io.IOException; import java.util.Arrays; +import java.util.HashMap; import java.util.Map; import java.util.concurrent.locks.ReadWriteLock; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -118,12 +120,19 @@ public TSStatus unsetTTL(SetTTLPlan plan) { return RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS); } - public ShowTTLResp showAllTTL() { + public ShowTTLResp showTTL(ShowTTLPlan plan) { ShowTTLResp resp = new ShowTTLResp(); - Map pathTTLMap; + Map pathTTLMap = new HashMap<>(); lock.readLock().lock(); try { - pathTTLMap = ttlCache.getAllPathTTL(); + PartialPath pathPattern = new PartialPath(plan.getPathPattern()); + for (Map.Entry entry : ttlCache.getAllTTLs().entrySet()) { + if (pathPattern.matchFullPath(entry.getKey())) { + pathTTLMap.put( + String.join(String.valueOf(IoTDBConstant.PATH_SEPARATOR), entry.getKey()), + entry.getValue()); + } + } } finally { lock.readLock().unlock(); } @@ -175,6 +184,8 @@ public void processLoadSnapshot(File snapshotDir) throws TException, IOException BufferedInputStream bufferedInputStream = new BufferedInputStream(fileInputStream)) { ttlCache.clear(); ttlCache.deserialize(bufferedInputStream); + } catch (IllegalPathException e) { + throw new IOException(e); } finally { lock.writeLock().unlock(); } @@ -190,7 +201,9 @@ public boolean equals(Object o) { } TTLInfo other = (TTLInfo) o; return this.getTTLCount() == other.getTTLCount() - && this.showAllTTL().getPathTTLMap().equals(other.showAllTTL().getPathTTLMap()); + && this.showTTL(new ShowTTLPlan()) + .getPathTTLMap() + .equals(other.showTTL(new ShowTTLPlan()).getPathTTLMap()); } @TestOnly diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java index 5d258d2b1a51d..a5a81c99905e4 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/executor/ConfigPlanExecutor.java @@ -48,6 +48,7 @@ import org.apache.iotdb.confignode.consensus.request.read.trigger.GetTriggerJarPlan; import org.apache.iotdb.confignode.consensus.request.read.trigger.GetTriggerLocationPlan; import org.apache.iotdb.confignode.consensus.request.read.trigger.GetTriggerTablePlan; +import org.apache.iotdb.confignode.consensus.request.read.ttl.ShowTTLPlan; import org.apache.iotdb.confignode.consensus.request.write.confignode.ApplyConfigNodePlan; import org.apache.iotdb.confignode.consensus.request.write.confignode.RemoveConfigNodePlan; import org.apache.iotdb.confignode.consensus.request.write.confignode.UpdateClusterIdPlan; @@ -314,7 +315,7 @@ public DataSet executeQueryPlan(ConfigPhysicalPlan req) case ShowPipeV2: return pipeInfo.getPipeTaskInfo().showPipes(); case ShowTTL: - return ttlInfo.showAllTTL(); + return ttlInfo.showTTL((ShowTTLPlan) req); case ShowTopic: return subscriptionInfo.showTopics(); case ShowSubscription: diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/CNPhysicalPlanGenerator.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/CNPhysicalPlanGenerator.java index 1658de401ce64..f8895158afce6 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/CNPhysicalPlanGenerator.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/schema/CNPhysicalPlanGenerator.java @@ -25,6 +25,7 @@ import org.apache.iotdb.commons.schema.node.role.IDatabaseMNode; import org.apache.iotdb.commons.schema.node.utils.IMNodeFactory; import org.apache.iotdb.commons.utils.AuthUtils; +import org.apache.iotdb.commons.utils.PathUtils; import org.apache.iotdb.commons.utils.ThriftConfigNodeSerDeUtils; import org.apache.iotdb.confignode.consensus.request.ConfigPhysicalPlan; import org.apache.iotdb.confignode.consensus.request.ConfigPhysicalPlanType; @@ -38,7 +39,6 @@ import org.apache.iotdb.db.schemaengine.template.Template; import org.apache.commons.io.IOUtils; -import org.apache.tsfile.common.constant.TsFileConstant; import org.apache.tsfile.utils.Pair; import org.apache.tsfile.utils.ReadWriteIOUtils; import org.slf4j.Logger; @@ -60,7 +60,6 @@ import java.util.Iterator; import java.util.List; import java.util.NoSuchElementException; -import java.util.Objects; import java.util.Stack; import static org.apache.iotdb.commons.conf.IoTDBConstant.PATH_ROOT; @@ -277,13 +276,11 @@ private void generateSetTTLPlan() { while (size > 0) { String path = ReadWriteIOUtils.readString(ttlInputStream); long ttl = ReadWriteIOUtils.readLong(ttlInputStream); - planDeque.add( - new SetTTLPlan( - Objects.requireNonNull(path).split(TsFileConstant.PATH_SEPARATER_NO_REGEX), ttl)); + planDeque.add(new SetTTLPlan(PathUtils.splitPathToDetachedNodes(path), ttl)); size--; } - } catch (IOException e) { - logger.error("Got IOException when deserializing ttl file", e); + } catch (IOException | IllegalPathException e) { + logger.error("Got exception when deserializing ttl file", e); latestException = e; } } diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/env/ConfigNodeProcedureEnv.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/env/ConfigNodeProcedureEnv.java index 00d9569c6593c..c2040a05328a5 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/env/ConfigNodeProcedureEnv.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/env/ConfigNodeProcedureEnv.java @@ -32,10 +32,10 @@ import org.apache.iotdb.commons.pipe.config.PipeConfig; import org.apache.iotdb.commons.pipe.plugin.meta.PipePluginMeta; import org.apache.iotdb.commons.trigger.TriggerInformation; -import org.apache.iotdb.confignode.client.ConfigNodeRequestType; -import org.apache.iotdb.confignode.client.DataNodeRequestType; -import org.apache.iotdb.confignode.client.async.AsyncDataNodeClientPool; -import org.apache.iotdb.confignode.client.async.handlers.AsyncClientHandler; +import org.apache.iotdb.confignode.client.CnToCnNodeRequestType; +import org.apache.iotdb.confignode.client.CnToDnRequestType; +import org.apache.iotdb.confignode.client.async.CnToDnInternalServiceAsyncRequestManager; +import org.apache.iotdb.confignode.client.async.handlers.DataNodeAsyncRequestContext; import org.apache.iotdb.confignode.client.sync.SyncConfigNodeClientPool; import org.apache.iotdb.confignode.client.sync.SyncDataNodeClientPool; import org.apache.iotdb.confignode.consensus.request.write.confignode.RemoveConfigNodePlan; @@ -186,7 +186,7 @@ public boolean invalidateCache(String storageGroupName) throws IOException, TExc .sendSyncRequestToDataNodeWithRetry( dataNodeConfiguration.getLocation().getInternalEndPoint(), invalidateCacheReq, - DataNodeRequestType.INVALIDATE_PARTITION_CACHE); + CnToDnRequestType.INVALIDATE_PARTITION_CACHE); final TSStatus invalidateSchemaStatus = (TSStatus) @@ -194,7 +194,7 @@ public boolean invalidateCache(String storageGroupName) throws IOException, TExc .sendSyncRequestToDataNodeWithRetry( dataNodeConfiguration.getLocation().getInternalEndPoint(), invalidateCacheReq, - DataNodeRequestType.INVALIDATE_SCHEMA_CACHE); + CnToDnRequestType.INVALIDATE_SCHEMA_CACHE); if (!verifySucceed(invalidatePartitionStatus, invalidateSchemaStatus)) { LOG.error( @@ -251,7 +251,7 @@ public void addConsensusGroup(TConfigNodeLocation tConfigNodeLocation) .sendSyncRequestToConfigNodeWithRetry( tConfigNodeLocation.getInternalEndPoint(), new TAddConsensusGroupReq(configNodeLocations), - ConfigNodeRequestType.ADD_CONSENSUS_GROUP); + CnToCnNodeRequestType.ADD_CONSENSUS_GROUP); if (status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { throw new AddConsensusGroupException(tConfigNodeLocation); } @@ -315,7 +315,7 @@ public void deleteConfigNodePeer(TConfigNodeLocation removedConfigNode) .sendSyncRequestToConfigNodeWithRetry( removedConfigNode.getInternalEndPoint(), removedConfigNode, - ConfigNodeRequestType.DELETE_CONFIG_NODE_PEER); + CnToCnNodeRequestType.DELETE_CONFIG_NODE_PEER); if (tsStatus.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { throw new ProcedureException(tsStatus.getMessage()); } @@ -334,7 +334,7 @@ public void stopConfigNode(TConfigNodeLocation tConfigNodeLocation) throws Proce .sendSyncRequestToConfigNodeWithRetry( tConfigNodeLocation.getInternalEndPoint(), tConfigNodeLocation, - ConfigNodeRequestType.STOP_CONFIG_NODE); + CnToCnNodeRequestType.STOP_CONFIG_NODE); if (tsStatus.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { throw new ProcedureException(tsStatus.getMessage()); @@ -364,7 +364,7 @@ public void notifyRegisterSuccess(TConfigNodeLocation configNodeLocation) { .sendSyncRequestToConfigNodeWithRetry( configNodeLocation.getInternalEndPoint(), null, - ConfigNodeRequestType.NOTIFY_REGISTER_SUCCESS); + CnToCnNodeRequestType.NOTIFY_REGISTER_SUCCESS); } /** @@ -389,14 +389,14 @@ public void markDataNodeAsRemovingAndBroadcast(TDataNodeLocation dataNodeLocatio .sendSyncRequestToDataNodeWithGivenRetry( dataNodeLocation.getInternalEndPoint(), NodeStatus.Removing.getStatus(), - DataNodeRequestType.SET_SYSTEM_STATUS, + CnToDnRequestType.SET_SYSTEM_STATUS, 1); } else { SyncDataNodeClientPool.getInstance() .sendSyncRequestToDataNodeWithRetry( dataNodeLocation.getInternalEndPoint(), NodeStatus.Removing.getStatus(), - DataNodeRequestType.SET_SYSTEM_STATUS); + CnToDnRequestType.SET_SYSTEM_STATUS); } long currentTime = System.nanoTime(); @@ -430,7 +430,7 @@ public Map doRegionCreation( TConsensusGroupType consensusGroupType, CreateRegionGroupsPlan createRegionGroupsPlan) { // Prepare clientHandler - AsyncClientHandler clientHandler; + DataNodeAsyncRequestContext clientHandler; switch (consensusGroupType) { case SchemaRegion: clientHandler = getCreateSchemaRegionClientHandler(createRegionGroupsPlan); @@ -445,7 +445,7 @@ public Map doRegionCreation( } // Send CreateRegion requests to DataNodes - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); // Filter RegionGroups that weren't created successfully int requestId = 0; @@ -469,10 +469,10 @@ public Map doRegionCreation( return failedRegions; } - private AsyncClientHandler getCreateSchemaRegionClientHandler( - CreateRegionGroupsPlan createRegionGroupsPlan) { - AsyncClientHandler clientHandler = - new AsyncClientHandler<>(DataNodeRequestType.CREATE_SCHEMA_REGION); + private DataNodeAsyncRequestContext + getCreateSchemaRegionClientHandler(CreateRegionGroupsPlan createRegionGroupsPlan) { + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>(CnToDnRequestType.CREATE_SCHEMA_REGION); int requestId = 0; for (Map.Entry> sgRegionsEntry : @@ -483,7 +483,7 @@ private AsyncClientHandler getCreateSchemaRegi for (TDataNodeLocation dataNodeLocation : regionReplicaSet.getDataNodeLocations()) { clientHandler.putRequest( requestId, genCreateSchemaRegionReq(storageGroup, regionReplicaSet)); - clientHandler.putDataNodeLocation(requestId, dataNodeLocation); + clientHandler.putNodeLocation(requestId, dataNodeLocation); requestId += 1; } } @@ -492,10 +492,10 @@ private AsyncClientHandler getCreateSchemaRegi return clientHandler; } - private AsyncClientHandler getCreateDataRegionClientHandler( - CreateRegionGroupsPlan createRegionGroupsPlan) { - AsyncClientHandler clientHandler = - new AsyncClientHandler<>(DataNodeRequestType.CREATE_DATA_REGION); + private DataNodeAsyncRequestContext + getCreateDataRegionClientHandler(CreateRegionGroupsPlan createRegionGroupsPlan) { + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>(CnToDnRequestType.CREATE_DATA_REGION); int requestId = 0; for (Map.Entry> sgRegionsEntry : @@ -506,7 +506,7 @@ private AsyncClientHandler getCreateDataRegionCl for (TDataNodeLocation dataNodeLocation : regionReplicaSet.getDataNodeLocations()) { clientHandler.putRequest( requestId, genCreateDataRegionReq(storageGroup, regionReplicaSet)); - clientHandler.putDataNodeLocation(requestId, dataNodeLocation); + clientHandler.putNodeLocation(requestId, dataNodeLocation); requestId += 1; } } @@ -588,10 +588,10 @@ public List createTriggerOnDataNodes( request.setJarFile(ByteBuffer.wrap(jarFile.getValues())); } - AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.CREATE_TRIGGER_INSTANCE, request, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.CREATE_TRIGGER_INSTANCE, request, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); return clientHandler.getResponseList(); } @@ -602,10 +602,10 @@ public List dropTriggerOnDataNodes(String triggerName, boolean needToD final TDropTriggerInstanceReq request = new TDropTriggerInstanceReq(triggerName, needToDeleteJarFile); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.DROP_TRIGGER_INSTANCE, request, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.DROP_TRIGGER_INSTANCE, request, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); return clientHandler.getResponseList(); } @@ -615,10 +615,10 @@ public List activeTriggerOnDataNodes(String triggerName) { nodeManager.getRegisteredDataNodeLocations(); final TActiveTriggerInstanceReq request = new TActiveTriggerInstanceReq(triggerName); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.ACTIVE_TRIGGER_INSTANCE, request, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.ACTIVE_TRIGGER_INSTANCE, request, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); return clientHandler.getResponseList(); } @@ -628,10 +628,10 @@ public List inactiveTriggerOnDataNodes(String triggerName) { nodeManager.getRegisteredDataNodeLocations(); final TInactiveTriggerInstanceReq request = new TInactiveTriggerInstanceReq(triggerName); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.INACTIVE_TRIGGER_INSTANCE, request, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.INACTIVE_TRIGGER_INSTANCE, request, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); return clientHandler.getResponseList(); } @@ -642,10 +642,10 @@ public List createPipePluginOnDataNodes(PipePluginMeta pipePluginMeta, final TCreatePipePluginInstanceReq request = new TCreatePipePluginInstanceReq(pipePluginMeta.serialize(), ByteBuffer.wrap(jarFile)); - final AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.CREATE_PIPE_PLUGIN, request, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + final DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.CREATE_PIPE_PLUGIN, request, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); return clientHandler.getResponseList(); } @@ -656,10 +656,10 @@ public List dropPipePluginOnDataNodes( final TDropPipePluginInstanceReq request = new TDropPipePluginInstanceReq(pipePluginName, needToDeleteJarFile); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.DROP_PIPE_PLUGIN, request, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.DROP_PIPE_PLUGIN, request, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); return clientHandler.getResponseList(); } @@ -669,11 +669,11 @@ public Map pushAllPipeMetaToDataNodes( configManager.getNodeManager().getRegisteredDataNodeLocations(); final TPushPipeMetaReq request = new TPushPipeMetaReq().setPipeMetas(pipeMetaBinaryList); - final AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.PIPE_PUSH_ALL_META, request, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance() - .sendAsyncRequestToDataNodeWithRetryAndTimeoutInMs( + final DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.PIPE_PUSH_ALL_META, request, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance() + .sendAsyncRequestToNodeWithRetryAndTimeoutInMs( clientHandler, PipeConfig.getInstance().getPipeMetaSyncerSyncIntervalMinutes() * 60 * 1000 * 2 / 3); return clientHandler.getResponseMap(); @@ -684,11 +684,11 @@ public Map pushSinglePipeMetaToDataNodes(ByteBuffer configManager.getNodeManager().getRegisteredDataNodeLocations(); final TPushSinglePipeMetaReq request = new TPushSinglePipeMetaReq().setPipeMeta(pipeMetaBinary); - final AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.PIPE_PUSH_SINGLE_META, request, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance() - .sendAsyncRequestToDataNodeWithRetryAndTimeoutInMs( + final DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.PIPE_PUSH_SINGLE_META, request, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance() + .sendAsyncRequestToNodeWithRetryAndTimeoutInMs( clientHandler, PipeConfig.getInstance().getPipeMetaSyncerSyncIntervalMinutes() * 60 * 1000 * 2 / 3); return clientHandler.getResponseMap(); @@ -700,11 +700,11 @@ public Map dropSinglePipeOnDataNodes(String pipeName final TPushSinglePipeMetaReq request = new TPushSinglePipeMetaReq().setPipeNameToDrop(pipeNameToDrop); - final AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.PIPE_PUSH_SINGLE_META, request, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance() - .sendAsyncRequestToDataNodeWithRetryAndTimeoutInMs( + final DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.PIPE_PUSH_SINGLE_META, request, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance() + .sendAsyncRequestToNodeWithRetryAndTimeoutInMs( clientHandler, PipeConfig.getInstance().getPipeMetaSyncerSyncIntervalMinutes() * 60 * 1000 * 2 / 3); return clientHandler.getResponseMap(); @@ -717,11 +717,11 @@ public Map pushMultiPipeMetaToDataNodes( final TPushMultiPipeMetaReq request = new TPushMultiPipeMetaReq().setPipeMetas(pipeMetaBinaryList); - final AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.PIPE_PUSH_MULTI_META, request, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance() - .sendAsyncRequestToDataNodeWithRetryAndTimeoutInMs( + final DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.PIPE_PUSH_MULTI_META, request, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance() + .sendAsyncRequestToNodeWithRetryAndTimeoutInMs( clientHandler, PipeConfig.getInstance().getPipeMetaSyncerSyncIntervalMinutes() * 60 * 1000 * 2 / 3); return clientHandler.getResponseMap(); @@ -733,11 +733,11 @@ public Map dropMultiPipeOnDataNodes(List pip final TPushMultiPipeMetaReq request = new TPushMultiPipeMetaReq().setPipeNamesToDrop(pipeNamesToDrop); - final AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.PIPE_PUSH_MULTI_META, request, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance() - .sendAsyncRequestToDataNodeWithRetryAndTimeoutInMs( + final DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.PIPE_PUSH_MULTI_META, request, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance() + .sendAsyncRequestToNodeWithRetryAndTimeoutInMs( clientHandler, PipeConfig.getInstance().getPipeMetaSyncerSyncIntervalMinutes() * 60 * 1000 * 2 / 3); return clientHandler.getResponseMap(); @@ -749,11 +749,11 @@ public Map pushAllTopicMetaToDataNodes( configManager.getNodeManager().getRegisteredDataNodeLocations(); final TPushTopicMetaReq request = new TPushTopicMetaReq().setTopicMetas(topicMetaBinaryList); - final AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.TOPIC_PUSH_ALL_META, request, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance() - .sendAsyncRequestToDataNodeWithRetryAndTimeoutInMs( + final DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.TOPIC_PUSH_ALL_META, request, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance() + .sendAsyncRequestToNodeWithRetryAndTimeoutInMs( clientHandler, PipeConfig.getInstance().getPipeMetaSyncerSyncIntervalMinutes() * 60 * 1000 * 2 / 3); return clientHandler.getResponseMap(); @@ -764,10 +764,10 @@ public List pushSingleTopicOnDataNode(ByteBuffer topicMeta) { configManager.getNodeManager().getRegisteredDataNodeLocations(); final TPushSingleTopicMetaReq request = new TPushSingleTopicMetaReq().setTopicMeta(topicMeta); - final AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.TOPIC_PUSH_SINGLE_META, request, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + final DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.TOPIC_PUSH_SINGLE_META, request, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); return clientHandler.getResponseList().stream() .map(TPushTopicMetaResp::getStatus) .collect(Collectors.toList()); @@ -779,10 +779,10 @@ public List dropSingleTopicOnDataNode(String topicNameToDrop) { final TPushSingleTopicMetaReq request = new TPushSingleTopicMetaReq().setTopicNameToDrop(topicNameToDrop); - final AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.TOPIC_PUSH_SINGLE_META, request, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + final DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.TOPIC_PUSH_SINGLE_META, request, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); return clientHandler.getResponseList().stream() .map(TPushTopicMetaResp::getStatus) .collect(Collectors.toList()); @@ -795,11 +795,11 @@ public Map pushMultiTopicMetaToDataNodes( final TPushMultiTopicMetaReq request = new TPushMultiTopicMetaReq().setTopicMetas(topicMetaBinaryList); - final AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.TOPIC_PUSH_MULTI_META, request, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance() - .sendAsyncRequestToDataNodeWithRetryAndTimeoutInMs( + final DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.TOPIC_PUSH_MULTI_META, request, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance() + .sendAsyncRequestToNodeWithRetryAndTimeoutInMs( clientHandler, PipeConfig.getInstance().getPipeMetaSyncerSyncIntervalMinutes() * 60 * 1000 * 2 / 3); return clientHandler.getResponseMap(); @@ -811,11 +811,11 @@ public Map dropMultiTopicOnDataNodes(List t final TPushMultiTopicMetaReq request = new TPushMultiTopicMetaReq().setTopicNamesToDrop(topicNamesToDrop); - final AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.TOPIC_PUSH_MULTI_META, request, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance() - .sendAsyncRequestToDataNodeWithRetryAndTimeoutInMs( + final DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.TOPIC_PUSH_MULTI_META, request, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance() + .sendAsyncRequestToNodeWithRetryAndTimeoutInMs( clientHandler, PipeConfig.getInstance().getPipeMetaSyncerSyncIntervalMinutes() * 60 * 1000 * 2 / 3); return clientHandler.getResponseMap(); @@ -828,11 +828,12 @@ public Map pushAllConsumerGroupMetaToDataNo final TPushConsumerGroupMetaReq request = new TPushConsumerGroupMetaReq().setConsumerGroupMetas(consumerGroupMetaBinaryList); - final AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.CONSUMER_GROUP_PUSH_ALL_META, request, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance() - .sendAsyncRequestToDataNodeWithRetryAndTimeoutInMs( + final DataNodeAsyncRequestContext + clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.CONSUMER_GROUP_PUSH_ALL_META, request, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance() + .sendAsyncRequestToNodeWithRetryAndTimeoutInMs( clientHandler, PipeConfig.getInstance().getPipeMetaSyncerSyncIntervalMinutes() * 60 * 1000 * 2 / 3); return clientHandler.getResponseMap(); @@ -844,11 +845,11 @@ public List pushSingleConsumerGroupOnDataNode(ByteBuffer consumerGroup final TPushSingleConsumerGroupMetaReq request = new TPushSingleConsumerGroupMetaReq().setConsumerGroupMeta(consumerGroupMeta); - final AsyncClientHandler + final DataNodeAsyncRequestContext clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.CONSUMER_GROUP_PUSH_SINGLE_META, request, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.CONSUMER_GROUP_PUSH_SINGLE_META, request, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); return clientHandler.getResponseList().stream() .map(TPushConsumerGroupMetaResp::getStatus) .collect(Collectors.toList()); @@ -860,11 +861,11 @@ public List dropSingleConsumerGroupOnDataNode(String consumerGroupName final TPushSingleConsumerGroupMetaReq request = new TPushSingleConsumerGroupMetaReq().setConsumerGroupNameToDrop(consumerGroupNameToDrop); - final AsyncClientHandler + final DataNodeAsyncRequestContext clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.CONSUMER_GROUP_PUSH_SINGLE_META, request, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.CONSUMER_GROUP_PUSH_SINGLE_META, request, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); return clientHandler.getResponseList().stream() .map(TPushConsumerGroupMetaResp::getStatus) .collect(Collectors.toList()); diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/env/RegionMaintainHandler.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/env/RegionMaintainHandler.java index 4f82d5c502fbf..9bb5b860eb9a7 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/env/RegionMaintainHandler.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/env/RegionMaintainHandler.java @@ -35,9 +35,9 @@ import org.apache.iotdb.commons.service.metric.MetricService; import org.apache.iotdb.commons.utils.CommonDateTimeUtils; import org.apache.iotdb.commons.utils.NodeUrlUtils; -import org.apache.iotdb.confignode.client.DataNodeRequestType; -import org.apache.iotdb.confignode.client.async.AsyncDataNodeClientPool; -import org.apache.iotdb.confignode.client.async.handlers.AsyncClientHandler; +import org.apache.iotdb.confignode.client.CnToDnRequestType; +import org.apache.iotdb.confignode.client.async.CnToDnInternalServiceAsyncRequestManager; +import org.apache.iotdb.confignode.client.async.handlers.DataNodeAsyncRequestContext; import org.apache.iotdb.confignode.client.sync.SyncDataNodeClientPool; import org.apache.iotdb.confignode.conf.ConfigNodeConfig; import org.apache.iotdb.confignode.conf.ConfigNodeDescriptor; @@ -145,7 +145,7 @@ public void broadcastDisableDataNode(TDataNodeLocation disabledDataNode) { .sendSyncRequestToDataNodeWithRetry( node.getLocation().getInternalEndPoint(), disableReq, - DataNodeRequestType.DISABLE_DATA_NODE); + CnToDnRequestType.DISABLE_DATA_NODE); if (!isSucceed(status)) { LOGGER.error( "{}, BroadcastDisableDataNode meets error, disabledDataNode: {}, error: {}", @@ -230,7 +230,7 @@ public TSStatus createNewRegionPeer(TConsensusGroupId regionId, TDataNodeLocatio .sendSyncRequestToDataNodeWithRetry( destDataNode.getInternalEndPoint(), req, - DataNodeRequestType.CREATE_NEW_REGION_PEER); + CnToDnRequestType.CREATE_NEW_REGION_PEER); if (isSucceed(status)) { LOGGER.info( @@ -276,7 +276,7 @@ public TSStatus submitAddRegionPeerTask( .sendSyncRequestToDataNodeWithRetry( coordinator.getInternalEndPoint(), maintainPeerReq, - DataNodeRequestType.ADD_REGION_PEER); + CnToDnRequestType.ADD_REGION_PEER); LOGGER.info( "{}, Send action addRegionPeer finished, regionId: {}, rpcDataNode: {}, destDataNode: {}, status: {}", REGION_MIGRATE_PROCESS, @@ -313,7 +313,7 @@ public TSStatus submitRemoveRegionPeerTask( .sendSyncRequestToDataNodeWithRetry( coordinator.getInternalEndPoint(), maintainPeerReq, - DataNodeRequestType.REMOVE_REGION_PEER); + CnToDnRequestType.REMOVE_REGION_PEER); LOGGER.info( "{}, Send action removeRegionPeer finished, regionId: {}, rpcDataNode: {}", REGION_MIGRATE_PROCESS, @@ -347,14 +347,14 @@ public TSStatus submitDeleteOldRegionPeerTask( .sendSyncRequestToDataNodeWithGivenRetry( originalDataNode.getInternalEndPoint(), maintainPeerReq, - DataNodeRequestType.DELETE_OLD_REGION_PEER, + CnToDnRequestType.DELETE_OLD_REGION_PEER, 1) : (TSStatus) SyncDataNodeClientPool.getInstance() .sendSyncRequestToDataNodeWithRetry( originalDataNode.getInternalEndPoint(), maintainPeerReq, - DataNodeRequestType.DELETE_OLD_REGION_PEER); + CnToDnRequestType.DELETE_OLD_REGION_PEER); LOGGER.info( "{}, Send action deleteOldRegionPeer finished, regionId: {}, dataNodeId: {}", REGION_MIGRATE_PROCESS, @@ -367,12 +367,12 @@ public Map resetPeerList( TConsensusGroupId regionId, List correctDataNodeLocations, Map dataNodeLocationMap) { - AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.RESET_PEER_LIST, + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.RESET_PEER_LIST, new TResetPeerListReq(regionId, correctDataNodeLocations), dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); return clientHandler.getResponseMap(); } @@ -508,10 +508,7 @@ public void stopDataNode(TDataNodeLocation dataNode) { (TSStatus) SyncDataNodeClientPool.getInstance() .sendSyncRequestToDataNodeWithGivenRetry( - dataNode.getInternalEndPoint(), - dataNode, - DataNodeRequestType.STOP_DATA_NODE, - 2); + dataNode.getInternalEndPoint(), dataNode, CnToDnRequestType.STOP_DATA_NODE, 2); configManager.getLoadManager().removeNodeCache(dataNode.getDataNodeId()); LOGGER.info( "{}, Stop Data Node result: {}, stoppedDataNode: {}", diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/AlterLogicalViewProcedure.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/AlterLogicalViewProcedure.java index 66677129dab64..8c6eed0655344 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/AlterLogicalViewProcedure.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/AlterLogicalViewProcedure.java @@ -30,9 +30,9 @@ import org.apache.iotdb.commons.path.PathDeserializeUtil; import org.apache.iotdb.commons.path.PathPatternTree; import org.apache.iotdb.commons.schema.view.viewExpression.ViewExpression; -import org.apache.iotdb.confignode.client.DataNodeRequestType; -import org.apache.iotdb.confignode.client.async.AsyncDataNodeClientPool; -import org.apache.iotdb.confignode.client.async.handlers.AsyncClientHandler; +import org.apache.iotdb.confignode.client.CnToDnRequestType; +import org.apache.iotdb.confignode.client.async.CnToDnInternalServiceAsyncRequestManager; +import org.apache.iotdb.confignode.client.async.handlers.DataNodeAsyncRequestContext; import org.apache.iotdb.confignode.procedure.env.ConfigNodeProcedureEnv; import org.apache.iotdb.confignode.procedure.exception.ProcedureException; import org.apache.iotdb.confignode.procedure.exception.ProcedureSuspendedException; @@ -120,12 +120,12 @@ protected Flow executeFromState(ConfigNodeProcedureEnv env, AlterLogicalViewStat private void invalidateCache(ConfigNodeProcedureEnv env) { Map dataNodeLocationMap = env.getConfigManager().getNodeManager().getRegisteredDataNodeLocations(); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.INVALIDATE_MATCHED_SCHEMA_CACHE, + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.INVALIDATE_MATCHED_SCHEMA_CACHE, new TInvalidateMatchedSchemaCacheReq(patternTreeBytes), dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); Map statusMap = clientHandler.getResponseMap(); for (TSStatus status : statusMap.values()) { // all dataNodes must clear the related schemaengine cache @@ -155,7 +155,7 @@ private void alterLogicalView(ConfigNodeProcedureEnv env) throws ProcedureExcept "Alter view", env, targetSchemaRegionGroup, - DataNodeRequestType.ALTER_VIEW, + CnToDnRequestType.ALTER_VIEW, (dataNodeLocation, consensusGroupIdList) -> { TAlterViewReq req = new TAlterViewReq().setIsGeneratedByPipe(isGeneratedByPipe); req.setSchemaRegionIdList(consensusGroupIdList); @@ -323,7 +323,7 @@ private class AlterLogicalViewRegionTaskExecutor String taskName, ConfigNodeProcedureEnv env, Map targetSchemaRegionGroup, - DataNodeRequestType dataNodeRequestType, + CnToDnRequestType dataNodeRequestType, BiFunction, Q> dataNodeRequestGenerator) { super(env, targetSchemaRegionGroup, false, dataNodeRequestType, dataNodeRequestGenerator); this.taskName = taskName; diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/DataNodeRegionTaskExecutor.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/DataNodeRegionTaskExecutor.java index d2bf19a231af1..f7fa7b1055518 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/DataNodeRegionTaskExecutor.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/DataNodeRegionTaskExecutor.java @@ -22,9 +22,9 @@ import org.apache.iotdb.common.rpc.thrift.TConsensusGroupId; import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; import org.apache.iotdb.common.rpc.thrift.TRegionReplicaSet; -import org.apache.iotdb.confignode.client.DataNodeRequestType; -import org.apache.iotdb.confignode.client.async.AsyncDataNodeClientPool; -import org.apache.iotdb.confignode.client.async.handlers.AsyncClientHandler; +import org.apache.iotdb.confignode.client.CnToDnRequestType; +import org.apache.iotdb.confignode.client.async.CnToDnInternalServiceAsyncRequestManager; +import org.apache.iotdb.confignode.client.async.handlers.DataNodeAsyncRequestContext; import org.apache.iotdb.confignode.manager.ConfigManager; import org.apache.iotdb.confignode.procedure.env.ConfigNodeProcedureEnv; @@ -45,7 +45,7 @@ public abstract class DataNodeRegionTaskExecutor { protected final Map targetSchemaRegionGroup; protected final boolean executeOnAllReplicaset; - protected final DataNodeRequestType dataNodeRequestType; + protected final CnToDnRequestType dataNodeRequestType; protected final BiFunction, Q> dataNodeRequestGenerator; @@ -55,7 +55,7 @@ protected DataNodeRegionTaskExecutor( ConfigManager configManager, Map targetSchemaRegionGroup, boolean executeOnAllReplicaset, - DataNodeRequestType dataNodeRequestType, + CnToDnRequestType dataNodeRequestType, BiFunction, Q> dataNodeRequestGenerator) { this.configManager = configManager; this.targetSchemaRegionGroup = targetSchemaRegionGroup; @@ -68,7 +68,7 @@ protected DataNodeRegionTaskExecutor( ConfigNodeProcedureEnv env, Map targetSchemaRegionGroup, boolean executeOnAllReplicaset, - DataNodeRequestType dataNodeRequestType, + CnToDnRequestType dataNodeRequestType, BiFunction, Q> dataNodeRequestGenerator) { this.configManager = env.getConfigManager(); this.targetSchemaRegionGroup = targetSchemaRegionGroup; @@ -86,8 +86,10 @@ public void execute() { : getLeaderDataNodeRegionGroupMap( configManager.getLoadManager().getRegionLeaderMap(), targetSchemaRegionGroup); while (!dataNodeConsensusGroupIdMap.isEmpty()) { - AsyncClientHandler clientHandler = prepareRequestHandler(dataNodeConsensusGroupIdMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + prepareRequestHandler(dataNodeConsensusGroupIdMap); + CnToDnInternalServiceAsyncRequestManager.getInstance() + .sendAsyncRequestWithRetry(clientHandler); Map> currentFailedDataNodeMap = checkDataNodeExecutionResult(clientHandler.getResponseMap(), dataNodeConsensusGroupIdMap); @@ -112,12 +114,13 @@ public void execute() { } } - private AsyncClientHandler prepareRequestHandler( + private DataNodeAsyncRequestContext prepareRequestHandler( Map> dataNodeConsensusGroupIdMap) { - AsyncClientHandler clientHandler = new AsyncClientHandler<>(dataNodeRequestType); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>(dataNodeRequestType); for (Map.Entry> entry : dataNodeConsensusGroupIdMap.entrySet()) { - clientHandler.putDataNodeLocation(entry.getKey().getDataNodeId(), entry.getKey()); + clientHandler.putNodeLocation(entry.getKey().getDataNodeId(), entry.getKey()); clientHandler.putRequest( entry.getKey().getDataNodeId(), dataNodeRequestGenerator.apply(entry.getKey(), entry.getValue())); diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/DeactivateTemplateProcedure.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/DeactivateTemplateProcedure.java index 194e23d148865..f75814ef0f96a 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/DeactivateTemplateProcedure.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/DeactivateTemplateProcedure.java @@ -28,9 +28,9 @@ import org.apache.iotdb.commons.path.PartialPath; import org.apache.iotdb.commons.path.PathDeserializeUtil; import org.apache.iotdb.commons.path.PathPatternTree; -import org.apache.iotdb.confignode.client.DataNodeRequestType; -import org.apache.iotdb.confignode.client.async.AsyncDataNodeClientPool; -import org.apache.iotdb.confignode.client.async.handlers.AsyncClientHandler; +import org.apache.iotdb.confignode.client.CnToDnRequestType; +import org.apache.iotdb.confignode.client.async.CnToDnInternalServiceAsyncRequestManager; +import org.apache.iotdb.confignode.client.async.handlers.DataNodeAsyncRequestContext; import org.apache.iotdb.confignode.consensus.request.write.pipe.payload.PipeDeactivateTemplatePlan; import org.apache.iotdb.confignode.consensus.request.write.pipe.payload.PipeEnrichedPlan; import org.apache.iotdb.confignode.procedure.env.ConfigNodeProcedureEnv; @@ -152,7 +152,7 @@ private long constructBlackList(ConfigNodeProcedureEnv env) { "construct schema black list", env, targetSchemaRegionGroup, - DataNodeRequestType.CONSTRUCT_SCHEMA_BLACK_LIST_WITH_TEMPLATE, + CnToDnRequestType.CONSTRUCT_SCHEMA_BLACK_LIST_WITH_TEMPLATE, ((dataNodeLocation, consensusGroupIdList) -> new TConstructSchemaBlackListWithTemplateReq( consensusGroupIdList, dataNodeRequest))) { @@ -198,12 +198,13 @@ private void invalidateCache(ConfigNodeProcedureEnv env) { if (!timeSeriesPatternTree.isEmpty()) { Map dataNodeLocationMap = env.getConfigManager().getNodeManager().getRegisteredDataNodeLocations(); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.INVALIDATE_MATCHED_SCHEMA_CACHE, + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.INVALIDATE_MATCHED_SCHEMA_CACHE, new TInvalidateMatchedSchemaCacheReq(timeSeriesPatternTreeBytes), dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + CnToDnInternalServiceAsyncRequestManager.getInstance() + .sendAsyncRequestWithRetry(clientHandler); Map statusMap = clientHandler.getResponseMap(); for (TSStatus status : statusMap.values()) { // all dataNodes must clear the related schema cache @@ -232,7 +233,7 @@ private void deleteData(ConfigNodeProcedureEnv env) { env, relatedDataRegionGroup, true, - DataNodeRequestType.DELETE_DATA_FOR_DELETE_SCHEMA, + CnToDnRequestType.DELETE_DATA_FOR_DELETE_SCHEMA, ((dataNodeLocation, consensusGroupIdList) -> new TDeleteDataForDeleteSchemaReq( new ArrayList<>(consensusGroupIdList), timeSeriesPatternTreeBytes))); @@ -247,7 +248,7 @@ private void deactivateTemplate(ConfigNodeProcedureEnv env) { "deactivate template schema", env, env.getConfigManager().getRelatedSchemaRegionGroup(timeSeriesPatternTree), - DataNodeRequestType.DEACTIVATE_TEMPLATE, + CnToDnRequestType.DEACTIVATE_TEMPLATE, ((dataNodeLocation, consensusGroupIdList) -> new TDeactivateTemplateReq(consensusGroupIdList, dataNodeRequest) .setIsGeneratedByPipe(isGeneratedByPipe))); @@ -285,7 +286,7 @@ protected void rollbackState( "roll back schema black list", env, env.getConfigManager().getRelatedSchemaRegionGroup(timeSeriesPatternTree), - DataNodeRequestType.ROLLBACK_SCHEMA_BLACK_LIST_WITH_TEMPLATE, + CnToDnRequestType.ROLLBACK_SCHEMA_BLACK_LIST_WITH_TEMPLATE, ((dataNodeLocation, consensusGroupIdList) -> new TRollbackSchemaBlackListWithTemplateReq( consensusGroupIdList, dataNodeRequest))); @@ -438,7 +439,7 @@ private class DeactivateTemplateRegionTaskExecutor String taskName, ConfigNodeProcedureEnv env, Map targetSchemaRegionGroup, - DataNodeRequestType dataNodeRequestType, + CnToDnRequestType dataNodeRequestType, BiFunction, Q> dataNodeRequestGenerator) { super(env, targetSchemaRegionGroup, false, dataNodeRequestType, dataNodeRequestGenerator); this.taskName = taskName; @@ -449,7 +450,7 @@ private class DeactivateTemplateRegionTaskExecutor ConfigNodeProcedureEnv env, Map targetSchemaRegionGroup, boolean executeOnAllReplicaset, - DataNodeRequestType dataNodeRequestType, + CnToDnRequestType dataNodeRequestType, BiFunction, Q> dataNodeRequestGenerator) { super( env, diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/DeleteDatabaseProcedure.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/DeleteDatabaseProcedure.java index f03cc7619ef24..d47e575a3ad6a 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/DeleteDatabaseProcedure.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/DeleteDatabaseProcedure.java @@ -27,9 +27,9 @@ import org.apache.iotdb.commons.exception.runtime.ThriftSerDeException; import org.apache.iotdb.commons.service.metric.MetricService; import org.apache.iotdb.commons.utils.ThriftConfigNodeSerDeUtils; -import org.apache.iotdb.confignode.client.DataNodeRequestType; -import org.apache.iotdb.confignode.client.async.AsyncDataNodeClientPool; -import org.apache.iotdb.confignode.client.async.handlers.AsyncClientHandler; +import org.apache.iotdb.confignode.client.CnToDnRequestType; +import org.apache.iotdb.confignode.client.async.CnToDnInternalServiceAsyncRequestManager; +import org.apache.iotdb.confignode.client.async.handlers.DataNodeAsyncRequestContext; import org.apache.iotdb.confignode.consensus.request.write.database.PreDeleteDatabasePlan; import org.apache.iotdb.confignode.consensus.request.write.region.OfferRegionMaintainTasksPlan; import org.apache.iotdb.confignode.manager.partition.PartitionMetrics; @@ -155,15 +155,15 @@ protected Flow executeFromState(ConfigNodeProcedureEnv env, DeleteStorageGroupSt MetricService.getInstance(), deleteDatabaseSchema.getName()); // try sync delete schemaengine region - AsyncClientHandler asyncClientHandler = - new AsyncClientHandler<>(DataNodeRequestType.DELETE_REGION); + DataNodeAsyncRequestContext asyncClientHandler = + new DataNodeAsyncRequestContext<>(CnToDnRequestType.DELETE_REGION); Map schemaRegionDeleteTaskMap = new HashMap<>(); int requestIndex = 0; for (TRegionReplicaSet schemaRegionReplicaSet : schemaRegionReplicaSets) { for (TDataNodeLocation dataNodeLocation : schemaRegionReplicaSet.getDataNodeLocations()) { asyncClientHandler.putRequest(requestIndex, schemaRegionReplicaSet.getRegionId()); - asyncClientHandler.putDataNodeLocation(requestIndex, dataNodeLocation); + asyncClientHandler.putNodeLocation(requestIndex, dataNodeLocation); schemaRegionDeleteTaskMap.put( requestIndex, new RegionDeleteTask(dataNodeLocation, schemaRegionReplicaSet.getRegionId())); @@ -171,8 +171,8 @@ protected Flow executeFromState(ConfigNodeProcedureEnv env, DeleteStorageGroupSt } } if (!schemaRegionDeleteTaskMap.isEmpty()) { - AsyncDataNodeClientPool.getInstance() - .sendAsyncRequestToDataNodeWithRetry(asyncClientHandler); + CnToDnInternalServiceAsyncRequestManager.getInstance() + .sendAsyncRequestWithRetry(asyncClientHandler); for (Map.Entry entry : asyncClientHandler.getResponseMap().entrySet()) { if (entry.getValue().getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/DeleteLogicalViewProcedure.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/DeleteLogicalViewProcedure.java index 1a566ae440466..97583dfc03b0b 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/DeleteLogicalViewProcedure.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/DeleteLogicalViewProcedure.java @@ -26,9 +26,9 @@ import org.apache.iotdb.commons.exception.MetadataException; import org.apache.iotdb.commons.path.PartialPath; import org.apache.iotdb.commons.path.PathPatternTree; -import org.apache.iotdb.confignode.client.DataNodeRequestType; -import org.apache.iotdb.confignode.client.async.AsyncDataNodeClientPool; -import org.apache.iotdb.confignode.client.async.handlers.AsyncClientHandler; +import org.apache.iotdb.confignode.client.CnToDnRequestType; +import org.apache.iotdb.confignode.client.async.CnToDnInternalServiceAsyncRequestManager; +import org.apache.iotdb.confignode.client.async.handlers.DataNodeAsyncRequestContext; import org.apache.iotdb.confignode.consensus.request.write.pipe.payload.PipeDeleteLogicalViewPlan; import org.apache.iotdb.confignode.consensus.request.write.pipe.payload.PipeEnrichedPlan; import org.apache.iotdb.confignode.procedure.env.ConfigNodeProcedureEnv; @@ -142,7 +142,7 @@ private long constructBlackList(ConfigNodeProcedureEnv env) { "construct view schemaengine black list", env, targetSchemaRegionGroup, - DataNodeRequestType.CONSTRUCT_VIEW_SCHEMA_BLACK_LIST, + CnToDnRequestType.CONSTRUCT_VIEW_SCHEMA_BLACK_LIST, ((dataNodeLocation, consensusGroupIdList) -> new TConstructViewSchemaBlackListReq(consensusGroupIdList, patternTreeBytes))) { @Override @@ -184,12 +184,12 @@ protected List processResponseOfOneDataNode( private void invalidateCache(ConfigNodeProcedureEnv env) { Map dataNodeLocationMap = env.getConfigManager().getNodeManager().getRegisteredDataNodeLocations(); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.INVALIDATE_MATCHED_SCHEMA_CACHE, + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.INVALIDATE_MATCHED_SCHEMA_CACHE, new TInvalidateMatchedSchemaCacheReq(patternTreeBytes), dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); Map statusMap = clientHandler.getResponseMap(); for (TSStatus status : statusMap.values()) { // all dataNodes must clear the related schemaengine cache @@ -211,7 +211,7 @@ private void deleteViewSchema(ConfigNodeProcedureEnv env) { "delete view schemaengine", env, env.getConfigManager().getRelatedSchemaRegionGroup(patternTree), - DataNodeRequestType.DELETE_VIEW, + CnToDnRequestType.DELETE_VIEW, ((dataNodeLocation, consensusGroupIdList) -> new TDeleteViewSchemaReq(consensusGroupIdList, patternTreeBytes) .setIsGeneratedByPipe(isGeneratedByPipe))); @@ -247,7 +247,7 @@ protected void rollbackState( "roll back view schemaengine black list", env, env.getConfigManager().getRelatedSchemaRegionGroup(patternTree), - DataNodeRequestType.ROLLBACK_VIEW_SCHEMA_BLACK_LIST, + CnToDnRequestType.ROLLBACK_VIEW_SCHEMA_BLACK_LIST, (dataNodeLocation, consensusGroupIdList) -> new TRollbackViewSchemaBlackListReq(consensusGroupIdList, patternTreeBytes)); rollbackStateTask.execute(); @@ -343,7 +343,7 @@ private class DeleteLogicalViewRegionTaskExecutor String taskName, ConfigNodeProcedureEnv env, Map targetSchemaRegionGroup, - DataNodeRequestType dataNodeRequestType, + CnToDnRequestType dataNodeRequestType, BiFunction, Q> dataNodeRequestGenerator) { super(env, targetSchemaRegionGroup, false, dataNodeRequestType, dataNodeRequestGenerator); this.taskName = taskName; diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/DeleteTimeSeriesProcedure.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/DeleteTimeSeriesProcedure.java index f49827f0895f4..40b8c55d23745 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/DeleteTimeSeriesProcedure.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/DeleteTimeSeriesProcedure.java @@ -26,9 +26,9 @@ import org.apache.iotdb.commons.exception.MetadataException; import org.apache.iotdb.commons.path.PartialPath; import org.apache.iotdb.commons.path.PathPatternTree; -import org.apache.iotdb.confignode.client.DataNodeRequestType; -import org.apache.iotdb.confignode.client.async.AsyncDataNodeClientPool; -import org.apache.iotdb.confignode.client.async.handlers.AsyncClientHandler; +import org.apache.iotdb.confignode.client.CnToDnRequestType; +import org.apache.iotdb.confignode.client.async.CnToDnInternalServiceAsyncRequestManager; +import org.apache.iotdb.confignode.client.async.handlers.DataNodeAsyncRequestContext; import org.apache.iotdb.confignode.consensus.request.write.pipe.payload.PipeDeleteTimeSeriesPlan; import org.apache.iotdb.confignode.consensus.request.write.pipe.payload.PipeEnrichedPlan; import org.apache.iotdb.confignode.procedure.env.ConfigNodeProcedureEnv; @@ -148,7 +148,7 @@ private long constructBlackList(ConfigNodeProcedureEnv env) { "construct schemaengine black list", env, targetSchemaRegionGroup, - DataNodeRequestType.CONSTRUCT_SCHEMA_BLACK_LIST, + CnToDnRequestType.CONSTRUCT_SCHEMA_BLACK_LIST, ((dataNodeLocation, consensusGroupIdList) -> new TConstructSchemaBlackListReq(consensusGroupIdList, patternTreeBytes))) { @Override @@ -190,12 +190,12 @@ protected List processResponseOfOneDataNode( private void invalidateCache(ConfigNodeProcedureEnv env) { Map dataNodeLocationMap = env.getConfigManager().getNodeManager().getRegisteredDataNodeLocations(); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.INVALIDATE_MATCHED_SCHEMA_CACHE, + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.INVALIDATE_MATCHED_SCHEMA_CACHE, new TInvalidateMatchedSchemaCacheReq(patternTreeBytes), dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); Map statusMap = clientHandler.getResponseMap(); for (TSStatus status : statusMap.values()) { // all dataNodes must clear the related schemaEngine cache @@ -237,7 +237,7 @@ private void executeDeleteData(ConfigNodeProcedureEnv env, PathPatternTree patte env, relatedDataRegionGroup, true, - DataNodeRequestType.DELETE_DATA_FOR_DELETE_SCHEMA, + CnToDnRequestType.DELETE_DATA_FOR_DELETE_SCHEMA, ((dataNodeLocation, consensusGroupIdList) -> new TDeleteDataForDeleteSchemaReq( new ArrayList<>(consensusGroupIdList), @@ -252,7 +252,7 @@ private void deleteTimeSeriesSchema(ConfigNodeProcedureEnv env) { "delete timeseries schemaengine", env, env.getConfigManager().getRelatedSchemaRegionGroup(patternTree), - DataNodeRequestType.DELETE_TIMESERIES, + CnToDnRequestType.DELETE_TIMESERIES, ((dataNodeLocation, consensusGroupIdList) -> new TDeleteTimeSeriesReq(consensusGroupIdList, patternTreeBytes) .setIsGeneratedByPipe(isGeneratedByPipe))); @@ -289,7 +289,7 @@ protected void rollbackState( "roll back schemaengine black list", env, env.getConfigManager().getRelatedSchemaRegionGroup(patternTree), - DataNodeRequestType.ROLLBACK_SCHEMA_BLACK_LIST, + CnToDnRequestType.ROLLBACK_SCHEMA_BLACK_LIST, (dataNodeLocation, consensusGroupIdList) -> new TRollbackSchemaBlackListReq(consensusGroupIdList, patternTreeBytes)); rollbackStateTask.execute(); @@ -386,7 +386,7 @@ private class DeleteTimeSeriesRegionTaskExecutor String taskName, ConfigNodeProcedureEnv env, Map targetSchemaRegionGroup, - DataNodeRequestType dataNodeRequestType, + CnToDnRequestType dataNodeRequestType, BiFunction, Q> dataNodeRequestGenerator) { super(env, targetSchemaRegionGroup, false, dataNodeRequestType, dataNodeRequestGenerator); this.taskName = taskName; @@ -397,7 +397,7 @@ private class DeleteTimeSeriesRegionTaskExecutor ConfigNodeProcedureEnv env, Map targetSchemaRegionGroup, boolean executeOnAllReplicaset, - DataNodeRequestType dataNodeRequestType, + CnToDnRequestType dataNodeRequestType, BiFunction, Q> dataNodeRequestGenerator) { super( env, diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/SchemaUtils.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/SchemaUtils.java index 1dc978cc40406..86215919aa191 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/SchemaUtils.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/SchemaUtils.java @@ -26,7 +26,7 @@ import org.apache.iotdb.commons.exception.MetadataException; import org.apache.iotdb.commons.path.PartialPath; import org.apache.iotdb.commons.path.PathPatternTree; -import org.apache.iotdb.confignode.client.DataNodeRequestType; +import org.apache.iotdb.confignode.client.CnToDnRequestType; import org.apache.iotdb.confignode.manager.ConfigManager; import org.apache.iotdb.db.exception.metadata.PathNotExistException; import org.apache.iotdb.db.schemaengine.template.Template; @@ -76,7 +76,7 @@ public static boolean checkDataNodeTemplateActivation( configManager, relatedSchemaRegionGroup, false, - DataNodeRequestType.COUNT_PATHS_USING_TEMPLATE, + CnToDnRequestType.COUNT_PATHS_USING_TEMPLATE, ((dataNodeLocation, consensusGroupIdList) -> new TCountPathsUsingTemplateReq( template.getId(), patternTreeBytes, consensusGroupIdList))) { @@ -155,7 +155,7 @@ public static void checkSchemaRegionUsingTemplate( configManager, relatedSchemaRegionGroup, false, - DataNodeRequestType.CHECK_SCHEMA_REGION_USING_TEMPLATE, + CnToDnRequestType.CHECK_SCHEMA_REGION_USING_TEMPLATE, ((dataNodeLocation, consensusGroupIdList) -> new TCheckSchemaRegionUsingTemplateReq(consensusGroupIdList))) { diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/SetTTLProcedure.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/SetTTLProcedure.java index 4cd1b9fa37d0d..ec9b003d7eeef 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/SetTTLProcedure.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/SetTTLProcedure.java @@ -24,9 +24,9 @@ import org.apache.iotdb.common.rpc.thrift.TSetTTLReq; import org.apache.iotdb.commons.exception.IoTDBException; import org.apache.iotdb.commons.exception.MetadataException; -import org.apache.iotdb.confignode.client.DataNodeRequestType; -import org.apache.iotdb.confignode.client.async.AsyncDataNodeClientPool; -import org.apache.iotdb.confignode.client.async.handlers.AsyncClientHandler; +import org.apache.iotdb.confignode.client.CnToDnRequestType; +import org.apache.iotdb.confignode.client.async.CnToDnInternalServiceAsyncRequestManager; +import org.apache.iotdb.confignode.client.async.handlers.DataNodeAsyncRequestContext; import org.apache.iotdb.confignode.consensus.request.ConfigPhysicalPlan; import org.apache.iotdb.confignode.consensus.request.write.database.SetTTLPlan; import org.apache.iotdb.confignode.consensus.request.write.pipe.payload.PipeEnrichedPlan; @@ -108,15 +108,15 @@ private void setConfigNodeTTL(ConfigNodeProcedureEnv env) { private void updateDataNodeTTL(ConfigNodeProcedureEnv env) { Map dataNodeLocationMap = env.getConfigManager().getNodeManager().getRegisteredDataNodeLocations(); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.SET_TTL, + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.SET_TTL, new TSetTTLReq( Collections.singletonList(String.join(".", plan.getPathPattern())), plan.getTTL(), plan.isDataBase()), dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); Map statusMap = clientHandler.getResponseMap(); for (TSStatus status : statusMap.values()) { // all dataNodes must clear the related schemaengine cache diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/SetTemplateProcedure.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/SetTemplateProcedure.java index ab8ac167aee9a..902221285e26e 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/SetTemplateProcedure.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/SetTemplateProcedure.java @@ -28,9 +28,9 @@ import org.apache.iotdb.commons.exception.MetadataException; import org.apache.iotdb.commons.path.PartialPath; import org.apache.iotdb.commons.path.PathPatternTree; -import org.apache.iotdb.confignode.client.DataNodeRequestType; -import org.apache.iotdb.confignode.client.async.AsyncDataNodeClientPool; -import org.apache.iotdb.confignode.client.async.handlers.AsyncClientHandler; +import org.apache.iotdb.confignode.client.CnToDnRequestType; +import org.apache.iotdb.confignode.client.async.CnToDnInternalServiceAsyncRequestManager; +import org.apache.iotdb.confignode.client.async.handlers.DataNodeAsyncRequestContext; import org.apache.iotdb.confignode.consensus.request.read.template.CheckTemplateSettablePlan; import org.apache.iotdb.confignode.consensus.request.read.template.GetSchemaTemplatePlan; import org.apache.iotdb.confignode.consensus.request.write.pipe.payload.PipeEnrichedPlan; @@ -210,9 +210,10 @@ private void preReleaseTemplate(ConfigNodeProcedureEnv env) { Map dataNodeLocationMap = env.getConfigManager().getNodeManager().getRegisteredDataNodeLocations(); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>(DataNodeRequestType.UPDATE_TEMPLATE, req, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.UPDATE_TEMPLATE, req, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); Map statusMap = clientHandler.getResponseMap(); for (Map.Entry entry : statusMap.entrySet()) { if (entry.getValue().getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { @@ -281,7 +282,7 @@ private void validateTimeSeriesExistence(ConfigNodeProcedureEnv env) { env, relatedSchemaRegionGroup, false, - DataNodeRequestType.CHECK_TIMESERIES_EXISTENCE, + CnToDnRequestType.CHECK_TIMESERIES_EXISTENCE, ((dataNodeLocation, consensusGroupIdList) -> new TCheckTimeSeriesExistenceReq(patternTreeBytes, consensusGroupIdList))) { @@ -382,9 +383,10 @@ private void commitReleaseTemplate(ConfigNodeProcedureEnv env) { Map dataNodeLocationMap = env.getConfigManager().getNodeManager().getRegisteredDataNodeLocations(); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>(DataNodeRequestType.UPDATE_TEMPLATE, req, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.UPDATE_TEMPLATE, req, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); Map statusMap = clientHandler.getResponseMap(); for (Map.Entry entry : statusMap.entrySet()) { if (entry.getValue().getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { @@ -486,10 +488,10 @@ private void rollbackPreRelease(ConfigNodeProcedureEnv env) { TemplateInternalRPCUtil.generateInvalidateTemplateSetInfoBytes( template.getId(), templateSetPath)); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.UPDATE_TEMPLATE, invalidateTemplateSetInfoReq, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.UPDATE_TEMPLATE, invalidateTemplateSetInfoReq, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); Map statusMap = clientHandler.getResponseMap(); for (Map.Entry entry : statusMap.entrySet()) { // all dataNodes must clear the related template cache diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/UnsetTemplateProcedure.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/UnsetTemplateProcedure.java index e2d30f10bff78..ee70f3c7a7d17 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/UnsetTemplateProcedure.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/UnsetTemplateProcedure.java @@ -26,9 +26,9 @@ import org.apache.iotdb.commons.path.PartialPath; import org.apache.iotdb.commons.path.PathDeserializeUtil; import org.apache.iotdb.commons.path.PathPatternTree; -import org.apache.iotdb.confignode.client.DataNodeRequestType; -import org.apache.iotdb.confignode.client.async.AsyncDataNodeClientPool; -import org.apache.iotdb.confignode.client.async.handlers.AsyncClientHandler; +import org.apache.iotdb.confignode.client.CnToDnRequestType; +import org.apache.iotdb.confignode.client.async.CnToDnInternalServiceAsyncRequestManager; +import org.apache.iotdb.confignode.client.async.handlers.DataNodeAsyncRequestContext; import org.apache.iotdb.confignode.procedure.env.ConfigNodeProcedureEnv; import org.apache.iotdb.confignode.procedure.exception.ProcedureException; import org.apache.iotdb.confignode.procedure.exception.ProcedureSuspendedException; @@ -155,10 +155,10 @@ private void executeInvalidateCache(ConfigNodeProcedureEnv env) throws Procedure invalidateTemplateSetInfoReq.setType( TemplateInternalRPCUpdateType.INVALIDATE_TEMPLATE_SET_INFO.toByte()); invalidateTemplateSetInfoReq.setTemplateInfo(getInvalidateTemplateSetInfo()); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.UPDATE_TEMPLATE, invalidateTemplateSetInfoReq, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.UPDATE_TEMPLATE, invalidateTemplateSetInfoReq, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); Map statusMap = clientHandler.getResponseMap(); for (TSStatus status : statusMap.values()) { // all dataNodes must clear the related template cache @@ -250,10 +250,10 @@ private void executeRollbackInvalidateCache(ConfigNodeProcedureEnv env) rollbackTemplateSetInfoReq.setType( TemplateInternalRPCUpdateType.ADD_TEMPLATE_SET_INFO.toByte()); rollbackTemplateSetInfoReq.setTemplateInfo(getAddTemplateSetInfo()); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>( - DataNodeRequestType.UPDATE_TEMPLATE, rollbackTemplateSetInfoReq, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>( + CnToDnRequestType.UPDATE_TEMPLATE, rollbackTemplateSetInfoReq, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); Map statusMap = clientHandler.getResponseMap(); for (TSStatus status : statusMap.values()) { // all dataNodes must clear the related template cache diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/AddTableColumnProcedure.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/AddTableColumnProcedure.java index 74fbfaa1728ee..2bc01bd842be7 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/AddTableColumnProcedure.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/AddTableColumnProcedure.java @@ -26,9 +26,9 @@ import org.apache.iotdb.commons.schema.table.TsTableInternalRPCType; import org.apache.iotdb.commons.schema.table.column.TsTableColumnSchema; import org.apache.iotdb.commons.schema.table.column.TsTableColumnSchemaUtil; -import org.apache.iotdb.confignode.client.DataNodeRequestType; -import org.apache.iotdb.confignode.client.async.AsyncDataNodeClientPool; -import org.apache.iotdb.confignode.client.async.handlers.AsyncClientHandler; +import org.apache.iotdb.confignode.client.CnToDnRequestType; +import org.apache.iotdb.confignode.client.async.CnToDnInternalServiceAsyncRequestManager; +import org.apache.iotdb.confignode.client.async.handlers.DataNodeAsyncRequestContext; import org.apache.iotdb.confignode.procedure.env.ConfigNodeProcedureEnv; import org.apache.iotdb.confignode.procedure.exception.ProcedureException; import org.apache.iotdb.confignode.procedure.exception.ProcedureSuspendedException; @@ -139,9 +139,9 @@ private void preRelease(ConfigNodeProcedureEnv env) { new TUpdateTableReq( TsTableInternalRPCType.PRE_ADD_COLUMN.getOperationType(), getCacheRequestInfo()); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>(DataNodeRequestType.UPDATE_TABLE, req, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>(CnToDnRequestType.UPDATE_TABLE, req, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); Map statusMap = clientHandler.getResponseMap(); for (TSStatus status : statusMap.values()) { // all dataNodes must clear the related schema cache @@ -165,9 +165,9 @@ private void commitRelease(ConfigNodeProcedureEnv env) { new TUpdateTableReq( TsTableInternalRPCType.COMMIT_ADD_COLUMN.getOperationType(), getCacheRequestInfo()); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>(DataNodeRequestType.UPDATE_TABLE, req, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>(CnToDnRequestType.UPDATE_TABLE, req, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); Map statusMap = clientHandler.getResponseMap(); for (TSStatus status : statusMap.values()) { // all dataNodes must clear the related schema cache @@ -230,9 +230,9 @@ private void rollbackUpdateCache(ConfigNodeProcedureEnv env) { new TUpdateTableReq( TsTableInternalRPCType.ROLLBACK_ADD_COLUMN.getOperationType(), getCacheRequestInfo()); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>(DataNodeRequestType.UPDATE_TABLE, req, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>(CnToDnRequestType.UPDATE_TABLE, req, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); Map statusMap = clientHandler.getResponseMap(); for (TSStatus status : statusMap.values()) { // all dataNodes must clear the related schema cache diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/CreateTableProcedure.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/CreateTableProcedure.java index c3c91e1cd0262..29dade50ca4e6 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/CreateTableProcedure.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/schema/table/CreateTableProcedure.java @@ -31,9 +31,9 @@ import org.apache.iotdb.commons.schema.table.TsTable; import org.apache.iotdb.commons.schema.table.TsTableInternalRPCType; import org.apache.iotdb.commons.schema.table.TsTableInternalRPCUtil; -import org.apache.iotdb.confignode.client.DataNodeRequestType; -import org.apache.iotdb.confignode.client.async.AsyncDataNodeClientPool; -import org.apache.iotdb.confignode.client.async.handlers.AsyncClientHandler; +import org.apache.iotdb.confignode.client.CnToDnRequestType; +import org.apache.iotdb.confignode.client.async.CnToDnInternalServiceAsyncRequestManager; +import org.apache.iotdb.confignode.client.async.handlers.DataNodeAsyncRequestContext; import org.apache.iotdb.confignode.consensus.request.write.table.CommitCreateTablePlan; import org.apache.iotdb.confignode.consensus.request.write.table.PreCreateTablePlan; import org.apache.iotdb.confignode.consensus.request.write.table.RollbackCreateTablePlan; @@ -153,9 +153,9 @@ private void preReleaseTable(ConfigNodeProcedureEnv env) { Map dataNodeLocationMap = env.getConfigManager().getNodeManager().getRegisteredDataNodeLocations(); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>(DataNodeRequestType.UPDATE_TABLE, req, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>(CnToDnRequestType.UPDATE_TABLE, req, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); Map statusMap = clientHandler.getResponseMap(); for (Map.Entry entry : statusMap.entrySet()) { if (entry.getValue().getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { @@ -197,7 +197,7 @@ private void validateTimeSeriesExistence(ConfigNodeProcedureEnv env) { env, relatedSchemaRegionGroup, false, - DataNodeRequestType.CHECK_TIMESERIES_EXISTENCE, + CnToDnRequestType.CHECK_TIMESERIES_EXISTENCE, ((dataNodeLocation, consensusGroupIdList) -> new TCheckTimeSeriesExistenceReq(patternTreeBytes, consensusGroupIdList))) { @@ -291,9 +291,9 @@ private void commitReleaseTable(ConfigNodeProcedureEnv env) { Map dataNodeLocationMap = env.getConfigManager().getNodeManager().getRegisteredDataNodeLocations(); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>(DataNodeRequestType.UPDATE_TABLE, req, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>(CnToDnRequestType.UPDATE_TABLE, req, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); Map statusMap = clientHandler.getResponseMap(); for (Map.Entry entry : statusMap.entrySet()) { if (entry.getValue().getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { @@ -359,9 +359,9 @@ private void rollbackRelease(ConfigNodeProcedureEnv env) { Map dataNodeLocationMap = env.getConfigManager().getNodeManager().getRegisteredDataNodeLocations(); - AsyncClientHandler clientHandler = - new AsyncClientHandler<>(DataNodeRequestType.UPDATE_TABLE, req, dataNodeLocationMap); - AsyncDataNodeClientPool.getInstance().sendAsyncRequestToDataNodeWithRetry(clientHandler); + DataNodeAsyncRequestContext clientHandler = + new DataNodeAsyncRequestContext<>(CnToDnRequestType.UPDATE_TABLE, req, dataNodeLocationMap); + CnToDnInternalServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(clientHandler); Map statusMap = clientHandler.getResponseMap(); for (Map.Entry entry : statusMap.entrySet()) { if (entry.getValue().getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/subscription/subscription/CreateSubscriptionProcedure.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/subscription/subscription/CreateSubscriptionProcedure.java index 8710eec85225e..0894feb62ad9e 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/subscription/subscription/CreateSubscriptionProcedure.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/subscription/subscription/CreateSubscriptionProcedure.java @@ -229,6 +229,7 @@ protected void rollbackFromValidate(ConfigNodeProcedureEnv env) { protected void rollbackFromOperateOnConfigNodes(ConfigNodeProcedureEnv env) { LOGGER.info("CreateSubscriptionProcedure: rollbackFromOperateOnConfigNodes"); + // TODO: roll back from the last executed procedure to the first executed alterConsumerGroupProcedure.rollbackFromOperateOnConfigNodes(env); TSStatus response; @@ -283,6 +284,7 @@ protected void rollbackFromOperateOnConfigNodes(ConfigNodeProcedureEnv env) { protected void rollbackFromOperateOnDataNodes(ConfigNodeProcedureEnv env) throws IOException { LOGGER.info("CreateSubscriptionProcedure: rollbackFromOperateOnDataNodes"); + // TODO: roll back from the last executed procedure to the first executed alterConsumerGroupProcedure.rollbackFromOperateOnDataNodes(env); // Push all topic metas to datanode, may be time-consuming diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/subscription/subscription/DropSubscriptionProcedure.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/subscription/subscription/DropSubscriptionProcedure.java index efb5aa228272d..89da284ac0d95 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/subscription/subscription/DropSubscriptionProcedure.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/subscription/subscription/DropSubscriptionProcedure.java @@ -62,9 +62,10 @@ public class DropSubscriptionProcedure extends AbstractOperateSubscriptionAndPip private TUnsubscribeReq unsubscribeReq; - private AlterConsumerGroupProcedure alterConsumerGroupProcedure; - private List alterTopicProcedures = new ArrayList<>(); + // NOTE: The 'drop pipe' operation should be performed before 'alter consumer group'. private List dropPipeProcedures = new ArrayList<>(); + private List alterTopicProcedures = new ArrayList<>(); + private AlterConsumerGroupProcedure alterConsumerGroupProcedure; // Record failed index of procedures to rollback properly. // We only record fail index when executing on config nodes, because when executing on data nodes @@ -76,7 +77,7 @@ public DropSubscriptionProcedure() { super(); } - public DropSubscriptionProcedure(TUnsubscribeReq unsubscribeReq) { + public DropSubscriptionProcedure(final TUnsubscribeReq unsubscribeReq) { this.unsubscribeReq = unsubscribeReq; } @@ -86,27 +87,28 @@ protected SubscriptionOperation getOperation() { } @Override - protected void executeFromValidate(ConfigNodeProcedureEnv env) throws SubscriptionException { + protected void executeFromValidate(final ConfigNodeProcedureEnv env) + throws SubscriptionException { LOGGER.info("DropSubscriptionProcedure: executeFromValidate"); subscriptionInfo.get().validateBeforeUnsubscribe(unsubscribeReq); // Construct AlterConsumerGroupProcedure - ConsumerGroupMeta updatedConsumerGroupMeta = + final ConsumerGroupMeta updatedConsumerGroupMeta = subscriptionInfo.get().deepCopyConsumerGroupMeta(unsubscribeReq.getConsumerGroupId()); // Get topics subscribed by no consumers in this group after this un-subscription - Set topicsUnsubByGroup = + final Set topicsUnsubByGroup = updatedConsumerGroupMeta.removeSubscription( unsubscribeReq.getConsumerId(), unsubscribeReq.getTopicNames()); alterConsumerGroupProcedure = new AlterConsumerGroupProcedure(updatedConsumerGroupMeta, subscriptionInfo); - for (String topic : unsubscribeReq.getTopicNames()) { + for (final String topic : unsubscribeReq.getTopicNames()) { if (topicsUnsubByGroup.contains(topic)) { // Topic will be subscribed by no consumers in this group - TopicMeta updatedTopicMeta = subscriptionInfo.get().deepCopyTopicMeta(topic); + final TopicMeta updatedTopicMeta = subscriptionInfo.get().deepCopyTopicMeta(topic); updatedTopicMeta.removeSubscribedConsumerGroup(unsubscribeReq.getConsumerGroupId()); alterTopicProcedures.add(new AlterTopicProcedure(updatedTopicMeta, subscriptionInfo)); @@ -118,38 +120,39 @@ protected void executeFromValidate(ConfigNodeProcedureEnv env) throws Subscripti } } - alterConsumerGroupProcedure.executeFromValidate(env); + // Validate DropPipeProcedureV2s + for (final DropPipeProcedureV2 dropPipeProcedure : dropPipeProcedures) { + dropPipeProcedure.executeFromValidateTask(env); + dropPipeProcedure.executeFromCalculateInfoForTask(env); + } - for (AlterTopicProcedure alterTopicProcedure : alterTopicProcedures) { + // Validate AlterTopicProcedures + for (final AlterTopicProcedure alterTopicProcedure : alterTopicProcedures) { alterTopicProcedure.executeFromValidate(env); } - for (DropPipeProcedureV2 dropPipeProcedure : dropPipeProcedures) { - dropPipeProcedure.executeFromValidateTask(env); - dropPipeProcedure.executeFromCalculateInfoForTask(env); - } + // Validate AlterConsumerGroupProcedure + alterConsumerGroupProcedure.executeFromValidate(env); } @Override - protected void executeFromOperateOnConfigNodes(ConfigNodeProcedureEnv env) + protected void executeFromOperateOnConfigNodes(final ConfigNodeProcedureEnv env) throws SubscriptionException { LOGGER.info("DropSubscriptionProcedure: executeFromOperateOnConfigNodes"); - alterConsumerGroupProcedure.executeFromOperateOnConfigNodes(env); - TSStatus response; - List alterTopicPlans = - alterTopicProcedures.stream() - .map(AlterTopicProcedure::getUpdatedTopicMeta) - .map(AlterTopicPlan::new) + // Execute DropPipeProcedureV2s + final List dropPipePlans = + dropPipeProcedures.stream() + .map(proc -> new DropPipePlanV2(proc.getPipeName())) .collect(Collectors.toList()); try { response = env.getConfigManager() .getConsensusManager() - .write(new AlterMultipleTopicsPlan(alterTopicPlans)); - } catch (ConsensusException e) { + .write(new OperateMultiplePipesPlanV2(dropPipePlans)); + } catch (final ConsensusException e) { LOGGER.warn("Failed in the write API executing the consensus layer due to: ", e); response = new TSStatus(TSStatusCode.EXECUTE_STATEMENT_ERROR.getStatusCode()); response.setMessage(e.getMessage()); @@ -157,19 +160,21 @@ protected void executeFromOperateOnConfigNodes(ConfigNodeProcedureEnv env) if (response.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode() && response.getSubStatusSize() > 0) { // Record the failed index for rollback - alterTopicProcedureFailIndexOnCN = response.getSubStatusSize() - 1; + dropPipeProcedureFailIndexOnCN = response.getSubStatusSize() - 1; } - List dropPipePlans = - dropPipeProcedures.stream() - .map(proc -> new DropPipePlanV2(proc.getPipeName())) + // Execute AlterTopicProcedures + final List alterTopicPlans = + alterTopicProcedures.stream() + .map(AlterTopicProcedure::getUpdatedTopicMeta) + .map(AlterTopicPlan::new) .collect(Collectors.toList()); try { response = env.getConfigManager() .getConsensusManager() - .write(new OperateMultiplePipesPlanV2(dropPipePlans)); - } catch (ConsensusException e) { + .write(new AlterMultipleTopicsPlan(alterTopicPlans)); + } catch (final ConsensusException e) { LOGGER.warn("Failed in the write API executing the consensus layer due to: ", e); response = new TSStatus(TSStatusCode.EXECUTE_STATEMENT_ERROR.getStatusCode()); response.setMessage(e.getMessage()); @@ -177,34 +182,24 @@ protected void executeFromOperateOnConfigNodes(ConfigNodeProcedureEnv env) if (response.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode() && response.getSubStatusSize() > 0) { // Record the failed index for rollback - dropPipeProcedureFailIndexOnCN = response.getSubStatusSize() - 1; + alterTopicProcedureFailIndexOnCN = response.getSubStatusSize() - 1; } + + // Execute AlterConsumerGroupProcedure + alterConsumerGroupProcedure.executeFromOperateOnConfigNodes(env); } @Override - protected void executeFromOperateOnDataNodes(ConfigNodeProcedureEnv env) + protected void executeFromOperateOnDataNodes(final ConfigNodeProcedureEnv env) throws SubscriptionException, IOException { LOGGER.info("DropSubscriptionProcedure: executeFromOperateOnDataNodes"); - alterConsumerGroupProcedure.executeFromOperateOnDataNodes(env); - - // push topic meta to data nodes - List topicMetaBinaryList = new ArrayList<>(); - for (AlterTopicProcedure alterTopicProcedure : alterTopicProcedures) { - topicMetaBinaryList.add(alterTopicProcedure.getUpdatedTopicMeta().serialize()); - } - if (pushTopicMetaHasException(env.pushMultiTopicMetaToDataNodes(topicMetaBinaryList))) { - // If not all topic meta are pushed successfully, the meta can be pushed during meta sync. - LOGGER.warn( - "Failed to alter topics when creating subscription, metadata will be synchronized later."); - } - - // push pipe meta to data nodes - List pipeNames = + // Push pipe meta to data nodes + final List pipeNames = dropPipeProcedures.stream() .map(DropPipeProcedureV2::getPipeName) .collect(Collectors.toList()); - String exceptionMessage = + final String exceptionMessage = AbstractOperatePipeProcedureV2.parsePushPipeMetaExceptionForPipe( null, dropMultiPipeOnDataNodes(pipeNames, env)); if (!exceptionMessage.isEmpty()) { @@ -214,23 +209,37 @@ protected void executeFromOperateOnDataNodes(ConfigNodeProcedureEnv env) pipeNames, exceptionMessage); } + + // Push topic meta to data nodes + final List topicMetaBinaryList = new ArrayList<>(); + for (final AlterTopicProcedure alterTopicProcedure : alterTopicProcedures) { + topicMetaBinaryList.add(alterTopicProcedure.getUpdatedTopicMeta().serialize()); + } + if (pushTopicMetaHasException(env.pushMultiTopicMetaToDataNodes(topicMetaBinaryList))) { + // If not all topic meta are pushed successfully, the meta can be pushed during meta sync. + LOGGER.warn( + "Failed to alter topics when creating subscription, metadata will be synchronized later."); + } + + // Push consumer group meta to data nodes + alterConsumerGroupProcedure.executeFromOperateOnDataNodes(env); } @Override - protected void rollbackFromValidate(ConfigNodeProcedureEnv env) { + protected void rollbackFromValidate(final ConfigNodeProcedureEnv env) { LOGGER.info("DropSubscriptionProcedure: rollbackFromLock"); } @Override - protected void rollbackFromOperateOnConfigNodes(ConfigNodeProcedureEnv env) { + protected void rollbackFromOperateOnConfigNodes(final ConfigNodeProcedureEnv env) { LOGGER.info("DropSubscriptionProcedure: rollbackFromOperateOnConfigNodes"); + // Rollback AlterConsumerGroupProcedure alterConsumerGroupProcedure.rollbackFromOperateOnConfigNodes(env); + // Rollback AlterTopicProcedures TSStatus response; - - // rollback alterTopicProcedures - List alterTopicRollbackPlans = new ArrayList<>(); + final List alterTopicRollbackPlans = new ArrayList<>(); for (int i = 0; i <= Math.min(alterTopicProcedureFailIndexOnCN, alterTopicProcedures.size()); i++) { @@ -242,23 +251,25 @@ protected void rollbackFromOperateOnConfigNodes(ConfigNodeProcedureEnv env) { env.getConfigManager() .getConsensusManager() .write(new AlterMultipleTopicsPlan(alterTopicRollbackPlans)); - } catch (ConsensusException e) { + } catch (final ConsensusException e) { LOGGER.warn("Failed in the write API executing the consensus layer due to: ", e); response = new TSStatus(TSStatusCode.EXECUTE_STATEMENT_ERROR.getStatusCode()); response.setMessage(e.getMessage()); } - // if failed to rollback, throw exception + // If failed to rollback, throw exception if (response.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { throw new SubscriptionException(response.getMessage()); } - // Do nothing to rollback dropPipeProcedures + // Do nothing to rollback DropPipeProcedureV2s } @Override - protected void rollbackFromOperateOnDataNodes(ConfigNodeProcedureEnv env) throws IOException { + protected void rollbackFromOperateOnDataNodes(final ConfigNodeProcedureEnv env) + throws IOException { LOGGER.info("DropSubscriptionProcedure: rollbackFromOperateOnDataNodes"); + // Rollback AlterConsumerGroupProcedure alterConsumerGroupProcedure.rollbackFromOperateOnDataNodes(env); // Push all topic metas to datanode, may be time-consuming @@ -268,7 +279,7 @@ protected void rollbackFromOperateOnDataNodes(ConfigNodeProcedureEnv env) throws } // Push all pipe metas to datanode, may be time-consuming - String exceptionMessage = + final String exceptionMessage = AbstractOperatePipeProcedureV2.parsePushPipeMetaExceptionForPipe( null, AbstractOperatePipeProcedureV2.pushPipeMetaToDataNodes(env, pipeTaskInfo)); if (!exceptionMessage.isEmpty()) { @@ -279,7 +290,7 @@ protected void rollbackFromOperateOnDataNodes(ConfigNodeProcedureEnv env) throws } @Override - public void serialize(DataOutputStream stream) throws IOException { + public void serialize(final DataOutputStream stream) throws IOException { stream.writeShort(ProcedureType.DROP_SUBSCRIPTION_PROCEDURE.getTypeCode()); super.serialize(stream); @@ -289,7 +300,7 @@ public void serialize(DataOutputStream stream) throws IOException { final int size = unsubscribeReq.getTopicNamesSize(); ReadWriteIOUtils.write(size, stream); if (size != 0) { - for (String topicName : unsubscribeReq.getTopicNames()) { + for (final String topicName : unsubscribeReq.getTopicNames()) { ReadWriteIOUtils.write(topicName, stream); } } @@ -306,7 +317,7 @@ public void serialize(DataOutputStream stream) throws IOException { if (alterTopicProcedures != null) { ReadWriteIOUtils.write(true, stream); ReadWriteIOUtils.write(alterTopicProcedures.size(), stream); - for (AlterTopicProcedure topicProcedure : alterTopicProcedures) { + for (final AlterTopicProcedure topicProcedure : alterTopicProcedures) { topicProcedure.serialize(stream); } } else { @@ -317,7 +328,7 @@ public void serialize(DataOutputStream stream) throws IOException { if (dropPipeProcedures != null) { ReadWriteIOUtils.write(true, stream); ReadWriteIOUtils.write(dropPipeProcedures.size(), stream); - for (AbstractOperatePipeProcedureV2 pipeProcedure : dropPipeProcedures) { + for (final AbstractOperatePipeProcedureV2 pipeProcedure : dropPipeProcedures) { pipeProcedure.serialize(stream); } } else { @@ -326,7 +337,7 @@ public void serialize(DataOutputStream stream) throws IOException { } @Override - public void deserialize(ByteBuffer byteBuffer) { + public void deserialize(final ByteBuffer byteBuffer) { super.deserialize(byteBuffer); unsubscribeReq = @@ -355,7 +366,7 @@ public void deserialize(ByteBuffer byteBuffer) { // This readShort should return ALTER_TOPIC_PROCEDURE, and we ignore it. ReadWriteIOUtils.readShort(byteBuffer); - AlterTopicProcedure topicProcedure = new AlterTopicProcedure(); + final AlterTopicProcedure topicProcedure = new AlterTopicProcedure(); topicProcedure.deserialize(byteBuffer); alterTopicProcedures.add(topicProcedure); } @@ -366,9 +377,9 @@ public void deserialize(ByteBuffer byteBuffer) { size = ReadWriteIOUtils.readInt(byteBuffer); for (int i = 0; i < size; ++i) { // This readShort should return DROP_PIPE_PROCEDURE. - short typeCode = ReadWriteIOUtils.readShort(byteBuffer); + final short typeCode = ReadWriteIOUtils.readShort(byteBuffer); if (typeCode == ProcedureType.DROP_PIPE_PROCEDURE_V2.getTypeCode()) { - DropPipeProcedureV2 dropPipeProcedureV2 = new DropPipeProcedureV2(); + final DropPipeProcedureV2 dropPipeProcedureV2 = new DropPipeProcedureV2(); dropPipeProcedureV2.deserialize(byteBuffer); dropPipeProcedures.add(dropPipeProcedureV2); } @@ -377,14 +388,14 @@ public void deserialize(ByteBuffer byteBuffer) { } @Override - public boolean equals(Object o) { + public boolean equals(final Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } - DropSubscriptionProcedure that = (DropSubscriptionProcedure) o; + final DropSubscriptionProcedure that = (DropSubscriptionProcedure) o; return Objects.equals(getProcId(), that.getProcId()) && Objects.equals(getCurrentState(), that.getCurrentState()) && getCycles() == that.getCycles() @@ -408,7 +419,7 @@ public int hashCode() { @TestOnly public void setAlterConsumerGroupProcedure( - AlterConsumerGroupProcedure alterConsumerGroupProcedure) { + final AlterConsumerGroupProcedure alterConsumerGroupProcedure) { this.alterConsumerGroupProcedure = alterConsumerGroupProcedure; } @@ -418,7 +429,7 @@ public AlterConsumerGroupProcedure getAlterConsumerGroupProcedure() { } @TestOnly - public void setAlterTopicProcedures(List alterTopicProcedures) { + public void setAlterTopicProcedures(final List alterTopicProcedures) { this.alterTopicProcedures = alterTopicProcedures; } @@ -428,7 +439,7 @@ public List getAlterTopicProcedures() { } @TestOnly - public void setDropPipeProcedures(List dropPipeProcedures) { + public void setDropPipeProcedures(final List dropPipeProcedures) { this.dropPipeProcedures = dropPipeProcedures; } diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/sync/AuthOperationProcedure.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/sync/AuthOperationProcedure.java index badc5d2aa96b4..d8e999cd18789 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/sync/AuthOperationProcedure.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/impl/sync/AuthOperationProcedure.java @@ -25,7 +25,7 @@ import org.apache.iotdb.commons.conf.CommonDescriptor; import org.apache.iotdb.commons.exception.IoTDBException; import org.apache.iotdb.commons.utils.ThriftCommonsSerDeUtils; -import org.apache.iotdb.confignode.client.DataNodeRequestType; +import org.apache.iotdb.confignode.client.CnToDnRequestType; import org.apache.iotdb.confignode.client.sync.SyncDataNodeClientPool; import org.apache.iotdb.confignode.consensus.request.ConfigPhysicalPlan; import org.apache.iotdb.confignode.consensus.request.auth.AuthorPlan; @@ -112,7 +112,7 @@ protected Flow executeFromState(ConfigNodeProcedureEnv env, AuthOperationProcedu .sendSyncRequestToDataNodeWithRetry( pair.getLeft().getLocation().getInternalEndPoint(), req, - DataNodeRequestType.INVALIDATE_PERMISSION_CACHE); + CnToDnRequestType.INVALIDATE_PERMISSION_CACHE); if (status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { it.remove(); } diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/ConfigNode.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/ConfigNode.java index eb33b0d70eba9..3d537cdec61f7 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/ConfigNode.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/ConfigNode.java @@ -38,7 +38,7 @@ import org.apache.iotdb.commons.service.metric.MetricService; import org.apache.iotdb.commons.service.metric.cpu.CpuUsageMetrics; import org.apache.iotdb.commons.utils.TestOnly; -import org.apache.iotdb.confignode.client.ConfigNodeRequestType; +import org.apache.iotdb.confignode.client.CnToCnNodeRequestType; import org.apache.iotdb.confignode.client.sync.SyncConfigNodeClientPool; import org.apache.iotdb.confignode.conf.ConfigNodeConfig; import org.apache.iotdb.confignode.conf.ConfigNodeConstant; @@ -186,7 +186,7 @@ public void active() { configManager .getNodeManager() .applyConfigNode( - generateConfigNodeLocation(SEED_CONFIG_NODE_ID), + CONF.generateLocalConfigNodeLocationWithSpecifiedNodeId(SEED_CONFIG_NODE_ID), new TNodeVersionInfo(IoTDBConstant.VERSION, IoTDBConstant.BUILD_INFO)); setUpMetricService(); // Notice: We always set up Seed-ConfigNode's RPC service lastly to ensure @@ -323,7 +323,7 @@ private void sendRegisterConfigNodeRequest() throws StartupException, IOExceptio TConfigNodeRegisterReq req = new TConfigNodeRegisterReq( configManager.getClusterParameters(), - generateConfigNodeLocation(INIT_NON_SEED_CONFIG_NODE_ID)); + CONF.generateLocalConfigNodeLocationWithSpecifiedNodeId(INIT_NON_SEED_CONFIG_NODE_ID)); req.setVersionInfo(new TNodeVersionInfo(IoTDBConstant.VERSION, IoTDBConstant.BUILD_INFO)); @@ -339,7 +339,7 @@ private void sendRegisterConfigNodeRequest() throws StartupException, IOExceptio Object obj = SyncConfigNodeClientPool.getInstance() .sendSyncRequestToConfigNodeWithRetry( - seedConfigNode, req, ConfigNodeRequestType.REGISTER_CONFIG_NODE); + seedConfigNode, req, CnToCnNodeRequestType.REGISTER_CONFIG_NODE); if (obj instanceof TConfigNodeRegisterResp) { resp = (TConfigNodeRegisterResp) obj; diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/ConfigNodeShutdownHook.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/ConfigNodeShutdownHook.java index 369c6c96af84a..5c3ec5af06322 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/ConfigNodeShutdownHook.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/ConfigNodeShutdownHook.java @@ -24,7 +24,7 @@ import org.apache.iotdb.common.rpc.thrift.TSStatus; import org.apache.iotdb.commons.cluster.NodeStatus; import org.apache.iotdb.commons.conf.CommonDescriptor; -import org.apache.iotdb.confignode.client.ConfigNodeRequestType; +import org.apache.iotdb.confignode.client.CnToCnNodeRequestType; import org.apache.iotdb.confignode.client.sync.SyncConfigNodeClientPool; import org.apache.iotdb.confignode.conf.ConfigNodeConfig; import org.apache.iotdb.confignode.conf.ConfigNodeConstant; @@ -71,7 +71,7 @@ public void run() { CONF.getConfigNodeId(), new TEndPoint(CONF.getInternalAddress(), CONF.getInternalPort()), new TEndPoint(CONF.getInternalAddress(), CONF.getConsensusPort())), - ConfigNodeRequestType.REPORT_CONFIG_NODE_SHUTDOWN); + CnToCnNodeRequestType.REPORT_CONFIG_NODE_SHUTDOWN); if (result.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { // Report success diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java index d68430f318157..28978ab664832 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/ConfigNodeRPCServiceProcessor.java @@ -22,12 +22,15 @@ import org.apache.iotdb.common.rpc.thrift.TConfigNodeLocation; import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; import org.apache.iotdb.common.rpc.thrift.TFlushReq; +import org.apache.iotdb.common.rpc.thrift.TNodeLocations; import org.apache.iotdb.common.rpc.thrift.TSStatus; import org.apache.iotdb.common.rpc.thrift.TSetConfigurationReq; import org.apache.iotdb.common.rpc.thrift.TSetSpaceQuotaReq; import org.apache.iotdb.common.rpc.thrift.TSetTTLReq; import org.apache.iotdb.common.rpc.thrift.TSetThrottleQuotaReq; import org.apache.iotdb.common.rpc.thrift.TShowConfigurationResp; +import org.apache.iotdb.common.rpc.thrift.TShowTTLReq; +import org.apache.iotdb.common.rpc.thrift.TTestConnectionResp; import org.apache.iotdb.commons.conf.CommonDescriptor; import org.apache.iotdb.commons.consensus.ConsensusGroupId; import org.apache.iotdb.commons.path.PartialPath; @@ -493,8 +496,10 @@ public TDatabaseSchemaResp getMatchedDatabaseSchemas(TGetDatabaseReq req) { } @Override - public TShowTTLResp showAllTTL() { - ShowTTLResp showTTLResp = (ShowTTLResp) configManager.showAllTTL(new ShowTTLPlan()); + public TShowTTLResp showTTL(TShowTTLReq req) { + ShowTTLResp showTTLResp = + (ShowTTLResp) + configManager.showTTL(new ShowTTLPlan(req.getPathPattern().toArray(new String[0]))); return showTTLResp.convertToRPCTShowTTLResp(); } @@ -894,6 +899,25 @@ public TShowDatabaseResp showDatabase(TGetDatabaseReq req) { return configManager.showDatabase(req); } + /** Call by ConfigNode leader */ + @Override + public TTestConnectionResp submitTestConnectionTask(TNodeLocations nodeLocations) + throws TException { + return configManager.getClusterManager().doConnectionTest(nodeLocations); + } + + /** Call by client connected DataNode */ + @Override + public TTestConnectionResp submitTestConnectionTaskToLeader() throws TException { + return configManager.getClusterManager().submitTestConnectionTaskToEveryNode(); + } + + /** Call by every other nodes */ + @Override + public TSStatus testConnectionEmptyRPC() throws TException { + return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()); + } + @Override public TSStatus createSchemaTemplate(TCreateSchemaTemplateReq req) { return configManager.createSchemaTemplate(req); diff --git a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/NodeInfoTest.java b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/NodeInfoTest.java index 959eeba114d9f..5ce94932036df 100644 --- a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/NodeInfoTest.java +++ b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/NodeInfoTest.java @@ -24,6 +24,7 @@ import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; import org.apache.iotdb.common.rpc.thrift.TEndPoint; import org.apache.iotdb.common.rpc.thrift.TNodeResource; +import org.apache.iotdb.commons.exception.StartupException; import org.apache.iotdb.confignode.consensus.request.write.confignode.ApplyConfigNodePlan; import org.apache.iotdb.confignode.consensus.request.write.datanode.RegisterDataNodePlan; import org.apache.iotdb.confignode.persistence.node.NodeInfo; @@ -46,7 +47,7 @@ public class NodeInfoTest { private static final File snapshotDir = new File(BASE_OUTPUT_PATH, "snapshot"); @BeforeClass - public static void setup() { + public static void setup() throws StartupException { nodeInfo = new NodeInfo(); if (!snapshotDir.exists()) { snapshotDir.mkdirs(); diff --git a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/TTLInfoTest.java b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/TTLInfoTest.java index 80dc2ed4d31ce..2468914ea2b58 100644 --- a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/TTLInfoTest.java +++ b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/persistence/TTLInfoTest.java @@ -21,6 +21,7 @@ import org.apache.iotdb.commons.conf.CommonDescriptor; import org.apache.iotdb.commons.exception.IllegalPathException; import org.apache.iotdb.commons.path.PartialPath; +import org.apache.iotdb.confignode.consensus.request.read.ttl.ShowTTLPlan; import org.apache.iotdb.confignode.consensus.request.write.database.SetTTLPlan; import org.apache.iotdb.confignode.consensus.response.ttl.ShowTTLResp; @@ -68,7 +69,7 @@ public void tearDown() throws IOException { @Test public void testSetAndUnsetTTL() throws IllegalPathException { - ShowTTLResp resp = ttlInfo.showAllTTL(); + ShowTTLResp resp = ttlInfo.showTTL(new ShowTTLPlan()); Map ttlMap = resp.getPathTTLMap(); Map resultMap = new HashMap<>(); @@ -80,125 +81,125 @@ public void testSetAndUnsetTTL() throws IllegalPathException { PartialPath path = new PartialPath("root.test.db1.**"); ttlInfo.setTTL(new SetTTLPlan(Arrays.asList(path.getNodes()), 121322323L)); resultMap.put(path.getFullPath(), 121322323L); - Assert.assertEquals(resultMap, ttlInfo.showAllTTL().getPathTTLMap()); + Assert.assertEquals(resultMap, ttlInfo.showTTL(new ShowTTLPlan()).getPathTTLMap()); Assert.assertEquals(2, ttlInfo.getTTLCount()); // set ttl path = new PartialPath("root.test.db1.group1.group1.d1"); ttlInfo.setTTL(new SetTTLPlan(Arrays.asList(path.getNodes()), 2222L)); resultMap.put(path.getFullPath(), 2222L); - Assert.assertEquals(resultMap, ttlInfo.showAllTTL().getPathTTLMap()); + Assert.assertEquals(resultMap, ttlInfo.showTTL(new ShowTTLPlan()).getPathTTLMap()); Assert.assertEquals(3, ttlInfo.getTTLCount()); // set ttl path = new PartialPath("root.test.db1.group1.group2.d1"); ttlInfo.setTTL(new SetTTLPlan(Arrays.asList(path.getNodes()), 1)); resultMap.put(path.getFullPath(), 1L); - Assert.assertEquals(resultMap, ttlInfo.showAllTTL().getPathTTLMap()); + Assert.assertEquals(resultMap, ttlInfo.showTTL(new ShowTTLPlan()).getPathTTLMap()); Assert.assertEquals(4, ttlInfo.getTTLCount()); // set ttl path = new PartialPath("root.test1.db1.group1.group2.d1"); ttlInfo.setTTL(new SetTTLPlan(Arrays.asList(path.getNodes()), 599722L)); resultMap.put(path.getFullPath(), 599722L); - Assert.assertEquals(resultMap, ttlInfo.showAllTTL().getPathTTLMap()); + Assert.assertEquals(resultMap, ttlInfo.showTTL(new ShowTTLPlan()).getPathTTLMap()); Assert.assertEquals(5, ttlInfo.getTTLCount()); // set ttl path = new PartialPath("root.test1.db1.group1.group2.d1.**"); ttlInfo.setTTL(new SetTTLPlan(Arrays.asList(path.getNodes()), 9999999L)); resultMap.put(path.getFullPath(), 9999999L); - Assert.assertEquals(resultMap, ttlInfo.showAllTTL().getPathTTLMap()); + Assert.assertEquals(resultMap, ttlInfo.showTTL(new ShowTTLPlan()).getPathTTLMap()); Assert.assertEquals(6, ttlInfo.getTTLCount()); // set ttl path = new PartialPath("root.test1.db1.group1.group2.d1.d2.**"); ttlInfo.setTTL(new SetTTLPlan(Arrays.asList(path.getNodes()), 888888L)); resultMap.put(path.getFullPath(), 888888L); - Assert.assertEquals(resultMap, ttlInfo.showAllTTL().getPathTTLMap()); + Assert.assertEquals(resultMap, ttlInfo.showTTL(new ShowTTLPlan()).getPathTTLMap()); Assert.assertEquals(7, ttlInfo.getTTLCount()); // set ttl path = new PartialPath("root.test1.db1.group1.group2.d1.d2"); ttlInfo.setTTL(new SetTTLPlan(Arrays.asList(path.getNodes()), 9898989898L)); resultMap.put(path.getFullPath(), 9898989898L); - Assert.assertEquals(resultMap, ttlInfo.showAllTTL().getPathTTLMap()); + Assert.assertEquals(resultMap, ttlInfo.showTTL(new ShowTTLPlan()).getPathTTLMap()); Assert.assertEquals(8, ttlInfo.getTTLCount()); // set ttl path = new PartialPath("root.test.db1.group1.group2.d1"); ttlInfo.setTTL(new SetTTLPlan(Arrays.asList(path.getNodes()), 11111222L)); resultMap.put(path.getFullPath(), 11111222L); - Assert.assertEquals(resultMap, ttlInfo.showAllTTL().getPathTTLMap()); + Assert.assertEquals(resultMap, ttlInfo.showTTL(new ShowTTLPlan()).getPathTTLMap()); Assert.assertEquals(8, ttlInfo.getTTLCount()); // set ttl path = new PartialPath("root.test.db1.group1"); ttlInfo.setTTL(new SetTTLPlan(Arrays.asList(path.getNodes()), Long.MAX_VALUE)); resultMap.put(path.getFullPath(), Long.MAX_VALUE); - Assert.assertEquals(resultMap, ttlInfo.showAllTTL().getPathTTLMap()); + Assert.assertEquals(resultMap, ttlInfo.showTTL(new ShowTTLPlan()).getPathTTLMap()); Assert.assertEquals(9, ttlInfo.getTTLCount()); // set ttl path = new PartialPath("root.**"); ttlInfo.setTTL(new SetTTLPlan(Arrays.asList(path.getNodes()), 222222L)); resultMap.put(path.getFullPath(), 222222L); - Assert.assertEquals(resultMap, ttlInfo.showAllTTL().getPathTTLMap()); + Assert.assertEquals(resultMap, ttlInfo.showTTL(new ShowTTLPlan()).getPathTTLMap()); Assert.assertEquals(9, ttlInfo.getTTLCount()); // set ttl, not support negative ttl path = new PartialPath("root.test.db1.group1.group2"); ttlInfo.setTTL(new SetTTLPlan(Arrays.asList(path.getNodes()), -1)); - Assert.assertEquals(resultMap, ttlInfo.showAllTTL().getPathTTLMap()); + Assert.assertEquals(resultMap, ttlInfo.showTTL(new ShowTTLPlan()).getPathTTLMap()); Assert.assertEquals(9, ttlInfo.getTTLCount()); // unset ttl path = new PartialPath("root.test.db1.group1.group2"); ttlInfo.unsetTTL(new SetTTLPlan(Arrays.asList(path.getNodes()), -1)); resultMap.remove(path.getFullPath()); - Assert.assertEquals(resultMap, ttlInfo.showAllTTL().getPathTTLMap()); + Assert.assertEquals(resultMap, ttlInfo.showTTL(new ShowTTLPlan()).getPathTTLMap()); Assert.assertEquals(9, ttlInfo.getTTLCount()); // unset ttl path = new PartialPath("root.test.db1.group1"); ttlInfo.unsetTTL(new SetTTLPlan(Arrays.asList(path.getNodes()), -1)); resultMap.remove(path.getFullPath()); - Assert.assertEquals(resultMap, ttlInfo.showAllTTL().getPathTTLMap()); + Assert.assertEquals(resultMap, ttlInfo.showTTL(new ShowTTLPlan()).getPathTTLMap()); Assert.assertEquals(8, ttlInfo.getTTLCount()); // unset ttl path = new PartialPath("root.**"); ttlInfo.unsetTTL(new SetTTLPlan(Arrays.asList(path.getNodes()), -1)); resultMap.put(path.getFullPath(), ttl); - Assert.assertEquals(resultMap, ttlInfo.showAllTTL().getPathTTLMap()); + Assert.assertEquals(resultMap, ttlInfo.showTTL(new ShowTTLPlan()).getPathTTLMap()); Assert.assertEquals(8, ttlInfo.getTTLCount()); // unset ttl path = new PartialPath("root.test1.db1.group1.group2.d1.d2"); ttlInfo.unsetTTL(new SetTTLPlan(Arrays.asList(path.getNodes()), -1)); resultMap.remove(path.getFullPath()); - Assert.assertEquals(resultMap, ttlInfo.showAllTTL().getPathTTLMap()); + Assert.assertEquals(resultMap, ttlInfo.showTTL(new ShowTTLPlan()).getPathTTLMap()); Assert.assertEquals(7, ttlInfo.getTTLCount()); // unset ttl path = new PartialPath("root.test.db1.**"); ttlInfo.unsetTTL(new SetTTLPlan(Arrays.asList(path.getNodes()), -1)); resultMap.remove(path.getFullPath()); - Assert.assertEquals(resultMap, ttlInfo.showAllTTL().getPathTTLMap()); + Assert.assertEquals(resultMap, ttlInfo.showTTL(new ShowTTLPlan()).getPathTTLMap()); Assert.assertEquals(6, ttlInfo.getTTLCount()); // unset ttl path = new PartialPath("root.test1.db1.group1.group2.d1"); ttlInfo.unsetTTL(new SetTTLPlan(Arrays.asList(path.getNodes()), -1)); resultMap.remove(path.getFullPath()); - Assert.assertEquals(resultMap, ttlInfo.showAllTTL().getPathTTLMap()); + Assert.assertEquals(resultMap, ttlInfo.showTTL(new ShowTTLPlan()).getPathTTLMap()); Assert.assertEquals(5, ttlInfo.getTTLCount()); // unset ttl path = new PartialPath("root.test1.db1.group1.group2.d1.d2.**"); ttlInfo.unsetTTL(new SetTTLPlan(Arrays.asList(path.getNodes()), -1)); resultMap.remove(path.getFullPath()); - Assert.assertEquals(resultMap, ttlInfo.showAllTTL().getPathTTLMap()); + Assert.assertEquals(resultMap, ttlInfo.showTTL(new ShowTTLPlan()).getPathTTLMap()); Assert.assertEquals(4, ttlInfo.getTTLCount()); } diff --git a/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/ConsensusFactory.java b/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/ConsensusFactory.java index 7742baf3bdccf..8cab79e315e4a 100644 --- a/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/ConsensusFactory.java +++ b/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/ConsensusFactory.java @@ -22,6 +22,7 @@ import org.apache.iotdb.commons.client.container.PipeConsensusClientMgrContainer; import org.apache.iotdb.consensus.config.ConsensusConfig; import org.apache.iotdb.consensus.config.PipeConsensusConfig.ReplicateMode; +import org.apache.iotdb.consensus.pipe.metric.PipeConsensusSyncLagManager; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -41,13 +42,13 @@ public class ConsensusFactory { public static final String IOT_CONSENSUS = "org.apache.iotdb.consensus.iot.IoTConsensus"; public static final String REAL_PIPE_CONSENSUS = "org.apache.iotdb.consensus.pipe.PipeConsensus"; // Corresponding to streamConsensus - public static final String IOTV2_CONSENSUS = "org.apache.iotdb.consensus.iot.IoTV2Consensus"; + public static final String IOT_CONSENSUS_V2 = "org.apache.iotdb.consensus.iot.IoTConsensusV2"; // Corresponding to batchConsensus public static final String FAST_IOT_CONSENSUS = "org.apache.iotdb.consensus.iot.FastIoTConsensus"; private static final Map PIPE_CONSENSUS_MODE_MAP = new HashMap<>(); static { - PIPE_CONSENSUS_MODE_MAP.put(IOTV2_CONSENSUS, ReplicateMode.STREAM); + PIPE_CONSENSUS_MODE_MAP.put(IOT_CONSENSUS_V2, ReplicateMode.STREAM); PIPE_CONSENSUS_MODE_MAP.put(FAST_IOT_CONSENSUS, ReplicateMode.BATCH); } @@ -61,11 +62,13 @@ public static Optional getConsensusImpl( String className, ConsensusConfig config, IStateMachine.Registry registry) { try { // special judge for PipeConsensus - if (className.equals(IOTV2_CONSENSUS) || className.equals(FAST_IOT_CONSENSUS)) { + if (className.equals(IOT_CONSENSUS_V2) || className.equals(FAST_IOT_CONSENSUS)) { config.getPipeConsensusConfig().setReplicateMode(PIPE_CONSENSUS_MODE_MAP.get(className)); className = REAL_PIPE_CONSENSUS; // initialize pipeConsensus' thrift component PipeConsensusClientMgrContainer.build(); + // initialize pipeConsensus's metric component + PipeConsensusSyncLagManager.build(); } Class executor = Class.forName(className); Constructor executorConstructor = diff --git a/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/pipe/PipeConsensusServerImpl.java b/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/pipe/PipeConsensusServerImpl.java index f4a64fc691bfe..95d5a23cdc2fa 100644 --- a/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/pipe/PipeConsensusServerImpl.java +++ b/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/pipe/PipeConsensusServerImpl.java @@ -28,15 +28,19 @@ import org.apache.iotdb.commons.consensus.index.ProgressIndex; import org.apache.iotdb.commons.consensus.index.impl.MinimumProgressIndex; import org.apache.iotdb.commons.pipe.task.meta.PipeStatus; +import org.apache.iotdb.commons.service.metric.MetricService; +import org.apache.iotdb.commons.service.metric.PerformanceOverviewMetrics; import org.apache.iotdb.consensus.IStateMachine; import org.apache.iotdb.consensus.common.DataSet; import org.apache.iotdb.consensus.common.Peer; import org.apache.iotdb.consensus.common.request.IConsensusRequest; import org.apache.iotdb.consensus.config.PipeConsensusConfig; +import org.apache.iotdb.consensus.config.PipeConsensusConfig.ReplicateMode; import org.apache.iotdb.consensus.exception.ConsensusGroupModifyPeerException; import org.apache.iotdb.consensus.pipe.consensuspipe.ConsensusPipeManager; import org.apache.iotdb.consensus.pipe.consensuspipe.ConsensusPipeName; import org.apache.iotdb.consensus.pipe.consensuspipe.ProgressIndexManager; +import org.apache.iotdb.consensus.pipe.metric.PipeConsensusServerMetrics; import org.apache.iotdb.consensus.pipe.thrift.TCheckConsensusPipeCompletedReq; import org.apache.iotdb.consensus.pipe.thrift.TCheckConsensusPipeCompletedResp; import org.apache.iotdb.consensus.pipe.thrift.TNotifyPeerToCreateConsensusPipeReq; @@ -66,7 +70,8 @@ public class PipeConsensusServerImpl { private static final Logger LOGGER = LoggerFactory.getLogger(PipeConsensusServerImpl.class); private static final long CHECK_TRANSMISSION_COMPLETION_INTERVAL_IN_MILLISECONDS = 2_000L; - + private static final PerformanceOverviewMetrics PERFORMANCE_OVERVIEW_METRICS = + PerformanceOverviewMetrics.getInstance(); private final Peer thisNode; private final IStateMachine stateMachine; private final Lock stateMachineLock = new ReentrantLock(); @@ -77,6 +82,8 @@ public class PipeConsensusServerImpl { private final ConsensusPipeManager consensusPipeManager; private final ProgressIndexManager progressIndexManager; private final IClientManager syncClientManager; + private final PipeConsensusServerMetrics pipeConsensusServerMetrics; + private final ReplicateMode replicateMode; private ProgressIndex cachedProgressIndex = MinimumProgressIndex.INSTANCE; @@ -98,6 +105,8 @@ public PipeConsensusServerImpl( this.consensusPipeManager = consensusPipeManager; this.progressIndexManager = config.getPipe().getProgressIndexManager(); this.syncClientManager = syncClientManager; + this.pipeConsensusServerMetrics = new PipeConsensusServerMetrics(this); + this.replicateMode = config.getReplicateMode(); if (configuration.isEmpty()) { peerManager.recover(); @@ -129,6 +138,7 @@ public PipeConsensusServerImpl( public synchronized void start(boolean startConsensusPipes) throws IOException { stateMachine.start(); + MetricService.getInstance().addMetricSet(this.pipeConsensusServerMetrics); if (startConsensusPipes) { // start all consensus pipes @@ -153,7 +163,7 @@ public synchronized void stop() { // do not roll back, because it will stop anyway LOGGER.warn("{} cannot stop all consensus pipes", thisNode); } - + MetricService.getInstance().removeMetricSet(this.pipeConsensusServerMetrics); stateMachine.stop(); isStarted.set(false); } @@ -167,6 +177,7 @@ public synchronized void clear() throws IOException { LOGGER.warn("{} cannot drop all consensus pipes", thisNode); } + MetricService.getInstance().removeMetricSet(this.pipeConsensusServerMetrics); peerManager.clear(); stateMachine.stop(); isStarted.set(false); @@ -183,7 +194,11 @@ private List createConsensusPipes(List peers) { } return true; } catch (Exception e) { - LOGGER.warn("{} cannot create consensus pipe between {} and {}", thisNode, peer, e); + LOGGER.warn( + "{}: cannot create consensus pipe between {} and {}", + e.getMessage(), + thisNode, + peer); return false; } }) @@ -202,11 +217,11 @@ private List updateConsensusPipesStatus(List peers, PipeStatus statu return true; } catch (Exception e) { LOGGER.warn( - "{} cannot update consensus pipe between {} and {} to status {}", + "{}: cannot update consensus pipe between {} and {} to status {}", + e.getMessage(), thisNode, peer, - status, - e); + status); return false; } }) @@ -274,12 +289,25 @@ public synchronized void checkConsensusPipe(Map e public TSStatus write(IConsensusRequest request) { try { + long consensusWriteStartTime = System.nanoTime(); stateMachineLock.lock(); + long getStateMachineLockTime = System.nanoTime(); + // statistic the time of acquiring stateMachine lock + pipeConsensusServerMetrics.recordGetStateMachineLockTime( + getStateMachineLockTime - consensusWriteStartTime); + long writeToStateMachineStartTime = System.nanoTime(); if (request instanceof ComparableConsensusRequest) { ((ComparableConsensusRequest) request) .setProgressIndex(progressIndexManager.assignProgressIndex(thisNode.getGroupId())); } - return stateMachine.write(request); + TSStatus result = stateMachine.write(request); + long writeToStateMachineEndTime = System.nanoTime(); + PERFORMANCE_OVERVIEW_METRICS.recordEngineCost( + writeToStateMachineEndTime - writeToStateMachineStartTime); + // statistic the time of writing request into stateMachine + pipeConsensusServerMetrics.recordUserWriteStateMachineTime( + writeToStateMachineEndTime - writeToStateMachineStartTime); + return result; } finally { stateMachineLock.unlock(); } @@ -287,8 +315,23 @@ public TSStatus write(IConsensusRequest request) { public TSStatus writeOnFollowerReplica(IConsensusRequest request) { try { + long consensusWriteStartTime = System.nanoTime(); stateMachineLock.lock(); - return stateMachine.write(request); + long getStateMachineLockTime = System.nanoTime(); + // statistic the time of acquiring stateMachine lock + pipeConsensusServerMetrics.recordGetStateMachineLockTime( + getStateMachineLockTime - consensusWriteStartTime); + + long writeToStateMachineStartTime = System.nanoTime(); + TSStatus result = stateMachine.write(request); + long writeToStateMachineEndTime = System.nanoTime(); + + PERFORMANCE_OVERVIEW_METRICS.recordEngineCost( + writeToStateMachineEndTime - writeToStateMachineStartTime); + // statistic the time of writing request into stateMachine + pipeConsensusServerMetrics.recordReplicaWriteStateMachineTime( + writeToStateMachineEndTime - writeToStateMachineStartTime); + return result; } finally { stateMachineLock.unlock(); } @@ -540,4 +583,12 @@ public boolean containsPeer(Peer peer) { public List getPeers() { return peerManager.getPeers(); } + + public String getConsensusGroupId() { + return consensusGroupId; + } + + public long getReplicateMode() { + return (replicateMode == ReplicateMode.BATCH) ? 2 : 1; + } } diff --git a/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/pipe/consensuspipe/ConsensusPipeConnector.java b/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/pipe/consensuspipe/ConsensusPipeConnector.java new file mode 100644 index 0000000000000..6f1396db97229 --- /dev/null +++ b/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/pipe/consensuspipe/ConsensusPipeConnector.java @@ -0,0 +1,25 @@ +/* + * 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.iotdb.consensus.pipe.consensuspipe; + +public interface ConsensusPipeConnector { + long getConsensusPipeCommitProgress(); + + long getConsensusPipeReplicateProgress(); +} diff --git a/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/pipe/consensuspipe/ConsensusPipeManager.java b/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/pipe/consensuspipe/ConsensusPipeManager.java index bb1bf2a176942..eab94de768f04 100644 --- a/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/pipe/consensuspipe/ConsensusPipeManager.java +++ b/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/pipe/consensuspipe/ConsensusPipeManager.java @@ -29,10 +29,12 @@ import java.util.Map; import static org.apache.iotdb.commons.pipe.config.constant.PipeConnectorConstant.CONNECTOR_CONSENSUS_GROUP_ID_KEY; +import static org.apache.iotdb.commons.pipe.config.constant.PipeConnectorConstant.CONNECTOR_CONSENSUS_PIPE_NAME; import static org.apache.iotdb.commons.pipe.config.constant.PipeConnectorConstant.CONNECTOR_IOTDB_IP_KEY; import static org.apache.iotdb.commons.pipe.config.constant.PipeConnectorConstant.CONNECTOR_IOTDB_PARALLEL_TASKS_KEY; import static org.apache.iotdb.commons.pipe.config.constant.PipeConnectorConstant.CONNECTOR_IOTDB_PORT_KEY; import static org.apache.iotdb.commons.pipe.config.constant.PipeConnectorConstant.CONNECTOR_KEY; +import static org.apache.iotdb.commons.pipe.config.constant.PipeConnectorConstant.CONNECTOR_REALTIME_FIRST_KEY; import static org.apache.iotdb.commons.pipe.config.constant.PipeExtractorConstant.EXTRACTOR_CONSENSUS_GROUP_ID_KEY; import static org.apache.iotdb.commons.pipe.config.constant.PipeExtractorConstant.EXTRACTOR_CONSENSUS_RECEIVER_DATANODE_ID_KEY; import static org.apache.iotdb.commons.pipe.config.constant.PipeExtractorConstant.EXTRACTOR_CONSENSUS_SENDER_DATANODE_ID_KEY; @@ -78,9 +80,11 @@ public void createConsensusPipe(Peer senderPeer, Peer receiverPeer) throws Excep .put( CONNECTOR_CONSENSUS_GROUP_ID_KEY, String.valueOf(consensusPipeName.getConsensusGroupId().getId())) + .put(CONNECTOR_CONSENSUS_PIPE_NAME, consensusPipeName.toString()) .put(CONNECTOR_IOTDB_IP_KEY, receiverPeer.getEndpoint().ip) .put(CONNECTOR_IOTDB_PORT_KEY, String.valueOf(receiverPeer.getEndpoint().port)) .put(CONNECTOR_IOTDB_PARALLEL_TASKS_KEY, String.valueOf(1)) + .put(CONNECTOR_REALTIME_FIRST_KEY, String.valueOf(false)) .build()); } diff --git a/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/pipe/metric/PipeConsensusServerMetrics.java b/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/pipe/metric/PipeConsensusServerMetrics.java new file mode 100644 index 0000000000000..39bcb1e526ff8 --- /dev/null +++ b/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/pipe/metric/PipeConsensusServerMetrics.java @@ -0,0 +1,190 @@ +/* + * 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.iotdb.consensus.pipe.metric; + +import org.apache.iotdb.commons.service.metric.enums.Metric; +import org.apache.iotdb.commons.service.metric.enums.Tag; +import org.apache.iotdb.consensus.pipe.PipeConsensusServerImpl; +import org.apache.iotdb.metrics.AbstractMetricService; +import org.apache.iotdb.metrics.impl.DoNothingMetricManager; +import org.apache.iotdb.metrics.metricsets.IMetricSet; +import org.apache.iotdb.metrics.type.Timer; +import org.apache.iotdb.metrics.utils.MetricLevel; +import org.apache.iotdb.metrics.utils.MetricType; + +public class PipeConsensusServerMetrics implements IMetricSet { + private final PipeConsensusServerImpl impl; + private final PipeConsensusSyncLagManager syncLagManager; + + private Timer getStateMachineLockTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + private Timer userWriteStateMachineTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + private Timer replicaWriteStateMachineTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + + public PipeConsensusServerMetrics(PipeConsensusServerImpl impl) { + this.impl = impl; + this.syncLagManager = PipeConsensusSyncLagManager.getInstance(impl.getConsensusGroupId()); + } + + private static final String IMPL = "PipeConsensusServerImpl"; + + public void recordGetStateMachineLockTime(long costTimeInNanos) { + getStateMachineLockTimer.updateNanos(costTimeInNanos); + } + + public void recordUserWriteStateMachineTime(long costTimeInNanos) { + userWriteStateMachineTimer.updateNanos(costTimeInNanos); + } + + public void recordReplicaWriteStateMachineTime(long costTimeInNanos) { + replicaWriteStateMachineTimer.updateNanos(costTimeInNanos); + } + + @Override + public void bindTo(AbstractMetricService metricService) { + bindAutoGauge(metricService); + bindGauge(metricService); + bindStageTimer(metricService); + } + + @Override + public void unbindFrom(AbstractMetricService metricService) { + unbindAutoGauge(metricService); + unbindGauge(metricService); + unbindStageTimer(metricService); + + // release corresponding resource + PipeConsensusSyncLagManager.release(impl.getConsensusGroupId()); + } + + public void bindGauge(AbstractMetricService metricService) { + metricService + .getOrCreateGauge( + Metric.PIPE_CONSENSUS_MODE.toString(), + MetricLevel.IMPORTANT, + Tag.NAME.toString(), + IMPL, + Tag.TYPE.toString(), + "replicateMode") + .set(impl.getReplicateMode()); + } + + public void unbindGauge(AbstractMetricService metricService) { + metricService.remove( + MetricType.GAUGE, + Metric.PIPE_CONSENSUS_MODE.toString(), + Tag.NAME.toString(), + IMPL, + Tag.TYPE.toString(), + "replicateMode"); + } + + public void bindAutoGauge(AbstractMetricService metricService) { + metricService.createAutoGauge( + Metric.PIPE_CONSENSUS.toString(), + MetricLevel.IMPORTANT, + syncLagManager, + PipeConsensusSyncLagManager::calculateSyncLag, + Tag.NAME.toString(), + IMPL, + Tag.REGION.toString(), + impl.getConsensusGroupId(), + Tag.TYPE.toString(), + "syncLag"); + } + + public void unbindAutoGauge(AbstractMetricService metricService) { + metricService.remove( + MetricType.AUTO_GAUGE, + Metric.PIPE_CONSENSUS.toString(), + Tag.NAME.toString(), + IMPL, + Tag.REGION.toString(), + impl.getConsensusGroupId(), + Tag.TYPE.toString(), + "syncLag"); + } + + public void bindStageTimer(AbstractMetricService metricService) { + getStateMachineLockTimer = + metricService.getOrCreateTimer( + Metric.STAGE.toString(), + MetricLevel.IMPORTANT, + Tag.NAME.toString(), + Metric.PIPE_CONSENSUS.toString(), + Tag.TYPE.toString(), + "getStateMachineLock", + Tag.REGION.toString(), + impl.getConsensusGroupId()); + userWriteStateMachineTimer = + metricService.getOrCreateTimer( + Metric.STAGE.toString(), + MetricLevel.IMPORTANT, + Tag.NAME.toString(), + Metric.PIPE_CONSENSUS.toString(), + Tag.TYPE.toString(), + "userWriteStateMachine", + Tag.REGION.toString(), + impl.getConsensusGroupId()); + replicaWriteStateMachineTimer = + metricService.getOrCreateTimer( + Metric.PIPE_RECEIVE_EVENT.toString(), + MetricLevel.IMPORTANT, + Tag.NAME.toString(), + Metric.PIPE_CONSENSUS.toString(), + Tag.TYPE.toString(), + "replicaWriteStateMachine", + Tag.REGION.toString(), + impl.getConsensusGroupId()); + } + + public void unbindStageTimer(AbstractMetricService metricService) { + getStateMachineLockTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + userWriteStateMachineTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + replicaWriteStateMachineTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + + metricService.remove( + MetricType.TIMER, + Metric.STAGE.toString(), + Tag.NAME.toString(), + Metric.PIPE_CONSENSUS.toString(), + Tag.TYPE.toString(), + "getStateMachineLock", + Tag.REGION.toString(), + impl.getConsensusGroupId()); + metricService.remove( + MetricType.TIMER, + Metric.STAGE.toString(), + Tag.NAME.toString(), + Metric.PIPE_CONSENSUS.toString(), + Tag.TYPE.toString(), + "writeStateMachine", + Tag.REGION.toString(), + impl.getConsensusGroupId()); + metricService.remove( + MetricType.TIMER, + Metric.PIPE_RECEIVE_EVENT.toString(), + Tag.NAME.toString(), + Metric.PIPE_CONSENSUS.toString(), + Tag.TYPE.toString(), + "replicaWriteStateMachine", + Tag.REGION.toString(), + impl.getConsensusGroupId()); + } +} diff --git a/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/pipe/metric/PipeConsensusSyncLagManager.java b/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/pipe/metric/PipeConsensusSyncLagManager.java new file mode 100644 index 0000000000000..6ff754e02ef7a --- /dev/null +++ b/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/pipe/metric/PipeConsensusSyncLagManager.java @@ -0,0 +1,131 @@ +/* + * 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.iotdb.consensus.pipe.metric; + +import org.apache.iotdb.consensus.pipe.consensuspipe.ConsensusPipeConnector; + +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * This class is used to aggregate the write progress of all Connectors to calculate the minimum + * synchronization progress of all follower copies, thereby calculating syncLag. + * + *

Note: every consensusGroup/dataRegion has and only has 1 instance of this class. + */ +public class PipeConsensusSyncLagManager { + long userWriteProgress = 0; + long minReplicateProgress = Long.MAX_VALUE; + List consensusPipeConnectorList = new CopyOnWriteArrayList<>(); + + private void updateReplicateProgress() { + minReplicateProgress = Long.MAX_VALUE; + // if there isn't a consensus pipe task, replicate progress is Long.MAX_VALUE. + if (consensusPipeConnectorList.isEmpty()) { + return; + } + // else we find the minimum progress in all consensus pipe task. + consensusPipeConnectorList.forEach( + consensusPipeConnector -> + minReplicateProgress = + Math.min( + minReplicateProgress, + consensusPipeConnector.getConsensusPipeReplicateProgress())); + } + + private void updateUserWriteProgress() { + // if there isn't a consensus pipe task, user write progress is 0. + if (consensusPipeConnectorList.isEmpty()) { + userWriteProgress = 0; + return; + } + // since the user write progress of different consensus pipes on the same DataRegion is the + // same, we only need to take out one Connector to calculate + try { + ConsensusPipeConnector connector = consensusPipeConnectorList.get(0); + userWriteProgress = connector.getConsensusPipeCommitProgress(); + } catch (Exception e) { + // if removing the last connector happens after empty check, we may encounter + // OutOfBoundsException, in this case, we set userWriteProgress to 0. + userWriteProgress = 0; + } + } + + public void addConsensusPipeConnector(ConsensusPipeConnector consensusPipeConnector) { + consensusPipeConnectorList.add(consensusPipeConnector); + } + + public void removeConsensusPipeConnector(ConsensusPipeConnector connector) { + consensusPipeConnectorList.remove(connector); + } + + /** + * SyncLag represents the difference between the current replica users' write progress and the + * minimum synchronization progress of all other replicas. The semantics is how much data the + * leader has left to synchronize. + */ + public long calculateSyncLag() { + updateUserWriteProgress(); + updateReplicateProgress(); + // if there isn't a consensus pipe task, the syncLag is userWriteProgress - 0 + if (minReplicateProgress == Long.MAX_VALUE) { + return userWriteProgress; + } else { + // since we first update userWriteProgress then update replicateProgress, there may have some + // cases that userWriteProgress is less than replicateProgress. In these cases, we return 0. + return Math.max(userWriteProgress - minReplicateProgress, 0); + } + } + + private PipeConsensusSyncLagManager() { + // do nothing + } + + private static class PipeConsensusSyncLagManagerHolder { + private static Map CONSENSU_GROUP_ID_2_INSTANCE_MAP; + + private PipeConsensusSyncLagManagerHolder() { + // empty constructor + } + + private static void build() { + if (CONSENSU_GROUP_ID_2_INSTANCE_MAP == null) { + CONSENSU_GROUP_ID_2_INSTANCE_MAP = new ConcurrentHashMap<>(); + } + } + } + + public static PipeConsensusSyncLagManager getInstance(String groupId) { + return PipeConsensusSyncLagManagerHolder.CONSENSU_GROUP_ID_2_INSTANCE_MAP.computeIfAbsent( + groupId, key -> new PipeConsensusSyncLagManager()); + } + + public static void release(String groupId) { + PipeConsensusSyncLagManagerHolder.CONSENSU_GROUP_ID_2_INSTANCE_MAP.remove(groupId); + } + + // Only when consensus protocol is PipeConsensus, this method will be called once when construct + // consensus class. + public static void build() { + PipeConsensusSyncLagManagerHolder.build(); + } +} diff --git a/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/ratis/RatisConsensus.java b/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/ratis/RatisConsensus.java index 90816ba6291c2..c8fbeea4ced26 100644 --- a/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/ratis/RatisConsensus.java +++ b/iotdb-core/consensus/src/main/java/org/apache/iotdb/consensus/ratis/RatisConsensus.java @@ -771,14 +771,22 @@ public void triggerSnapshot(ConsensusGroupId groupId, boolean force) throws Cons 300000, force ? 1 : 0); - final RaftClientReply reply; - try { - reply = server.get().snapshotManagement(request); - if (!reply.isSuccess()) { - throw new RatisRequestFailedException(reply.getException()); + synchronized (raftGroupId) { + final RaftClientReply reply; + try { + reply = server.get().snapshotManagement(request); + if (!reply.isSuccess()) { + throw new RatisRequestFailedException(reply.getException()); + } + logger.info( + "{} group {}: successfully taken snapshot at index {} with force = {}", + this, + raftGroupId, + reply.getLogIndex(), + force); + } catch (IOException ioException) { + throw new RatisRequestFailedException(ioException); } - } catch (IOException ioException) { - throw new RatisRequestFailedException(ioException); } } diff --git a/iotdb-core/datanode/src/assembly/resources/sbin/stop-datanode.sh b/iotdb-core/datanode/src/assembly/resources/sbin/stop-datanode.sh index 71bdcef0a82b5..94441cd6252a0 100644 --- a/iotdb-core/datanode/src/assembly/resources/sbin/stop-datanode.sh +++ b/iotdb-core/datanode/src/assembly/resources/sbin/stop-datanode.sh @@ -18,6 +18,7 @@ # under the License. # +source "$(dirname "$0")/iotdb-common.sh" DATANODE_CONF="`dirname "$0"`/../conf" if [ -f "${DATANODE_CONF}/iotdb-system.properties" ]; then @@ -26,6 +27,8 @@ else dn_rpc_port=`sed '/^dn_rpc_port=/!d;s/.*=//' ${DATANODE_CONF}/iotdb-datanode.properties` fi +check_config_unique "dn_rpc_port" "$dn_rpc_port" + force="" while true; do diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/auth/AuthorityChecker.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/auth/AuthorityChecker.java index 4dc29bd42f770..395f1f42d8a01 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/auth/AuthorityChecker.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/auth/AuthorityChecker.java @@ -40,6 +40,7 @@ import org.apache.iotdb.rpc.TSStatusCode; import com.google.common.util.concurrent.SettableFuture; +import org.apache.ratis.util.MemoizedSupplier; import org.apache.tsfile.common.conf.TSFileConfig; import org.apache.tsfile.enums.TSDataType; import org.apache.tsfile.read.common.block.TsBlockBuilder; @@ -66,8 +67,8 @@ public class AuthorityChecker { private static final String NO_PERMISSION_PROMOTION = "No permissions for this operation, please add privilege "; - private static final IAuthorityFetcher authorityFetcher = - new ClusterAuthorityFetcher(new BasicAuthorityCache()); + private static final MemoizedSupplier authorityFetcher = + MemoizedSupplier.valueOf(() -> new ClusterAuthorityFetcher(new BasicAuthorityCache())); private static final PerformanceOverviewMetrics PERFORMANCE_OVERVIEW_METRICS = PerformanceOverviewMetrics.getInstance(); @@ -77,24 +78,24 @@ private AuthorityChecker() { } public static IAuthorityFetcher getAuthorityFetcher() { - return authorityFetcher; + return authorityFetcher.get(); } public static boolean invalidateCache(String username, String rolename) { - return authorityFetcher.getAuthorCache().invalidateCache(username, rolename); + return authorityFetcher.get().getAuthorCache().invalidateCache(username, rolename); } public static TSStatus checkUser(String userName, String password) { - return authorityFetcher.checkUser(userName, password); + return authorityFetcher.get().checkUser(userName, password); } public static SettableFuture queryPermission(AuthorStatement authorStatement) { - return authorityFetcher.queryPermission(authorStatement); + return authorityFetcher.get().queryPermission(authorStatement); } public static SettableFuture operatePermission( AuthorStatement authorStatement) { - return authorityFetcher.operatePermission(authorStatement); + return authorityFetcher.get().operatePermission(authorStatement); } /** Check whether specific Session has the authorization to given plan. */ @@ -166,35 +167,38 @@ public static TSStatus getTSStatus( public static boolean checkFullPathPermission( String userName, PartialPath fullPath, int permission) { return authorityFetcher + .get() .checkUserPathPrivileges(userName, Collections.singletonList(fullPath), permission) .isEmpty(); } public static List checkFullPathListPermission( String userName, List fullPaths, int permission) { - return authorityFetcher.checkUserPathPrivileges(userName, fullPaths, permission); + return authorityFetcher.get().checkUserPathPrivileges(userName, fullPaths, permission); } public static List checkPatternPermission( String userName, List pathPatterns, int permission) { - return authorityFetcher.checkUserPathPrivileges(userName, pathPatterns, permission); + return authorityFetcher.get().checkUserPathPrivileges(userName, pathPatterns, permission); } public static PathPatternTree getAuthorizedPathTree(String userName, int permission) throws AuthException { - return authorityFetcher.getAuthorizedPatternTree(userName, permission); + return authorityFetcher.get().getAuthorizedPatternTree(userName, permission); } public static boolean checkSystemPermission(String userName, int permission) { - return authorityFetcher.checkUserSysPrivileges(userName, permission).getCode() + return authorityFetcher.get().checkUserSysPrivileges(userName, permission).getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode(); } public static boolean checkGrantOption( String userName, String[] privilegeList, List nodeNameList) { for (String s : privilegeList) { - if (!authorityFetcher.checkUserPrivilegeGrantOpt( - userName, nodeNameList, PrivilegeType.valueOf(s.toUpperCase()).ordinal())) { + if (!authorityFetcher + .get() + .checkUserPrivilegeGrantOpt( + userName, nodeNameList, PrivilegeType.valueOf(s.toUpperCase()).ordinal())) { return false; } } @@ -202,7 +206,7 @@ public static boolean checkGrantOption( } public static boolean checkRole(String username, String rolename) { - return authorityFetcher.checkRole(username, rolename); + return authorityFetcher.get().checkRole(username, rolename); } public static void buildTSBlock( diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/DataNodeSystemPropertiesHandler.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/DataNodeSystemPropertiesHandler.java new file mode 100644 index 0000000000000..2c9d6e5e5358f --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/DataNodeSystemPropertiesHandler.java @@ -0,0 +1,52 @@ +/* + * 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.iotdb.db.conf; + +import org.apache.iotdb.commons.file.SystemPropertiesHandler; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; + +import static org.apache.iotdb.db.conf.IoTDBStartCheck.PROPERTIES_FILE_NAME; + +public class DataNodeSystemPropertiesHandler extends SystemPropertiesHandler { + private static final Logger LOGGER = + LoggerFactory.getLogger(DataNodeSystemPropertiesHandler.class); + + private static DataNodeSystemPropertiesHandler INSTANCE; + + private DataNodeSystemPropertiesHandler(String filePath) { + super(filePath); + } + + public static synchronized SystemPropertiesHandler getInstance() { + if (INSTANCE == null) { + INSTANCE = + new DataNodeSystemPropertiesHandler( + IoTDBDescriptor.getInstance().getConfig().getSystemDir() + + File.separator + + PROPERTIES_FILE_NAME); + INSTANCE.recover(); + } + return INSTANCE; + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java index df32ee99efaf9..a89d4f0a7d5a9 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBConfig.java @@ -19,6 +19,7 @@ package org.apache.iotdb.db.conf; +import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; import org.apache.iotdb.common.rpc.thrift.TEndPoint; import org.apache.iotdb.commons.client.property.ClientPoolProperty.DefaultProperty; import org.apache.iotdb.commons.conf.CommonDescriptor; @@ -48,6 +49,7 @@ import org.apache.tsfile.common.conf.TSFileDescriptor; import org.apache.tsfile.common.constant.TsFileConstant; import org.apache.tsfile.enums.TSDataType; +import org.apache.tsfile.file.metadata.enums.CompressionType; import org.apache.tsfile.file.metadata.enums.TSEncoding; import org.apache.tsfile.fileSystem.FSType; import org.apache.tsfile.utils.FSUtils; @@ -73,7 +75,7 @@ public class IoTDBConfig { /* Names of Watermark methods */ public static final String WATERMARK_GROUPED_LSB = "GroupBasedLSBMethod"; - public static final String CONFIG_NAME = "iotdb-datanode.properties"; + public static final String CONFIG_NAME = "iotdb-system.properties"; private static final Logger logger = LoggerFactory.getLogger(IoTDBConfig.class); private static final String MULTI_DIR_STRATEGY_PREFIX = "org.apache.iotdb.db.storageengine.rescon.disk.strategy."; @@ -310,8 +312,9 @@ public class IoTDBConfig { {IoTDBConstant.DN_DEFAULT_DATA_DIR + File.separator + IoTDBConstant.DATA_FOLDER_NAME} }; - private String loadTsFileDir = - tierDataDirs[0][0] + File.separator + IoTDBConstant.LOAD_TSFILE_FOLDER_NAME; + private String[] loadTsFileDirs = { + tierDataDirs[0][0] + File.separator + IoTDBConstant.LOAD_TSFILE_FOLDER_NAME + }; /** Strategy of multiple directories. */ private String multiDirStrategyClassName = null; @@ -1135,6 +1138,8 @@ public class IoTDBConfig { */ private String RateLimiterType = "FixedIntervalRateLimiter"; + private CompressionType WALCompressionAlgorithm = CompressionType.UNCOMPRESSED; + IoTDBConfig() {} public int getMaxLogEntriesNumPerBatch() { @@ -1276,7 +1281,6 @@ public void updatePath() { private void formulateFolders() { systemDir = addDataHomeDir(systemDir); schemaDir = addDataHomeDir(schemaDir); - loadTsFileDir = addDataHomeDir(loadTsFileDir); consensusDir = addDataHomeDir(consensusDir); dataRegionConsensusDir = addDataHomeDir(dataRegionConsensusDir); ratisDataRegionSnapshotDir = addDataHomeDir(ratisDataRegionSnapshotDir); @@ -1324,6 +1328,7 @@ private void formulateDataDirs(String[][] tierDataDirs) { } } } + formulateLoadTsFileDirs(tierDataDirs); } void reloadDataDirs(String[][] tierDataDirs) throws LoadConfigurationException { @@ -1427,7 +1432,6 @@ public void setTierDataDirs(String[][] tierDataDirs) { // TODO(szywilliam): rewrite the logic here when ratis supports complete snapshot semantic setRatisDataRegionSnapshotDir( tierDataDirs[0][0] + File.separator + IoTDBConstant.SNAPSHOT_FOLDER_NAME); - setLoadTsFileDir(tierDataDirs[0][0] + File.separator + IoTDBConstant.LOAD_TSFILE_FOLDER_NAME); } public String getRpcAddress() { @@ -1462,12 +1466,21 @@ public void setSystemDir(String systemDir) { this.systemDir = systemDir; } - public String getLoadTsFileDir() { - return loadTsFileDir; + public String[] getLoadTsFileDirs() { + return this.loadTsFileDirs; } - public void setLoadTsFileDir(String loadTsFileDir) { - this.loadTsFileDir = loadTsFileDir; + public void formulateLoadTsFileDirs(String[][] tierDataDirs) { + final String[] newLoadTsFileDirs = new String[tierDataDirs.length]; + for (int i = 0; i < tierDataDirs.length; i++) { + newLoadTsFileDirs[i] = + tierDataDirs[i][0] + File.separator + IoTDBConstant.LOAD_TSFILE_FOLDER_NAME; + } + + // Update loadTsFileDirs after all newLoadTsFileDirs are generated, + // or the newLoadTsFileDirs will be used in the middle of the process + // and cause the undefined behavior. + this.loadTsFileDirs = newLoadTsFileDirs; } public String getSchemaDir() { @@ -1871,7 +1884,7 @@ public long getWalFileSizeThresholdInByte() { return walFileSizeThresholdInByte; } - void setWalFileSizeThresholdInByte(long walFileSizeThresholdInByte) { + public void setWalFileSizeThresholdInByte(long walFileSizeThresholdInByte) { this.walFileSizeThresholdInByte = walFileSizeThresholdInByte; } @@ -2175,14 +2188,6 @@ public void setAvgSeriesPointNumberThreshold(int avgSeriesPointNumberThreshold) this.avgSeriesPointNumberThreshold = avgSeriesPointNumberThreshold; } - public long getCrossCompactionFileSelectionTimeBudget() { - return crossCompactionFileSelectionTimeBudget; - } - - void setCrossCompactionFileSelectionTimeBudget(long crossCompactionFileSelectionTimeBudget) { - this.crossCompactionFileSelectionTimeBudget = crossCompactionFileSelectionTimeBudget; - } - public boolean isRpcThriftCompressionEnable() { return rpcThriftCompressionEnable; } @@ -3968,4 +3973,26 @@ public void setInnerCompactionTaskSelectionDiskRedundancy( double innerCompactionTaskSelectionDiskRedundancy) { this.innerCompactionTaskSelectionDiskRedundancy = innerCompactionTaskSelectionDiskRedundancy; } + + public TDataNodeLocation generateLocalDataNodeLocation() { + TDataNodeLocation result = new TDataNodeLocation(); + result.setDataNodeId(getDataNodeId()); + result.setClientRpcEndPoint(new TEndPoint(getInternalAddress(), getRpcPort())); + result.setInternalEndPoint(new TEndPoint(getInternalAddress(), getInternalPort())); + result.setMPPDataExchangeEndPoint( + new TEndPoint(getInternalAddress(), getMppDataExchangePort())); + result.setDataRegionConsensusEndPoint( + new TEndPoint(getInternalAddress(), getDataRegionConsensusPort())); + result.setSchemaRegionConsensusEndPoint( + new TEndPoint(getInternalAddress(), getSchemaRegionConsensusPort())); + return result; + } + + public CompressionType getWALCompressionAlgorithm() { + return WALCompressionAlgorithm; + } + + public void setWALCompressionAlgorithm(CompressionType WALCompressionAlgorithm) { + this.WALCompressionAlgorithm = WALCompressionAlgorithm; + } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java index c54b7d5ef4f95..dcf8792a145ea 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java @@ -62,6 +62,7 @@ import org.apache.tsfile.common.conf.TSFileDescriptor; import org.apache.tsfile.enums.TSDataType; +import org.apache.tsfile.file.metadata.enums.CompressionType; import org.apache.tsfile.file.metadata.enums.TSEncoding; import org.apache.tsfile.fileSystem.FSType; import org.apache.tsfile.utils.FilePathUtils; @@ -416,6 +417,10 @@ public void loadProperties(Properties properties) throws BadNodeUrlException, IO properties.getProperty( "io_task_queue_size_for_flushing", Integer.toString(conf.getIoTaskQueueSizeForFlushing())))); + boolean enableWALCompression = + Boolean.parseBoolean(properties.getProperty("enable_wal_compression", "false")); + conf.setWALCompressionAlgorithm( + enableWALCompression ? CompressionType.LZ4 : CompressionType.UNCOMPRESSED); conf.setCompactionScheduleIntervalInMs( Long.parseLong( @@ -591,11 +596,6 @@ public void loadProperties(Properties properties) throws BadNodeUrlException, IO conf.setChunkBufferPoolEnable( Boolean.parseBoolean(properties.getProperty("chunk_buffer_pool_enable"))); } - conf.setCrossCompactionFileSelectionTimeBudget( - Long.parseLong( - properties.getProperty( - "cross_compaction_file_selection_time_budget", - Long.toString(conf.getCrossCompactionFileSelectionTimeBudget())))); conf.setMergeIntervalSec( Long.parseLong( properties.getProperty( @@ -895,32 +895,6 @@ public void loadProperties(Properties properties) throws BadNodeUrlException, IO conf.setIntoOperationExecutionThreadCount(2); } - conf.setMaxAllocateMemoryRatioForLoad( - Double.parseDouble( - properties.getProperty( - "max_allocate_memory_ratio_for_load", - String.valueOf(conf.getMaxAllocateMemoryRatioForLoad())))); - conf.setLoadTsFileAnalyzeSchemaBatchFlushTimeSeriesNumber( - Integer.parseInt( - properties.getProperty( - "load_tsfile_analyze_schema_batch_flush_time_series_number", - String.valueOf(conf.getLoadTsFileAnalyzeSchemaBatchFlushTimeSeriesNumber())))); - conf.setLoadTsFileAnalyzeSchemaMemorySizeInBytes( - Long.parseLong( - properties.getProperty( - "load_tsfile_analyze_schema_memory_size_in_bytes", - String.valueOf(conf.getLoadTsFileAnalyzeSchemaMemorySizeInBytes())))); - conf.setLoadCleanupTaskExecutionDelayTimeSeconds( - Long.parseLong( - properties.getProperty( - "load_clean_up_task_execution_delay_time_seconds", - String.valueOf(conf.getLoadCleanupTaskExecutionDelayTimeSeconds())))); - conf.setLoadWriteThroughputBytesPerSecond( - Double.parseDouble( - properties.getProperty( - "load_write_throughput_bytes_per_second", - String.valueOf(conf.getLoadWriteThroughputBytesPerSecond())))); - conf.setExtPipeDir(properties.getProperty("ext_pipe_dir", conf.getExtPipeDir()).trim()); // At the same time, set TSFileConfig @@ -1023,6 +997,9 @@ public void loadProperties(Properties properties) throws BadNodeUrlException, IO // CQ loadCQProps(properties); + // Load TsFile + loadLoadTsFileProps(properties); + // Pipe loadPipeProps(properties); @@ -1821,6 +1798,10 @@ public void loadHotModifiedProps(Properties properties) throws QueryProcessExcep properties.getProperty( "merge_threshold_of_explain_analyze", String.valueOf(conf.getMergeThresholdOfExplainAnalyze())))); + boolean enableWALCompression = + Boolean.parseBoolean(properties.getProperty("enable_wal_compression", "false")); + conf.setWALCompressionAlgorithm( + enableWALCompression ? CompressionType.LZ4 : CompressionType.UNCOMPRESSED); // update Consensus config reloadConsensusProps(properties); @@ -2092,6 +2073,34 @@ private void initSchemaMemoryAllocate(Properties properties) { LOGGER.info("allocateMemoryForPartitionCache = {}", conf.getAllocateMemoryForPartitionCache()); } + private void loadLoadTsFileProps(Properties properties) { + conf.setMaxAllocateMemoryRatioForLoad( + Double.parseDouble( + properties.getProperty( + "max_allocate_memory_ratio_for_load", + String.valueOf(conf.getMaxAllocateMemoryRatioForLoad())))); + conf.setLoadTsFileAnalyzeSchemaBatchFlushTimeSeriesNumber( + Integer.parseInt( + properties.getProperty( + "load_tsfile_analyze_schema_batch_flush_time_series_number", + String.valueOf(conf.getLoadTsFileAnalyzeSchemaBatchFlushTimeSeriesNumber())))); + conf.setLoadTsFileAnalyzeSchemaMemorySizeInBytes( + Long.parseLong( + properties.getProperty( + "load_tsfile_analyze_schema_memory_size_in_bytes", + String.valueOf(conf.getLoadTsFileAnalyzeSchemaMemorySizeInBytes())))); + conf.setLoadCleanupTaskExecutionDelayTimeSeconds( + Long.parseLong( + properties.getProperty( + "load_clean_up_task_execution_delay_time_seconds", + String.valueOf(conf.getLoadCleanupTaskExecutionDelayTimeSeconds())))); + conf.setLoadWriteThroughputBytesPerSecond( + Double.parseDouble( + properties.getProperty( + "load_write_throughput_bytes_per_second", + String.valueOf(conf.getLoadWriteThroughputBytesPerSecond())))); + } + @SuppressWarnings("squid:S3518") // "proportionSum" can't be zero private void loadUDFProps(Properties properties) { String initialByteArrayLengthForMemoryControl = diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBStartCheck.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBStartCheck.java index c5d22f36e3f98..a91a8d7f7fc06 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBStartCheck.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBStartCheck.java @@ -24,23 +24,17 @@ import org.apache.iotdb.commons.conf.IoTDBConstant; import org.apache.iotdb.commons.exception.ConfigurationException; import org.apache.iotdb.commons.file.SystemFileFactory; +import org.apache.iotdb.commons.file.SystemPropertiesHandler; import org.apache.iotdb.consensus.ConsensusFactory; import org.apache.iotdb.db.storageengine.dataregion.wal.utils.WALMode; import org.apache.iotdb.db.storageengine.rescon.disk.DirectoryChecker; import org.apache.commons.io.FileUtils; -import org.apache.tsfile.common.conf.TSFileConfig; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.nio.charset.StandardCharsets; -import java.nio.file.Files; import java.util.HashMap; import java.util.Map; import java.util.Map.Entry; @@ -61,13 +55,10 @@ public class IoTDBStartCheck { private boolean isFirstStart = false; - private final File propertiesFile; - private final File oldPropertiesFile; - private final File tmpPropertiesFile; - - private final Properties properties = new Properties(); + private Properties properties = new Properties(); private final Map> systemProperties = new HashMap<>(); + private final SystemPropertiesHandler systemPropertiesHandler; // region params need checking, determined when first start private static final String SYSTEM_PROPERTIES_STRING = "System properties:"; @@ -148,15 +139,7 @@ private IoTDBStartCheck() { } } - oldPropertiesFile = - SystemFileFactory.INSTANCE.getFile( - IoTDBStartCheck.SCHEMA_DIR + File.separator + PROPERTIES_FILE_NAME); - propertiesFile = - SystemFileFactory.INSTANCE.getFile( - config.getSystemDir() + File.separator + PROPERTIES_FILE_NAME); - tmpPropertiesFile = - SystemFileFactory.INSTANCE.getFile( - IoTDBStartCheck.SCHEMA_DIR + File.separator + PROPERTIES_FILE_NAME + ".tmp"); + systemPropertiesHandler = DataNodeSystemPropertiesHandler.getInstance(); systemProperties.put(IOTDB_VERSION_STRING, () -> IoTDBConstant.VERSION); systemProperties.put(COMMIT_ID_STRING, () -> IoTDBConstant.BUILD_INFO); @@ -165,43 +148,6 @@ private IoTDBStartCheck() { } } - /** check configuration in system.properties when starting IoTDB */ - public boolean checkIsFirstStart() throws IOException { - // system init first time, no need to check, write system.properties and return - if (!propertiesFile.exists() && !tmpPropertiesFile.exists()) { - // create system.properties - if (propertiesFile.createNewFile()) { - logger.info(" {} has been created.", propertiesFile.getAbsolutePath()); - } else { - logger.error("can not create {}", propertiesFile.getAbsolutePath()); - System.exit(-1); - } - - // write properties to system.properties - try (FileOutputStream outputStream = new FileOutputStream(propertiesFile)) { - systemProperties.forEach((k, v) -> properties.setProperty(k, v.get())); - properties.store( - new OutputStreamWriter(outputStream, StandardCharsets.UTF_8), SYSTEM_PROPERTIES_STRING); - } - isFirstStart = true; - return true; - } - - if (!propertiesFile.exists() && tmpPropertiesFile.exists()) { - // rename tmp file to system.properties, no need to check - FileUtils.moveFile(tmpPropertiesFile, propertiesFile); - logger.info("rename {} to {}", tmpPropertiesFile, propertiesFile); - isFirstStart = false; - return false; - } else if (propertiesFile.exists() && tmpPropertiesFile.exists()) { - // both files exist, remove tmp file - FileUtils.forceDelete(tmpPropertiesFile); - logger.info("remove {}", tmpPropertiesFile); - } - isFirstStart = false; - return false; - } - /** * check and create directory before start IoTDB. * @@ -240,14 +186,20 @@ public void checkDirectory() throws ConfigurationException, IOException { * * @throws IOException If copy fail or delete fail */ - public void checkOldSystemConfig() throws IOException { + public static void checkOldSystemConfig() throws IOException { + File oldPropertiesFile = + SystemFileFactory.INSTANCE.getFile( + IoTDBStartCheck.SCHEMA_DIR + File.separator + PROPERTIES_FILE_NAME); if (oldPropertiesFile.exists()) { - FileUtils.copyFile(oldPropertiesFile, propertiesFile); + File correctPropertiesFile = + SystemFileFactory.INSTANCE.getFile( + config.getSystemDir() + File.separator + PROPERTIES_FILE_NAME); + FileUtils.copyFile(oldPropertiesFile, correctPropertiesFile); FileUtils.delete(oldPropertiesFile); logger.info( "system.properties file has been moved successfully: {} -> {}", oldPropertiesFile.getAbsolutePath(), - propertiesFile.getAbsolutePath()); + correctPropertiesFile.getAbsolutePath()); } } @@ -261,19 +213,9 @@ public void checkOldSystemConfig() throws IOException { */ public void checkSystemConfig() throws ConfigurationException, IOException { // read properties from system.properties - try (FileInputStream inputStream = new FileInputStream(propertiesFile); - InputStreamReader inputStreamReader = - new InputStreamReader(inputStream, TSFileConfig.STRING_CHARSET)) { - properties.load(inputStreamReader); - } + properties = systemPropertiesHandler.read(); - if (isFirstStart) { - // overwrite system.properties when first start - try (FileOutputStream outputStream = new FileOutputStream(propertiesFile)) { - systemProperties.forEach((k, v) -> properties.setProperty(k, v.get())); - properties.store( - new OutputStreamWriter(outputStream, StandardCharsets.UTF_8), SYSTEM_PROPERTIES_STRING); - } + if (systemPropertiesHandler.isFirstStart()) { if (config.getDataRegionConsensusProtocolClass().equals(ConsensusFactory.IOT_CONSENSUS) && config.getWalMode().equals(WALMode.DISABLE)) { throw new ConfigurationException( @@ -298,32 +240,15 @@ public void checkSystemConfig() throws ConfigurationException, IOException { /** repair broken properties */ private void upgradePropertiesFileFromBrokenFile() throws IOException { - // create an empty tmpPropertiesFile - if (tmpPropertiesFile.createNewFile()) { - logger.info("Create system.properties.tmp {}.", tmpPropertiesFile); - } else { - logger.error("Create system.properties.tmp {} failed.", tmpPropertiesFile); - System.exit(-1); - } - - try (FileOutputStream tmpFOS = new FileOutputStream(tmpPropertiesFile.toString())) { - systemProperties.forEach( - (k, v) -> { - if (!properties.containsKey(k)) { - properties.setProperty(k, v.get()); - } - }); - properties.setProperty(IOTDB_VERSION_STRING, IoTDBConstant.VERSION); - properties.setProperty(COMMIT_ID_STRING, IoTDBConstant.BUILD_INFO); - properties.store( - new OutputStreamWriter(tmpFOS, StandardCharsets.UTF_8), SYSTEM_PROPERTIES_STRING); - // upgrade finished, delete old system.properties file - if (propertiesFile.exists()) { - Files.delete(propertiesFile.toPath()); - } - } - // rename system.properties.tmp to system.properties - FileUtils.moveFile(tmpPropertiesFile, propertiesFile); + systemProperties.forEach( + (k, v) -> { + if (!properties.containsKey(k)) { + properties.setProperty(k, v.get()); + } + }); + properties.setProperty(IOTDB_VERSION_STRING, IoTDBConstant.VERSION); + properties.setProperty(COMMIT_ID_STRING, IoTDBConstant.BUILD_INFO); + systemPropertiesHandler.overwrite(properties); } /** Check all immutable properties */ @@ -362,44 +287,11 @@ private void throwException(String parameter, Object badValue) throws Configurat parameter + "can't be modified after first startup"); } - // reload properties from system.properties - private void reloadProperties() throws IOException { - try (FileInputStream inputStream = new FileInputStream(propertiesFile); - InputStreamReader inputStreamReader = - new InputStreamReader(inputStream, TSFileConfig.STRING_CHARSET)) { - properties.load(inputStreamReader); - } - } - /** call this method to serialize ClusterName and DataNodeId */ public void serializeClusterNameAndDataNodeId(String clusterName, int dataNodeId) throws IOException { - // create an empty tmpPropertiesFile - if (tmpPropertiesFile.createNewFile()) { - logger.info("Create system.properties.tmp {}.", tmpPropertiesFile); - } else { - logger.error("Create system.properties.tmp {} failed.", tmpPropertiesFile); - System.exit(-1); - } - - reloadProperties(); - FileOutputStream tmpFOS = new FileOutputStream(tmpPropertiesFile.toString()); - try { - properties.setProperty(IoTDBConstant.CLUSTER_NAME, clusterName); - properties.setProperty(DATA_NODE_ID, String.valueOf(dataNodeId)); - properties.store( - new OutputStreamWriter(tmpFOS, StandardCharsets.UTF_8), SYSTEM_PROPERTIES_STRING); - // serialize finished, delete old system.properties file - if (propertiesFile.exists()) { - Files.delete(propertiesFile.toPath()); - } - } finally { - tmpFOS.flush(); - tmpFOS.getFD().sync(); - tmpFOS.close(); - } - // rename system.properties.tmp to system.properties - FileUtils.moveFile(tmpPropertiesFile, propertiesFile); + systemPropertiesHandler.put( + IoTDBConstant.CLUSTER_NAME, clusterName, DATA_NODE_ID, String.valueOf(dataNodeId)); } public boolean checkConsensusProtocolExists(TConsensusGroupType type) { @@ -417,21 +309,22 @@ public void serializeMutableSystemPropertiesIfNecessary() throws IOException { long startTime = System.currentTimeMillis(); boolean needsSerialize = false; for (String param : variableParamValueTable.keySet()) { - if (!(properties.getProperty(param).equals(getVal(param)))) { + if (!properties.getProperty(param).equals(getVal(param))) { needsSerialize = true; } } if (needsSerialize) { - try (FileOutputStream outputStream = new FileOutputStream(propertiesFile)) { - systemProperties.forEach((k, v) -> properties.setProperty(k, v.get())); - properties.store( - new OutputStreamWriter(outputStream, StandardCharsets.UTF_8), SYSTEM_PROPERTIES_STRING); - } + generateOrOverwriteSystemPropertiesFile(); } long endTime = System.currentTimeMillis(); logger.info( "Serialize mutable system properties successfully, which takes {} ms.", (endTime - startTime)); } + + public void generateOrOverwriteSystemPropertiesFile() throws IOException { + systemProperties.forEach((k, v) -> properties.setProperty(k, v.get())); + systemPropertiesHandler.overwrite(properties); + } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/consensus/DataRegionConsensusImpl.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/consensus/DataRegionConsensusImpl.java index 5873a0ff628e1..515a9f54ddca4 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/consensus/DataRegionConsensusImpl.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/consensus/DataRegionConsensusImpl.java @@ -36,7 +36,7 @@ import org.apache.iotdb.db.conf.IoTDBDescriptor; import org.apache.iotdb.db.consensus.statemachine.dataregion.DataRegionStateMachine; import org.apache.iotdb.db.consensus.statemachine.dataregion.IoTConsensusDataRegionStateMachine; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.consensus.ConsensusPipeDataNodeDispatcher; import org.apache.iotdb.db.pipe.consensus.ConsensusPipeDataNodeRuntimeAgentGuardian; import org.apache.iotdb.db.pipe.consensus.ProgressIndexDataNodeManager; @@ -80,7 +80,7 @@ private static class DataRegionConsensusImplHolder { // Make sure both statics are initialized. static { reinitializeStatics(); - PipeAgent.receiver().pipeConsensus().initConsensusInRuntime(); + PipeDataNodeAgent.receiver().pipeConsensus().initConsensusInRuntime(); } private static void reinitializeStatics() { @@ -164,8 +164,9 @@ private static ConsensusConfig buildConsensusConfig() { // name .setConsensusPipeDispatcher(new ConsensusPipeDataNodeDispatcher()) .setConsensusPipeGuardian(new ConsensusPipeDataNodeRuntimeAgentGuardian()) - .setConsensusPipeSelector(() -> PipeAgent.task().getAllConsensusPipe()) - .setConsensusPipeReceiver(PipeAgent.receiver().pipeConsensus()) + .setConsensusPipeSelector( + () -> PipeDataNodeAgent.task().getAllConsensusPipe()) + .setConsensusPipeReceiver(PipeDataNodeAgent.receiver().pipeConsensus()) .setProgressIndexManager(new ProgressIndexDataNodeManager()) .setConsensusPipeGuardJobIntervalInSeconds(300) // TODO: move to config .build()) diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/consensus/statemachine/schemaregion/SchemaExecutionVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/consensus/statemachine/schemaregion/SchemaExecutionVisitor.java index 0ef64674d11d6..0f8a5f51b87eb 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/consensus/statemachine/schemaregion/SchemaExecutionVisitor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/consensus/statemachine/schemaregion/SchemaExecutionVisitor.java @@ -28,7 +28,7 @@ import org.apache.iotdb.commons.schema.view.viewExpression.ViewExpression; import org.apache.iotdb.db.exception.metadata.MeasurementAlreadyExistException; import org.apache.iotdb.db.exception.metadata.template.TemplateIsInUseException; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.extractor.schemaregion.SchemaRegionListeningQueue; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanVisitor; @@ -558,7 +558,7 @@ public TSStatus visitPipeEnrichedNonWritePlanNode( public TSStatus visitPipeOperateSchemaQueueNode( final PipeOperateSchemaQueueNode node, final ISchemaRegion schemaRegion) { final SchemaRegionId id = schemaRegion.getSchemaRegionId(); - final SchemaRegionListeningQueue queue = PipeAgent.runtime().schemaListener(id); + final SchemaRegionListeningQueue queue = PipeDataNodeAgent.runtime().schemaListener(id); if (node.isOpen() && !queue.isOpened()) { logger.info("Opened pipe listening queue on schema region {}", id); queue.open(); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/consensus/statemachine/schemaregion/SchemaRegionStateMachine.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/consensus/statemachine/schemaregion/SchemaRegionStateMachine.java index ee880200060e0..ca2c5f2821253 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/consensus/statemachine/schemaregion/SchemaRegionStateMachine.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/consensus/statemachine/schemaregion/SchemaRegionStateMachine.java @@ -27,7 +27,7 @@ import org.apache.iotdb.consensus.ratis.utils.Utils; import org.apache.iotdb.db.conf.IoTDBDescriptor; import org.apache.iotdb.db.consensus.statemachine.BaseStateMachine; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.extractor.schemaregion.SchemaRegionListeningQueue; import org.apache.iotdb.db.queryengine.execution.fragment.FragmentInstanceManager; import org.apache.iotdb.db.queryengine.plan.planner.plan.FragmentInstance; @@ -64,7 +64,7 @@ public void start() { @Override public void stop() { // Stop leader related service for schema pipe - PipeAgent.runtime().notifySchemaLeaderUnavailable(schemaRegion.getSchemaRegionId()); + PipeDataNodeAgent.runtime().notifySchemaLeaderUnavailable(schemaRegion.getSchemaRegionId()); } @Override @@ -79,7 +79,7 @@ public void notifyLeaderChanged(ConsensusGroupId groupId, int newLeaderId) { newLeaderId); // Shutdown leader related service for schema pipe - PipeAgent.runtime().notifySchemaLeaderUnavailable(schemaRegion.getSchemaRegionId()); + PipeDataNodeAgent.runtime().notifySchemaLeaderUnavailable(schemaRegion.getSchemaRegionId()); logger.info( "Current node [nodeId: {}] is no longer the schema region leader [regionId: {}], " @@ -97,7 +97,7 @@ public void notifyLeaderReady() { schemaRegion.getSchemaRegionId()); // Activate leader related service for schema pipe - PipeAgent.runtime().notifySchemaLeaderReady(schemaRegion.getSchemaRegionId()); + PipeDataNodeAgent.runtime().notifySchemaLeaderReady(schemaRegion.getSchemaRegionId()); logger.info( "Current node [nodeId: {}] as schema region leader [regionId: {}] is ready to work", @@ -113,7 +113,7 @@ public boolean isReadOnly() { @Override public boolean takeSnapshot(File snapshotDir) { if (schemaRegion.createSnapshot(snapshotDir) - && PipeAgent.runtime() + && PipeDataNodeAgent.runtime() .schemaListener(schemaRegion.getSchemaRegionId()) .createSnapshot(snapshotDir)) { listen2Snapshot4PipeListener(true); @@ -125,7 +125,7 @@ public boolean takeSnapshot(File snapshotDir) { @Override public void loadSnapshot(File latestSnapshotRootDir) { schemaRegion.loadSnapshot(latestSnapshotRootDir); - PipeAgent.runtime() + PipeDataNodeAgent.runtime() .schemaListener(schemaRegion.getSchemaRegionId()) .loadSnapshot(latestSnapshotRootDir); // We recompute the snapshot for pipe listener when loading snapshot @@ -141,7 +141,7 @@ public void listen2Snapshot4PipeListener(boolean isTmp) { .toString(), isTmp); SchemaRegionListeningQueue listener = - PipeAgent.runtime().schemaListener(schemaRegion.getSchemaRegionId()); + PipeDataNodeAgent.runtime().schemaListener(schemaRegion.getSchemaRegionId()); if (Objects.isNull(snapshotPaths) || Objects.isNull(snapshotPaths.getLeft())) { if (listener.isOpened()) { logger.warn( @@ -164,7 +164,7 @@ public TSStatus write(IConsensusRequest request) { try { TSStatus result = ((PlanNode) request).accept(new SchemaExecutionVisitor(), schemaRegion); if (result.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { - PipeAgent.runtime() + PipeDataNodeAgent.runtime() .schemaListener(schemaRegion.getSchemaRegionId()) .tryListenToNode((PlanNode) request); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/agent/PipeAgent.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/agent/PipeDataNodeAgent.java similarity index 81% rename from iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/agent/PipeAgent.java rename to iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/agent/PipeDataNodeAgent.java index 5ed3bed0898bc..e350f0a6f4bbb 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/agent/PipeAgent.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/agent/PipeDataNodeAgent.java @@ -25,8 +25,8 @@ import org.apache.iotdb.db.pipe.agent.task.PipeDataNodeTaskAgent; import org.apache.iotdb.db.service.DataNode; -/** {@link PipeAgent} is the entry point of the pipe module in {@link DataNode}. */ -public class PipeAgent { +/** {@link PipeDataNodeAgent} is the entry point of the pipe module in {@link DataNode}. */ +public class PipeDataNodeAgent { private final PipeDataNodePluginAgent pipeDataNodePluginAgent; private final PipeDataNodeTaskAgent pipeDataNodeTaskAgent; @@ -34,16 +34,16 @@ public class PipeAgent { private final PipeDataNodeReceiverAgent pipeDataNodeReceiverAgent; /** Private constructor to prevent users from creating a new instance. */ - private PipeAgent() { + private PipeDataNodeAgent() { pipeDataNodePluginAgent = new PipeDataNodePluginAgent(); pipeDataNodeTaskAgent = new PipeDataNodeTaskAgent(); pipeDataNodeRuntimeAgent = new PipeDataNodeRuntimeAgent(); pipeDataNodeReceiverAgent = new PipeDataNodeReceiverAgent(); } - /** The singleton holder of {@link PipeAgent}. */ - private static class PipeAgentHolder { - private static final PipeAgent HANDLE = new PipeAgent(); + /** The singleton holder of {@link PipeDataNodeAgent}. */ + private static class PipeDataNodeAgentHolder { + private static final PipeDataNodeAgent HANDLE = new PipeDataNodeAgent(); } /** @@ -52,7 +52,7 @@ private static class PipeAgentHolder { * @return the singleton instance of {@link PipeDataNodeTaskAgent} */ public static PipeDataNodeTaskAgent task() { - return PipeAgentHolder.HANDLE.pipeDataNodeTaskAgent; + return PipeDataNodeAgentHolder.HANDLE.pipeDataNodeTaskAgent; } /** @@ -61,7 +61,7 @@ public static PipeDataNodeTaskAgent task() { * @return the singleton instance of {@link PipeDataNodePluginAgent} */ public static PipeDataNodePluginAgent plugin() { - return PipeAgentHolder.HANDLE.pipeDataNodePluginAgent; + return PipeDataNodeAgentHolder.HANDLE.pipeDataNodePluginAgent; } /** @@ -70,7 +70,7 @@ public static PipeDataNodePluginAgent plugin() { * @return the singleton instance of {@link PipeDataNodeRuntimeAgent} */ public static PipeDataNodeRuntimeAgent runtime() { - return PipeAgentHolder.HANDLE.pipeDataNodeRuntimeAgent; + return PipeDataNodeAgentHolder.HANDLE.pipeDataNodeRuntimeAgent; } /** @@ -79,6 +79,6 @@ public static PipeDataNodeRuntimeAgent runtime() { * @return the singleton instance of {@link PipeDataNodeReceiverAgent} */ public static PipeDataNodeReceiverAgent receiver() { - return PipeAgentHolder.HANDLE.pipeDataNodeReceiverAgent; + return PipeDataNodeAgentHolder.HANDLE.pipeDataNodeReceiverAgent; } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/agent/runtime/PipeAgentLauncher.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/agent/runtime/PipeAgentLauncher.java index 45bd440ef7ccc..7138369639a7d 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/agent/runtime/PipeAgentLauncher.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/agent/runtime/PipeAgentLauncher.java @@ -30,7 +30,7 @@ import org.apache.iotdb.confignode.rpc.thrift.TGetJarInListResp; import org.apache.iotdb.db.conf.IoTDBConfig; import org.apache.iotdb.db.conf.IoTDBDescriptor; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.protocol.client.ConfigNodeClient; import org.apache.iotdb.db.protocol.client.ConfigNodeClientManager; import org.apache.iotdb.db.protocol.client.ConfigNodeInfo; @@ -88,7 +88,7 @@ public static synchronized void launchPipePluginAgent( if (meta.isBuiltin()) { continue; } - PipeAgent.plugin().doRegister(meta); + PipeDataNodeAgent.plugin().doRegister(meta); } } catch (Exception e) { throw new StartupException(e); @@ -159,7 +159,7 @@ public static synchronized void launchPipeTaskAgent() { throw new StartupException("Failed to get pipe task meta from config node."); } - PipeAgent.task() + PipeDataNodeAgent.task() .handlePipeMetaChanges( getAllPipeInfoResp.getAllPipeInfo().stream() .map( diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/agent/runtime/PipeDataNodeRuntimeAgent.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/agent/runtime/PipeDataNodeRuntimeAgent.java index 447fcbc3b6af0..dcf9f8b0435bb 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/agent/runtime/PipeDataNodeRuntimeAgent.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/agent/runtime/PipeDataNodeRuntimeAgent.java @@ -32,7 +32,7 @@ import org.apache.iotdb.commons.service.ServiceType; import org.apache.iotdb.commons.utils.TestOnly; import org.apache.iotdb.db.conf.IoTDBDescriptor; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.extractor.schemaregion.SchemaRegionListeningQueue; import org.apache.iotdb.db.pipe.progress.SimpleProgressIndexAssigner; import org.apache.iotdb.db.pipe.resource.PipeDataNodeHardlinkOrCopiedFileDirStartupCleaner; @@ -70,7 +70,7 @@ public synchronized void preparePipeResources( PipeDataNodeHardlinkOrCopiedFileDirStartupCleaner.clean(); // Clean receiver file dir - PipeAgent.receiver().cleanPipeReceiverDirs(); + PipeDataNodeAgent.receiver().cleanPipeReceiverDirs(); PipeAgentLauncher.launchPipePluginAgent(resourcesInformationHolder); simpleProgressIndexAssigner.start(); @@ -83,7 +83,7 @@ public synchronized void start() throws StartupException { registerPeriodicalJob( "PipeTaskAgent#restartAllStuckPipes", - PipeAgent.task()::restartAllStuckPipes, + PipeDataNodeAgent.task()::restartAllStuckPipes, PipeConfig.getInstance().getPipeStuckRestartIntervalSeconds()); pipePeriodicalJobExecutor.start(); @@ -98,7 +98,7 @@ public synchronized void stop() { isShutdown.set(true); pipePeriodicalJobExecutor.stop(); - PipeAgent.task().dropAllPipeTasks(); + PipeDataNodeAgent.task().dropAllPipeTasks(); } public boolean isShutdown() { @@ -207,7 +207,7 @@ public void report(PipeTaskMeta pipeTaskMeta, PipeRuntimeException pipeRuntimeEx // Quick stop all pipes locally if critical exception occurs, // no need to wait for the next heartbeat cycle. if (pipeRuntimeException instanceof PipeRuntimeCriticalException) { - PipeAgent.task().stopAllPipesWithCriticalException(); + PipeDataNodeAgent.task().stopAllPipesWithCriticalException(); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/agent/task/PipeDataNodeTaskAgent.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/agent/task/PipeDataNodeTaskAgent.java index 37c04e26f5085..0255dc05c3555 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/agent/task/PipeDataNodeTaskAgent.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/agent/task/PipeDataNodeTaskAgent.java @@ -40,7 +40,7 @@ import org.apache.iotdb.db.conf.IoTDBConfig; import org.apache.iotdb.db.conf.IoTDBDescriptor; import org.apache.iotdb.db.consensus.SchemaRegionConsensusImpl; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.extractor.dataregion.DataRegionListeningFilter; import org.apache.iotdb.db.pipe.extractor.dataregion.IoTDBDataRegionExtractor; import org.apache.iotdb.db.pipe.extractor.dataregion.realtime.listener.PipeInsertionDataNodeListener; @@ -96,7 +96,7 @@ public class PipeDataNodeTaskAgent extends PipeTaskAgent { @Override protected boolean isShutdown() { - return PipeAgent.runtime().isShutdown(); + return PipeDataNodeAgent.runtime().isShutdown(); } @Override @@ -204,7 +204,7 @@ private Set clearSchemaRegionListeningQueueIfNecessary( schemaRegionId2ListeningQueueNewFirstIndex.forEach( (schemaRegionId, listeningQueueNewFirstIndex) -> - PipeAgent.runtime() + PipeDataNodeAgent.runtime() .schemaListener(new SchemaRegionId(schemaRegionId)) .removeBefore(listeningQueueNewFirstIndex)); @@ -218,12 +218,12 @@ private void closeSchemaRegionListeningQueueIfNecessary( return; } - PipeAgent.runtime() + PipeDataNodeAgent.runtime() .listeningSchemaRegionIds() .forEach( schemaRegionId -> { if (!validSchemaRegionIds.contains(schemaRegionId.getId()) - && PipeAgent.runtime().isSchemaLeaderReady(schemaRegionId)) { + && PipeDataNodeAgent.runtime().isSchemaLeaderReady(schemaRegionId)) { try { SchemaRegionConsensusImpl.getInstance() .write( @@ -238,16 +238,33 @@ private void closeSchemaRegionListeningQueueIfNecessary( } @Override - protected void dropPipe(final String pipeName, final long creationTime) { - super.dropPipe(pipeName, creationTime); + protected void thawRate(final String pipeName, final long creationTime) { + PipeDataNodeRemainingEventAndTimeMetrics.getInstance().thawRate(pipeName + "_" + creationTime); + } + + @Override + protected void freezeRate(final String pipeName, final long creationTime) { + PipeDataNodeRemainingEventAndTimeMetrics.getInstance() + .freezeRate(pipeName + "_" + creationTime); + } + + @Override + protected boolean dropPipe(final String pipeName, final long creationTime) { + if (!super.dropPipe(pipeName, creationTime)) { + return false; + } PipeDataNodeRemainingEventAndTimeMetrics.getInstance() .deregister(pipeName + "_" + creationTime); + + return true; } @Override - protected void dropPipe(final String pipeName) { - super.dropPipe(pipeName); + protected boolean dropPipe(final String pipeName) { + if (!super.dropPipe(pipeName)) { + return false; + } final PipeMeta pipeMeta = pipeMetaKeeper.getPipeMeta(pipeName); if (Objects.nonNull(pipeMeta)) { @@ -255,6 +272,8 @@ protected void dropPipe(final String pipeName) { PipeDataNodeRemainingEventAndTimeMetrics.getInstance() .deregister(pipeName + "_" + creationTime); } + + return true; } public void stopAllPipesWithCriticalException() { @@ -278,7 +297,7 @@ public void collectPipeMetaList(final TDataNodeHeartbeatResp resp) throws TExcep private void collectPipeMetaListInternal(final TDataNodeHeartbeatResp resp) throws TException { // Do nothing if data node is removing or removed, or request does not need pipe meta list - if (PipeAgent.runtime().isShutdown()) { + if (PipeDataNodeAgent.runtime().isShutdown()) { return; } @@ -356,7 +375,7 @@ private void collectPipeMetaListInternal(final TDataNodeHeartbeatResp resp) thro protected void collectPipeMetaListInternal( final TPipeHeartbeatReq req, final TPipeHeartbeatResp resp) throws TException { // Do nothing if data node is removing or removed, or request does not need pipe meta list - if (PipeAgent.runtime().isShutdown()) { + if (PipeDataNodeAgent.runtime().isShutdown()) { return; } LOGGER.info("Received pipe heartbeat request {} from config node.", req.heartbeatId); @@ -612,7 +631,7 @@ public Set getPipeTaskRegionIdSet(final String pipeName, final long cre ///////////////////////// Pipe Consensus ///////////////////////// - public ProgressIndex getPipeTaskProgressIndex(String pipeName, int consensusGroupId) { + public ProgressIndex getPipeTaskProgressIndex(final String pipeName, final int consensusGroupId) { if (!tryReadLockWithTimeOut(10)) { throw new PipeException( String.format( diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/client/IoTDBDataNodeCacheLeaderClientManager.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/client/IoTDBDataNodeCacheLeaderClientManager.java index be3cb9d4fdaeb..965a2a068bf2d 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/client/IoTDBDataNodeCacheLeaderClientManager.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/client/IoTDBDataNodeCacheLeaderClientManager.java @@ -50,21 +50,22 @@ class LeaderCacheManager { private final ConcurrentHashMap endPoints = new ConcurrentHashMap<>(); public LeaderCacheManager() { - long initMemorySizeInBytes = PipeResourceManager.memory().getTotalMemorySizeInBytes() / 10; - long maxMemorySizeInBytes = + final long initMemorySizeInBytes = + PipeResourceManager.memory().getTotalMemorySizeInBytes() / 10; + final long maxMemorySizeInBytes = (long) (PipeResourceManager.memory().getTotalMemorySizeInBytes() * CONFIG.getPipeLeaderCacheMemoryUsagePercentage()); // properties required by pipe memory control framework - PipeMemoryBlock allocatedMemoryBlock = + final PipeMemoryBlock allocatedMemoryBlock = PipeResourceManager.memory() .tryAllocate(initMemorySizeInBytes) .setShrinkMethod(oldMemory -> Math.max(oldMemory / 2, 1)) .setShrinkCallback( (oldMemory, newMemory) -> { - memoryUsageCheatFactor.set( - memoryUsageCheatFactor.get() * ((double) oldMemory / newMemory)); + memoryUsageCheatFactor.updateAndGet( + factor -> factor * ((double) oldMemory / newMemory)); LOGGER.info( "LeaderCacheManager.allocatedMemoryBlock has shrunk from {} to {}.", oldMemory, @@ -74,8 +75,8 @@ public LeaderCacheManager() { oldMemory -> Math.min(Math.max(oldMemory, 1) * 2, maxMemorySizeInBytes)) .setExpandCallback( (oldMemory, newMemory) -> { - memoryUsageCheatFactor.set( - memoryUsageCheatFactor.get() / ((double) newMemory / oldMemory)); + memoryUsageCheatFactor.updateAndGet( + factor -> factor / ((double) newMemory / oldMemory)); LOGGER.info( "LeaderCacheManager.allocatedMemoryBlock has expanded from {} to {}.", oldMemory, @@ -100,16 +101,16 @@ public LeaderCacheManager() { .build(); } - public TEndPoint getLeaderEndPoint(String deviceId) { + public TEndPoint getLeaderEndPoint(final String deviceId) { return deviceId == null ? null : device2endpoint.getIfPresent(deviceId); } - public void updateLeaderEndPoint(String deviceId, TEndPoint endPoint) { + public void updateLeaderEndPoint(final String deviceId, final TEndPoint endPoint) { if (deviceId == null || endPoint == null) { return; } - TEndPoint endPointFromMap = endPoints.putIfAbsent(endPoint, endPoint); + final TEndPoint endPointFromMap = endPoints.putIfAbsent(endPoint, endPoint); if (endPointFromMap != null) { device2endpoint.put(deviceId, endPointFromMap); } else { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/payload/evolvable/builder/PipeEventBatch.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/payload/evolvable/builder/PipeEventBatch.java index 44d72b1e1c794..9707031330897 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/payload/evolvable/builder/PipeEventBatch.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/payload/evolvable/builder/PipeEventBatch.java @@ -30,6 +30,7 @@ import org.apache.iotdb.pipe.api.event.Event; import org.apache.iotdb.pipe.api.event.dml.insertion.TabletInsertionEvent; +import org.apache.tsfile.utils.Pair; import org.apache.tsfile.utils.PublicBAOS; import org.apache.tsfile.utils.ReadWriteIOUtils; import org.slf4j.Logger; @@ -64,7 +65,7 @@ public class PipeEventBatch implements AutoCloseable { private long totalBufferSize = 0; // Used to rate limit when transferring data - private final Map pipeName2BytesAccumulated = new HashMap<>(); + private final Map, Long> pipe2BytesAccumulated = new HashMap<>(); public PipeEventBatch(int maxDelayInMs, long requestMaxBatchSizeInBytes) { this.maxDelayInMs = maxDelayInMs; @@ -117,8 +118,9 @@ public synchronized boolean onEvent(final TabletInsertionEvent event) final int bufferSize = buildTabletInsertionBuffer(event); totalBufferSize += bufferSize; - pipeName2BytesAccumulated.compute( - ((EnrichedEvent) event).getPipeName(), + pipe2BytesAccumulated.compute( + new Pair<>( + ((EnrichedEvent) event).getPipeName(), ((EnrichedEvent) event).getCreationTime()), (pipeName, bytesAccumulated) -> bytesAccumulated == null ? bufferSize : bytesAccumulated + bufferSize); @@ -146,7 +148,7 @@ public synchronized void onSuccess() { firstEventProcessingTime = Long.MIN_VALUE; totalBufferSize = 0; - pipeName2BytesAccumulated.clear(); + pipe2BytesAccumulated.clear(); } public PipeTransferTabletBatchReq toTPipeTransferReq() throws IOException { @@ -170,12 +172,12 @@ public List deepCopyRequestCommitIds() { return new ArrayList<>(requestCommitIds); } - public Map deepCopyPipeName2BytesAccumulated() { - return new HashMap<>(pipeName2BytesAccumulated); + public Map, Long> deepCopyPipeName2BytesAccumulated() { + return new HashMap<>(pipe2BytesAccumulated); } - public Map getPipeName2BytesAccumulated() { - return pipeName2BytesAccumulated; + public Map, Long> getPipe2BytesAccumulated() { + return pipe2BytesAccumulated; } private int buildTabletInsertionBuffer(final TabletInsertionEvent event) diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/payload/evolvable/request/PipeTransferTabletRawReq.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/payload/evolvable/request/PipeTransferTabletRawReq.java index 8aa68e88756f4..451ec7d5bebc6 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/payload/evolvable/request/PipeTransferTabletRawReq.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/payload/evolvable/request/PipeTransferTabletRawReq.java @@ -43,6 +43,7 @@ import java.io.DataOutputStream; import java.io.IOException; import java.nio.ByteBuffer; +import java.time.LocalDate; import java.util.Arrays; import java.util.Comparator; import java.util.Objects; @@ -70,7 +71,7 @@ public InsertTabletStatement constructStatement() { try { final TSInsertTabletReq request = new TSInsertTabletReq(); - for (IMeasurementSchema measurementSchema : tablet.getSchemas()) { + for (final IMeasurementSchema measurementSchema : tablet.getSchemas()) { request.addToMeasurements(measurementSchema.getMeasurementId()); request.addToTypes(measurementSchema.getType().ordinal()); } @@ -84,13 +85,13 @@ public InsertTabletStatement constructStatement() { PathUtils.checkIsLegalSingleMeasurementsAndUpdate(request.getMeasurements())); return StatementGenerator.createStatement(request); - } catch (MetadataException e) { + } catch (final MetadataException e) { LOGGER.warn("Generate Statement from tablet {} error.", tablet, e); return null; } } - private static boolean checkSorted(Tablet tablet) { + private static boolean checkSorted(final Tablet tablet) { for (int i = 1; i < tablet.rowSize; i++) { if (tablet.timestamps[i] < tablet.timestamps[i - 1]) { return false; @@ -99,13 +100,13 @@ private static boolean checkSorted(Tablet tablet) { return true; } - private static void sortTablet(Tablet tablet) { + private static void sortTablet(final Tablet tablet) { /* * following part of code sort the batch data by time, * so we can insert continuous data in value list to get a better performance */ // sort to get index, and use index to sort value list - Integer[] index = new Integer[tablet.rowSize]; + final Integer[] index = new Integer[tablet.rowSize]; for (int i = 0; i < tablet.rowSize; i++) { index[i] = i; } @@ -113,7 +114,7 @@ private static void sortTablet(Tablet tablet) { Arrays.sort(tablet.timestamps, 0, tablet.rowSize); int columnIndex = 0; for (int i = 0; i < tablet.getSchemas().size(); i++) { - IMeasurementSchema schema = tablet.getSchemas().get(i); + final IMeasurementSchema schema = tablet.getSchemas().get(i); if (schema != null) { tablet.values[columnIndex] = sortList(tablet.values[columnIndex], schema.getType(), index); if (tablet.bitMaps != null && tablet.bitMaps[columnIndex] != null) { @@ -133,46 +134,57 @@ private static void sortTablet(Tablet tablet) { * @return sorted list * @throws UnSupportedDataTypeException if dataType is illegal */ - private static Object sortList(Object valueList, TSDataType dataType, Integer[] index) { + private static Object sortList( + final Object valueList, final TSDataType dataType, final Integer[] index) { switch (dataType) { case BOOLEAN: - boolean[] boolValues = (boolean[]) valueList; - boolean[] sortedValues = new boolean[boolValues.length]; + final boolean[] boolValues = (boolean[]) valueList; + final boolean[] sortedValues = new boolean[boolValues.length]; for (int i = 0; i < index.length; i++) { sortedValues[i] = boolValues[index[i]]; } return sortedValues; case INT32: - int[] intValues = (int[]) valueList; - int[] sortedIntValues = new int[intValues.length]; + final int[] intValues = (int[]) valueList; + final int[] sortedIntValues = new int[intValues.length]; for (int i = 0; i < index.length; i++) { sortedIntValues[i] = intValues[index[i]]; } return sortedIntValues; + case DATE: + final LocalDate[] dateValues = (LocalDate[]) valueList; + final LocalDate[] sortedDateValues = new LocalDate[dateValues.length]; + for (int i = 0; i < index.length; i++) { + sortedDateValues[i] = dateValues[index[i]]; + } + return sortedDateValues; case INT64: - long[] longValues = (long[]) valueList; - long[] sortedLongValues = new long[longValues.length]; + case TIMESTAMP: + final long[] longValues = (long[]) valueList; + final long[] sortedLongValues = new long[longValues.length]; for (int i = 0; i < index.length; i++) { sortedLongValues[i] = longValues[index[i]]; } return sortedLongValues; case FLOAT: - float[] floatValues = (float[]) valueList; - float[] sortedFloatValues = new float[floatValues.length]; + final float[] floatValues = (float[]) valueList; + final float[] sortedFloatValues = new float[floatValues.length]; for (int i = 0; i < index.length; i++) { sortedFloatValues[i] = floatValues[index[i]]; } return sortedFloatValues; case DOUBLE: - double[] doubleValues = (double[]) valueList; - double[] sortedDoubleValues = new double[doubleValues.length]; + final double[] doubleValues = (double[]) valueList; + final double[] sortedDoubleValues = new double[doubleValues.length]; for (int i = 0; i < index.length; i++) { sortedDoubleValues[i] = doubleValues[index[i]]; } return sortedDoubleValues; case TEXT: - Binary[] binaryValues = (Binary[]) valueList; - Binary[] sortedBinaryValues = new Binary[binaryValues.length]; + case BLOB: + case STRING: + final Binary[] binaryValues = (Binary[]) valueList; + final Binary[] sortedBinaryValues = new Binary[binaryValues.length]; for (int i = 0; i < index.length; i++) { sortedBinaryValues[i] = binaryValues[index[i]]; } @@ -190,8 +202,8 @@ private static Object sortList(Object valueList, TSDataType dataType, Integer[] * @param index index * @return sorted bitMap */ - private static BitMap sortBitMap(BitMap bitMap, Integer[] index) { - BitMap sortedBitMap = new BitMap(bitMap.getSize()); + private static BitMap sortBitMap(final BitMap bitMap, final Integer[] index) { + final BitMap sortedBitMap = new BitMap(bitMap.getSize()); for (int i = 0; i < index.length; i++) { if (bitMap.isMarked(index[i])) { sortedBitMap.mark(i); @@ -202,7 +214,8 @@ private static BitMap sortBitMap(BitMap bitMap, Integer[] index) { /////////////////////////////// WriteBack & Batch /////////////////////////////// - public static PipeTransferTabletRawReq toTPipeTransferRawReq(Tablet tablet, boolean isAligned) { + public static PipeTransferTabletRawReq toTPipeTransferRawReq( + final Tablet tablet, final boolean isAligned) { final PipeTransferTabletRawReq tabletReq = new PipeTransferTabletRawReq(); tabletReq.tablet = tablet; @@ -213,8 +226,8 @@ public static PipeTransferTabletRawReq toTPipeTransferRawReq(Tablet tablet, bool /////////////////////////////// Thrift /////////////////////////////// - public static PipeTransferTabletRawReq toTPipeTransferReq(Tablet tablet, boolean isAligned) - throws IOException { + public static PipeTransferTabletRawReq toTPipeTransferReq( + final Tablet tablet, final boolean isAligned) throws IOException { final PipeTransferTabletRawReq tabletReq = new PipeTransferTabletRawReq(); tabletReq.tablet = tablet; @@ -233,7 +246,7 @@ public static PipeTransferTabletRawReq toTPipeTransferReq(Tablet tablet, boolean return tabletReq; } - public static PipeTransferTabletRawReq fromTPipeTransferReq(TPipeTransferReq transferReq) { + public static PipeTransferTabletRawReq fromTPipeTransferReq(final TPipeTransferReq transferReq) { final PipeTransferTabletRawReq tabletReq = new PipeTransferTabletRawReq(); tabletReq.tablet = Tablet.deserialize(transferReq.body); @@ -248,7 +261,8 @@ public static PipeTransferTabletRawReq fromTPipeTransferReq(TPipeTransferReq tra /////////////////////////////// Air Gap /////////////////////////////// - public static byte[] toTPipeTransferBytes(Tablet tablet, boolean isAligned) throws IOException { + public static byte[] toTPipeTransferBytes(final Tablet tablet, final boolean isAligned) + throws IOException { try (final PublicBAOS byteArrayOutputStream = new PublicBAOS(); final DataOutputStream outputStream = new DataOutputStream(byteArrayOutputStream)) { ReadWriteIOUtils.write(IoTDBConnectorRequestVersion.VERSION_1.getVersion(), outputStream); @@ -262,14 +276,14 @@ public static byte[] toTPipeTransferBytes(Tablet tablet, boolean isAligned) thro /////////////////////////////// Object /////////////////////////////// @Override - public boolean equals(Object obj) { + public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } - PipeTransferTabletRawReq that = (PipeTransferTabletRawReq) obj; + final PipeTransferTabletRawReq that = (PipeTransferTabletRawReq) obj; return Objects.equals(tablet, that.tablet) && isAligned == that.isAligned && version == that.version diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/airgap/IoTDBDataNodeAirGapConnector.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/airgap/IoTDBDataNodeAirGapConnector.java index f6e80a2891760..b66c0012700c9 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/airgap/IoTDBDataNodeAirGapConnector.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/airgap/IoTDBDataNodeAirGapConnector.java @@ -127,6 +127,7 @@ private void doTransfer( throws PipeException, IOException { if (!send( pipeSchemaRegionWritePlanEvent.getPipeName(), + pipeSchemaRegionWritePlanEvent.getCreationTime(), socket, PipeTransferPlanNodeReq.toTPipeTransferBytes( pipeSchemaRegionWritePlanEvent.getPlanNode()))) { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/airgap/IoTDBDataRegionAirGapConnector.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/airgap/IoTDBDataRegionAirGapConnector.java index e83cd623fed64..22377cc9a6dd7 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/airgap/IoTDBDataRegionAirGapConnector.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/airgap/IoTDBDataRegionAirGapConnector.java @@ -174,7 +174,11 @@ private void doTransfer( pipeInsertNodeTabletInsertionEvent.getByteBuffer()) : PipeTransferTabletInsertNodeReq.toTPipeTransferBytes(insertNode); - if (!send(pipeInsertNodeTabletInsertionEvent.getPipeName(), socket, bytes)) { + if (!send( + pipeInsertNodeTabletInsertionEvent.getPipeName(), + pipeInsertNodeTabletInsertionEvent.getCreationTime(), + socket, + bytes)) { final String errorMessage = String.format( "Transfer PipeInsertNodeTabletInsertionEvent %s error. Socket: %s", @@ -208,6 +212,7 @@ private void doTransfer( throws PipeException, IOException { if (!send( pipeRawTabletInsertionEvent.getPipeName(), + pipeRawTabletInsertionEvent.getCreationTime(), socket, PipeTransferTabletRawReq.toTPipeTransferBytes( pipeRawTabletInsertionEvent.convertToTablet(), @@ -244,17 +249,19 @@ private void doTransfer( final AirGapSocket socket, final PipeTsFileInsertionEvent pipeTsFileInsertionEvent) throws PipeException, IOException { final String pipeName = pipeTsFileInsertionEvent.getPipeName(); + final long creationTime = pipeTsFileInsertionEvent.getCreationTime(); final File tsFile = pipeTsFileInsertionEvent.getTsFile(); final String errorMessage = String.format("Seal file %s error. Socket %s.", tsFile, socket); // 1. Transfer file piece by piece, and mod if needed if (pipeTsFileInsertionEvent.isWithMod() && supportModsIfIsDataNodeReceiver) { final File modFile = pipeTsFileInsertionEvent.getModFile(); - transferFilePieces(pipeName, modFile, socket, true); - transferFilePieces(pipeName, tsFile, socket, true); + transferFilePieces(pipeName, creationTime, modFile, socket, true); + transferFilePieces(pipeName, creationTime, tsFile, socket, true); // 2. Transfer file seal signal with mod, which means the file is transferred completely if (!send( pipeName, + creationTime, socket, PipeTransferTsFileSealWithModReq.toTPipeTransferBytes( modFile.getName(), modFile.length(), tsFile.getName(), tsFile.length()))) { @@ -267,10 +274,11 @@ private void doTransfer( LOGGER.info("Successfully transferred file {}.", tsFile); } } else { - transferFilePieces(pipeName, tsFile, socket, false); + transferFilePieces(pipeName, creationTime, tsFile, socket, false); // 2. Transfer file seal signal without mod, which means the file is transferred completely if (!send( pipeName, + creationTime, socket, PipeTransferTsFileSealReq.toTPipeTransferBytes(tsFile.getName(), tsFile.length()))) { receiverStatusHandler.handle( diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/airgap/IoTDBSchemaRegionAirGapConnector.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/airgap/IoTDBSchemaRegionAirGapConnector.java index a97408266b7a9..e53423779d0db 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/airgap/IoTDBSchemaRegionAirGapConnector.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/airgap/IoTDBSchemaRegionAirGapConnector.java @@ -103,17 +103,19 @@ private void doTransfer( final AirGapSocket socket, final PipeSchemaRegionSnapshotEvent pipeSchemaRegionSnapshotEvent) throws PipeException, IOException { final String pipeName = pipeSchemaRegionSnapshotEvent.getPipeName(); + final long creationTime = pipeSchemaRegionSnapshotEvent.getCreationTime(); final File mtreeSnapshotFile = pipeSchemaRegionSnapshotEvent.getMTreeSnapshotFile(); final File tagLogSnapshotFile = pipeSchemaRegionSnapshotEvent.getTagLogSnapshotFile(); // 1. Transfer mTreeSnapshotFile, and tLog file if exists - transferFilePieces(pipeName, mtreeSnapshotFile, socket, true); + transferFilePieces(pipeName, creationTime, mtreeSnapshotFile, socket, true); if (Objects.nonNull(tagLogSnapshotFile)) { - transferFilePieces(pipeName, tagLogSnapshotFile, socket, true); + transferFilePieces(pipeName, creationTime, tagLogSnapshotFile, socket, true); } // 2. Transfer file seal signal, which means the snapshots is transferred completely if (!send( pipeName, + creationTime, socket, PipeTransferSchemaSnapshotSealReq.toTPipeTransferBytes( // The pattern is surely Non-null diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/opcua/OpcUaConnector.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/opcua/OpcUaConnector.java index 2f4567a7fc6f2..ba134b5dcc93b 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/opcua/OpcUaConnector.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/opcua/OpcUaConnector.java @@ -45,6 +45,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.time.LocalDate; import java.util.Arrays; import java.util.Map; import java.util.UUID; @@ -260,7 +261,13 @@ private void transferTablet(final OpcUaServer server, final Tablet tablet) throw LocalizedText.english( Integer.toString(((int[]) tablet.values[columnIndex])[rowIndex]))); break; + case DATE: + eventNode.setMessage( + LocalizedText.english( + (((LocalDate[]) tablet.values[columnIndex])[rowIndex]).toString())); + break; case INT64: + case TIMESTAMP: eventNode.setMessage( LocalizedText.english( Long.toString(((long[]) tablet.values[columnIndex])[rowIndex]))); @@ -276,6 +283,8 @@ private void transferTablet(final OpcUaServer server, final Tablet tablet) throw Double.toString(((double[]) tablet.values[columnIndex])[rowIndex]))); break; case TEXT: + case BLOB: + case STRING: eventNode.setMessage( LocalizedText.english( ((Binary[]) tablet.values[columnIndex])[rowIndex].toString())); @@ -300,13 +309,18 @@ private NodeId convertToOpcDataType(final TSDataType type) { return Identifiers.Boolean; case INT32: return Identifiers.Int32; + case DATE: + return Identifiers.DateTime; case INT64: + case TIMESTAMP: return Identifiers.Int64; case FLOAT: return Identifiers.Float; case DOUBLE: return Identifiers.Double; case TEXT: + case BLOB: + case STRING: return Identifiers.String; case VECTOR: case UNKNOWN: diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/pipeconsensus/PipeConsensusAsyncConnector.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/pipeconsensus/PipeConsensusAsyncConnector.java index 50da4d56839f9..526773bf81a98 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/pipeconsensus/PipeConsensusAsyncConnector.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/pipeconsensus/PipeConsensusAsyncConnector.java @@ -25,26 +25,33 @@ import org.apache.iotdb.commons.client.IClientManager; import org.apache.iotdb.commons.client.async.AsyncPipeConsensusServiceClient; import org.apache.iotdb.commons.client.container.PipeConsensusClientMgrContainer; +import org.apache.iotdb.commons.consensus.ConsensusGroupId; import org.apache.iotdb.commons.consensus.index.ProgressIndex; -import org.apache.iotdb.commons.pipe.config.constant.PipeConnectorConstant; import org.apache.iotdb.commons.pipe.connector.protocol.IoTDBConnector; import org.apache.iotdb.commons.pipe.event.EnrichedEvent; +import org.apache.iotdb.commons.pipe.progress.PipeEventCommitManager; +import org.apache.iotdb.commons.service.metric.MetricService; +import org.apache.iotdb.consensus.pipe.consensuspipe.ConsensusPipeConnector; +import org.apache.iotdb.consensus.pipe.metric.PipeConsensusSyncLagManager; import org.apache.iotdb.consensus.pipe.thrift.TCommitId; import org.apache.iotdb.consensus.pipe.thrift.TPipeConsensusTransferReq; import org.apache.iotdb.db.conf.IoTDBConfig; import org.apache.iotdb.db.conf.IoTDBDescriptor; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.connector.protocol.pipeconsensus.handler.PipeConsensusTabletBatchEventHandler; import org.apache.iotdb.db.pipe.connector.protocol.pipeconsensus.handler.PipeConsensusTabletInsertNodeEventHandler; import org.apache.iotdb.db.pipe.connector.protocol.pipeconsensus.handler.PipeConsensusTsFileInsertionEventHandler; import org.apache.iotdb.db.pipe.connector.protocol.pipeconsensus.payload.builder.PipeConsensusAsyncBatchReqBuilder; import org.apache.iotdb.db.pipe.connector.protocol.pipeconsensus.payload.request.PipeConsensusTabletBinaryReq; import org.apache.iotdb.db.pipe.connector.protocol.pipeconsensus.payload.request.PipeConsensusTabletInsertNodeReq; +import org.apache.iotdb.db.pipe.consensus.PipeConsensusConnectorMetrics; import org.apache.iotdb.db.pipe.event.common.heartbeat.PipeHeartbeatEvent; import org.apache.iotdb.db.pipe.event.common.tablet.PipeInsertNodeTabletInsertionEvent; import org.apache.iotdb.db.pipe.event.common.tablet.PipeRawTabletInsertionEvent; import org.apache.iotdb.db.pipe.event.common.tsfile.PipeTsFileInsertionEvent; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.write.InsertNode; import org.apache.iotdb.pipe.api.customizer.configuration.PipeConnectorRuntimeConfiguration; +import org.apache.iotdb.pipe.api.customizer.parameter.PipeParameterValidator; import org.apache.iotdb.pipe.api.customizer.parameter.PipeParameters; import org.apache.iotdb.pipe.api.event.Event; import org.apache.iotdb.pipe.api.event.dml.insertion.TabletInsertionEvent; @@ -64,48 +71,51 @@ import java.util.concurrent.TimeUnit; import java.util.concurrent.atomic.AtomicBoolean; +import static org.apache.iotdb.commons.pipe.config.constant.PipeConnectorConstant.CONNECTOR_CONSENSUS_GROUP_ID_KEY; +import static org.apache.iotdb.commons.pipe.config.constant.PipeConnectorConstant.CONNECTOR_CONSENSUS_PIPE_NAME; + // TODO: Optimize the network and disk io for TsFile onComplete // TODO: support Tablet Batch -public class PipeConsensusAsyncConnector extends IoTDBConnector { - +public class PipeConsensusAsyncConnector extends IoTDBConnector implements ConsensusPipeConnector { private static final Logger LOGGER = LoggerFactory.getLogger(PipeConsensusAsyncConnector.class); - - private static final String CUSTOMIZE_EXCEPTION_MSG = - "Failed to customize pipeConsensusAsyncConnector because there isn't consensusGroupId passed in. Please check your construct parameters."; - private static final String ENQUEUE_EXCEPTION_MSG = "Timeout: PipeConsensusConnector offers an event into transferBuffer failed, because transferBuffer is full."; - private static final String THRIFT_ERROR_FORMATTER_WITHOUT_ENDPOINT = "Failed to borrow client from client pool or exception occurred " + "when sending to receiver."; - private static final String THRIFT_ERROR_FORMATTER_WITH_ENDPOINT = "Failed to borrow client from client pool or exception occurred " + "when sending to receiver %s:%s."; - private static final IoTDBConfig IOTDB_CONFIG = IoTDBDescriptor.getInstance().getConfig(); - private static final long PIPE_CONSENSUS_EVENT_ENQUEUE_TIMEOUT_IN_MS = IOTDB_CONFIG.getConnectionTimeoutInMS() / 6; - private final BlockingQueue retryEventQueue = new LinkedBlockingQueue<>(); - // We use enrichedEvent here to make use of EnrichedEvent.equalsInPipeConsensus private final BlockingQueue transferBuffer = new LinkedBlockingDeque<>(IOTDB_CONFIG.getPipeConsensusPipelineSize()); - private final AtomicBoolean isClosed = new AtomicBoolean(false); - private final int thisDataNodeId = IoTDBDescriptor.getInstance().getConfig().getDataNodeId(); - + private PipeConsensusConnectorMetrics pipeConsensusConnectorMetrics; + private String consensusPipeName; private int consensusGroupId; - private PipeConsensusSyncConnector retryConnector; - private IClientManager asyncTransferClientManager; - private PipeConsensusAsyncBatchReqBuilder tabletBatchBuilder; + private volatile long currentReplicateProgress = 0; + + @Override + public void validate(final PipeParameterValidator validator) throws Exception { + super.validate(validator); + // validate consensus pipe's parameters + final PipeParameters parameters = validator.getParameters(); + validator.validate( + args -> (boolean) args[0] || (boolean) args[1], + String.format( + "One of %s, %s must be specified in consensus pipe", + CONNECTOR_CONSENSUS_GROUP_ID_KEY, CONNECTOR_CONSENSUS_PIPE_NAME), + parameters.hasAttribute(CONNECTOR_CONSENSUS_GROUP_ID_KEY), + parameters.hasAttribute(CONNECTOR_CONSENSUS_PIPE_NAME)); + } @Override public void customize(PipeParameters parameters, PipeConnectorRuntimeConfiguration configuration) @@ -113,15 +123,16 @@ public void customize(PipeParameters parameters, PipeConnectorRuntimeConfigurati super.customize(parameters, configuration); // Get consensusGroupId from parameters passed by PipeConsensusImpl - if (!parameters.hasAttribute(PipeConnectorConstant.CONNECTOR_CONSENSUS_GROUP_ID_KEY)) { - throw new PipeException(CUSTOMIZE_EXCEPTION_MSG); - } - consensusGroupId = parameters.getInt(PipeConnectorConstant.CONNECTOR_CONSENSUS_GROUP_ID_KEY); + consensusGroupId = parameters.getInt(CONNECTOR_CONSENSUS_GROUP_ID_KEY); + // Get consensusPipeName from parameters passed by PipeConsensusImpl + consensusPipeName = parameters.getString(CONNECTOR_CONSENSUS_PIPE_NAME); // In PipeConsensus, one pipeConsensusTask corresponds to a pipeConsensusConnector. Thus, // `nodeUrls` here actually is a singletonList that contains one peer's TEndPoint. But here we // retain the implementation of list to cope with possible future expansion - retryConnector = new PipeConsensusSyncConnector(nodeUrls, consensusGroupId, thisDataNodeId); + retryConnector = + new PipeConsensusSyncConnector( + nodeUrls, consensusGroupId, thisDataNodeId, pipeConsensusConnectorMetrics); retryConnector.customize(parameters, configuration); asyncTransferClientManager = PipeConsensusClientMgrContainer.getInstance().getAsyncClientManager(); @@ -136,9 +147,17 @@ public void customize(PipeParameters parameters, PipeConnectorRuntimeConfigurati // currently, tablet batch is false by default in PipeConsensus; isTabletBatchModeEnabled = false; + + // initialize metric components + pipeConsensusConnectorMetrics = new PipeConsensusConnectorMetrics(this); + PipeConsensusSyncLagManager.getInstance(getConsensusGroupIdStr()) + .addConsensusPipeConnector(this); + MetricService.getInstance().addMetricSet(this.pipeConsensusConnectorMetrics); } - /** Add an event to transferBuffer, whose events will be asynchronizedly transfer to receiver. */ + /** + * Add an event to transferBuffer, whose events will be asynchronously transferred to receiver. + */ private boolean addEvent2Buffer(EnrichedEvent event) { try { if (LOGGER.isDebugEnabled()) { @@ -148,13 +167,21 @@ private boolean addEvent2Buffer(EnrichedEvent event) { event.getCommitId(), event); } + long currentTime = System.nanoTime(); boolean result = transferBuffer.offer( event, PIPE_CONSENSUS_EVENT_ENQUEUE_TIMEOUT_IN_MS, TimeUnit.MILLISECONDS); + long duration = System.nanoTime() - currentTime; + pipeConsensusConnectorMetrics.recordConnectorEnqueueTimer(duration); // add reference if (result) { event.increaseReferenceCount(PipeConsensusAsyncConnector.class.getName()); } + // if connector is closed when executing this method, need to clear this event's reference + // count to avoid unnecessarily pinning some resource such as WAL. + if (isClosed.get()) { + event.clearReferenceCount(PipeConsensusAsyncConnector.class.getName()); + } return result; } catch (InterruptedException e) { LOGGER.info("PipeConsensusConnector transferBuffer queue offer is interrupted.", e); @@ -182,6 +209,8 @@ public synchronized void removeEventFromBuffer(EnrichedEvent event) { current = iterator.next(); } iterator.remove(); + // update replicate progress + currentReplicateProgress = Math.max(currentReplicateProgress, event.getCommitId()); // decrease reference count event.decreaseReferenceCount(PipeConsensusAsyncConnector.class.getName(), true); } @@ -200,18 +229,18 @@ public void heartbeat() throws Exception { @Override public void transfer(TabletInsertionEvent tabletInsertionEvent) throws Exception { + syncTransferQueuedEventsIfNecessary(); + boolean enqueueResult = addEvent2Buffer((EnrichedEvent) tabletInsertionEvent); if (!enqueueResult) { throw new PipeException(ENQUEUE_EXCEPTION_MSG); } - - syncTransferQueuedEventsIfNecessary(); - // batch transfer tablets. if (isTabletBatchModeEnabled) { if (tabletBatchBuilder.onEvent(tabletInsertionEvent)) { final PipeConsensusTabletBatchEventHandler pipeConsensusTabletBatchEventHandler = - new PipeConsensusTabletBatchEventHandler(tabletBatchBuilder, this); + new PipeConsensusTabletBatchEventHandler( + tabletBatchBuilder, this, pipeConsensusConnectorMetrics); transfer(pipeConsensusTabletBatchEventHandler); @@ -252,7 +281,10 @@ public void transfer(TabletInsertionEvent tabletInsertionEvent) throws Exception insertNode, tCommitId, tConsensusGroupId, progressIndex, thisDataNodeId); final PipeConsensusTabletInsertNodeEventHandler pipeConsensusInsertNodeReqHandler = new PipeConsensusTabletInsertNodeEventHandler( - pipeInsertNodeTabletInsertionEvent, pipeConsensusTransferReq, this); + pipeInsertNodeTabletInsertionEvent, + pipeConsensusTransferReq, + this, + pipeConsensusConnectorMetrics); transfer(pipeConsensusInsertNodeReqHandler); } @@ -284,11 +316,6 @@ private void transfer( @Override public void transfer(TsFileInsertionEvent tsFileInsertionEvent) throws Exception { - boolean enqueueResult = addEvent2Buffer((EnrichedEvent) tsFileInsertionEvent); - if (!enqueueResult) { - throw new PipeException(ENQUEUE_EXCEPTION_MSG); - } - syncTransferQueuedEventsIfNecessary(); transferBatchedEventsIfNecessary(); @@ -299,6 +326,10 @@ public void transfer(TsFileInsertionEvent tsFileInsertionEvent) throws Exception return; } + boolean enqueueResult = addEvent2Buffer((EnrichedEvent) tsFileInsertionEvent); + if (!enqueueResult) { + throw new PipeException(ENQUEUE_EXCEPTION_MSG); + } final PipeTsFileInsertionEvent pipeTsFileInsertionEvent = (PipeTsFileInsertionEvent) tsFileInsertionEvent; TCommitId tCommitId = @@ -322,7 +353,12 @@ public void transfer(TsFileInsertionEvent tsFileInsertionEvent) throws Exception final PipeConsensusTsFileInsertionEventHandler pipeConsensusTsFileInsertionEventHandler = new PipeConsensusTsFileInsertionEventHandler( - pipeTsFileInsertionEvent, this, tCommitId, tConsensusGroupId, thisDataNodeId); + pipeTsFileInsertionEvent, + this, + tCommitId, + tConsensusGroupId, + thisDataNodeId, + pipeConsensusConnectorMetrics); transfer(pipeConsensusTsFileInsertionEventHandler); } catch (Exception e) { @@ -369,8 +405,9 @@ private void transferBatchedEventsIfNecessary() throws IOException { return; } - transfer(new PipeConsensusTabletBatchEventHandler(tabletBatchBuilder, this)); - + transfer( + new PipeConsensusTabletBatchEventHandler( + tabletBatchBuilder, this, pipeConsensusConnectorMetrics)); tabletBatchBuilder.onSuccess(); } @@ -381,7 +418,7 @@ private void transferBatchedEventsIfNecessary() throws IOException { * retry the {@link Event} and mark the {@link Event} as failure and stop the pipe if the * retry times exceeds the threshold. */ - private synchronized void syncTransferQueuedEventsIfNecessary() throws Exception { + private void syncTransferQueuedEventsIfNecessary() throws Exception { while (!retryEventQueue.isEmpty()) { synchronized (this) { if (isClosed.get() || retryEventQueue.isEmpty()) { @@ -443,7 +480,7 @@ public void addFailureEventToRetryQueue(final Event event) { return; } - retryEventQueue.offer(event); + boolean ignore = retryEventQueue.offer(event); if (LOGGER.isDebugEnabled()) { LOGGER.debug( "PipeConsensus-ConsensusGroup-{}: Event {} transfer failed, will be added to retry queue.", @@ -478,6 +515,13 @@ public synchronized void clearRetryEventsReferenceCount() { } } + public synchronized void clearTransferBufferReferenceCount() { + while (!transferBuffer.isEmpty()) { + final EnrichedEvent event = transferBuffer.poll(); + event.clearReferenceCount(PipeConsensusAsyncConnector.class.getName()); + } + } + private void logOnClientException( final AsyncPipeConsensusServiceClient client, final Exception e) { if (client == null) { @@ -506,13 +550,18 @@ public synchronized void close() { retryConnector.close(); clearRetryEventsReferenceCount(); + clearTransferBufferReferenceCount(); if (tabletBatchBuilder != null) { tabletBatchBuilder.close(); } + + PipeConsensusSyncLagManager.getInstance(getConsensusGroupIdStr()) + .removeConsensusPipeConnector(this); + MetricService.getInstance().removeMetricSet(this.pipeConsensusConnectorMetrics); } - //////////////////////////// TODO: APIs provided for metric framework //////////////////////////// + //////////////////////////// APIs provided for metric framework //////////////////////////// public int getTransferBufferSize() { return transferBuffer.size(); @@ -521,4 +570,24 @@ public int getTransferBufferSize() { public int getRetryBufferSize() { return retryEventQueue.size(); } + + @Override + public long getConsensusPipeCommitProgress() { + long creationTime = PipeDataNodeAgent.task().getPipeCreationTime(consensusPipeName); + String committerKey = + String.format("%s_%s_%s", consensusPipeName, consensusGroupId, creationTime); + return PipeEventCommitManager.getInstance().getGivenConsensusPipeCommitId(committerKey); + } + + @Override + public long getConsensusPipeReplicateProgress() { + return currentReplicateProgress; + } + + public String getConsensusGroupIdStr() { + ConsensusGroupId groupId = + ConsensusGroupId.Factory.create( + TConsensusGroupType.DataRegion.getValue(), consensusGroupId); + return groupId.toString(); + } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/pipeconsensus/PipeConsensusSyncConnector.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/pipeconsensus/PipeConsensusSyncConnector.java index e29d5f49398c5..c10c5bf93bfd3 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/pipeconsensus/PipeConsensusSyncConnector.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/pipeconsensus/PipeConsensusSyncConnector.java @@ -40,6 +40,7 @@ import org.apache.iotdb.db.pipe.connector.protocol.pipeconsensus.payload.request.PipeConsensusTsFilePieceWithModReq; import org.apache.iotdb.db.pipe.connector.protocol.pipeconsensus.payload.request.PipeConsensusTsFileSealReq; import org.apache.iotdb.db.pipe.connector.protocol.pipeconsensus.payload.request.PipeConsensusTsFileSealWithModReq; +import org.apache.iotdb.db.pipe.consensus.PipeConsensusConnectorMetrics; import org.apache.iotdb.db.pipe.event.common.heartbeat.PipeHeartbeatEvent; import org.apache.iotdb.db.pipe.event.common.tablet.PipeInsertNodeTabletInsertionEvent; import org.apache.iotdb.db.pipe.event.common.tsfile.PipeTsFileInsertionEvent; @@ -65,30 +66,24 @@ /** This connector is used for PipeConsensus to transfer queued event. */ public class PipeConsensusSyncConnector extends IoTDBConnector { - private static final Logger LOGGER = LoggerFactory.getLogger(PipeConsensusSyncConnector.class); - private static final String PIPE_CONSENSUS_SYNC_CONNECTION_FAILED_FORMAT = "PipeConsensus: syncClient connection to %s:%s failed when %s, because: %s"; - private static final String TABLET_INSERTION_NODE_SCENARIO = "transfer insertionNode tablet"; - private static final String TSFILE_SCENARIO = "transfer tsfile"; - private static final String TABLET_BATCH_SCENARIO = "transfer tablet batch"; - private final IClientManager syncRetryClientManager; - private final List peers; - private final int thisDataNodeId; - private final int consensusGroupId; - + private final PipeConsensusConnectorMetrics pipeConsensusConnectorMetrics; private PipeConsensusSyncBatchReqBuilder tabletBatchBuilder; public PipeConsensusSyncConnector( - List peers, int consensusGroupId, int thisDataNodeId) { + List peers, + int consensusGroupId, + int thisDataNodeId, + PipeConsensusConnectorMetrics pipeConsensusConnectorMetrics) { // In PipeConsensus, one pipeConsensusTask corresponds to a pipeConsensusConnector. Thus, // `peers` here actually is a singletonList that contains one peer's TEndPoint. But here we // retain the implementation of list to cope with possible future expansion @@ -97,6 +92,7 @@ public PipeConsensusSyncConnector( this.thisDataNodeId = thisDataNodeId; this.syncRetryClientManager = PipeConsensusClientMgrContainer.getInstance().getSyncClientManager(); + this.pipeConsensusConnectorMetrics = pipeConsensusConnectorMetrics; } @Override @@ -137,7 +133,10 @@ public void transfer(TabletInsertionEvent tabletInsertionEvent) throws Exception doTransfer(); } } else { + long startTime = System.nanoTime(); doTransferWrapper((PipeInsertNodeTabletInsertionEvent) tabletInsertionEvent); + long duration = System.nanoTime() - startTime; + pipeConsensusConnectorMetrics.recordRetryWALTransferTimer(duration); } } catch (Exception e) { throw new PipeConnectionException( @@ -154,12 +153,14 @@ public void transfer(TsFileInsertionEvent tsFileInsertionEvent) throws Exception // processor and will not change the event type like // org.apache.iotdb.db.pipe.connector.protocol.thrift.sync.IoTDBDataRegionSyncConnector try { + long startTime = System.nanoTime(); // In order to commit in order if (isTabletBatchModeEnabled && !tabletBatchBuilder.isEmpty()) { doTransfer(); } - doTransfer((PipeTsFileInsertionEvent) tsFileInsertionEvent); + long duration = System.nanoTime() - startTime; + pipeConsensusConnectorMetrics.recordRetryTsFileTransferTimer(duration); } catch (Exception e) { throw new PipeConnectionException( String.format( diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/pipeconsensus/handler/PipeConsensusTabletBatchEventHandler.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/pipeconsensus/handler/PipeConsensusTabletBatchEventHandler.java index 25816e68fa6ac..de9c7bec37d31 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/pipeconsensus/handler/PipeConsensusTabletBatchEventHandler.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/pipeconsensus/handler/PipeConsensusTabletBatchEventHandler.java @@ -27,6 +27,7 @@ import org.apache.iotdb.consensus.pipe.thrift.TPipeConsensusTransferResp; import org.apache.iotdb.db.pipe.connector.protocol.pipeconsensus.PipeConsensusAsyncConnector; import org.apache.iotdb.db.pipe.connector.protocol.pipeconsensus.payload.builder.PipeConsensusAsyncBatchReqBuilder; +import org.apache.iotdb.db.pipe.consensus.PipeConsensusConnectorMetrics; import org.apache.iotdb.pipe.api.event.Event; import org.apache.iotdb.pipe.api.exception.PipeException; import org.apache.iotdb.rpc.TSStatusCode; @@ -48,16 +49,19 @@ public class PipeConsensusTabletBatchEventHandler private final List events; private final TPipeConsensusBatchTransferReq req; private final PipeConsensusAsyncConnector connector; + private final PipeConsensusConnectorMetrics pipeConsensusConnectorMetrics; public PipeConsensusTabletBatchEventHandler( final PipeConsensusAsyncBatchReqBuilder batchBuilder, - final PipeConsensusAsyncConnector connector) + final PipeConsensusAsyncConnector connector, + final PipeConsensusConnectorMetrics pipeConsensusConnectorMetrics) throws IOException { // Deep copy to keep Ids' and events' reference requestCommitIds = batchBuilder.deepCopyRequestCommitIds(); events = batchBuilder.deepCopyEvents(); req = batchBuilder.toTPipeConsensusBatchTransferReq(); + this.pipeConsensusConnectorMetrics = pipeConsensusConnectorMetrics; this.connector = connector; } @@ -86,6 +90,7 @@ public void onComplete(final TPipeConsensusBatchTransferResp response) { .filter(tsStatus -> tsStatus.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) .forEach( tsStatus -> { + pipeConsensusConnectorMetrics.recordRetryCounter(); connector .statusHandler() .handle(tsStatus, tsStatus.getMessage(), events.toString()); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/pipeconsensus/handler/PipeConsensusTabletInsertNodeEventHandler.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/pipeconsensus/handler/PipeConsensusTabletInsertNodeEventHandler.java index 7b05fe297f279..cdd56d72cce5c 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/pipeconsensus/handler/PipeConsensusTabletInsertNodeEventHandler.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/pipeconsensus/handler/PipeConsensusTabletInsertNodeEventHandler.java @@ -23,6 +23,7 @@ import org.apache.iotdb.consensus.pipe.thrift.TPipeConsensusTransferReq; import org.apache.iotdb.consensus.pipe.thrift.TPipeConsensusTransferResp; import org.apache.iotdb.db.pipe.connector.protocol.pipeconsensus.PipeConsensusAsyncConnector; +import org.apache.iotdb.db.pipe.consensus.PipeConsensusConnectorMetrics; import org.apache.iotdb.db.pipe.event.common.tablet.PipeInsertNodeTabletInsertionEvent; import org.apache.thrift.TException; @@ -33,8 +34,9 @@ public class PipeConsensusTabletInsertNodeEventHandler public PipeConsensusTabletInsertNodeEventHandler( PipeInsertNodeTabletInsertionEvent event, TPipeConsensusTransferReq req, - PipeConsensusAsyncConnector connector) { - super(event, req, connector); + PipeConsensusAsyncConnector connector, + PipeConsensusConnectorMetrics metric) { + super(event, req, connector, metric); } @Override diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/pipeconsensus/handler/PipeConsensusTabletInsertionEventHandler.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/pipeconsensus/handler/PipeConsensusTabletInsertionEventHandler.java index 3e12b23f4633c..ae6a1e5334d20 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/pipeconsensus/handler/PipeConsensusTabletInsertionEventHandler.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/pipeconsensus/handler/PipeConsensusTabletInsertionEventHandler.java @@ -26,6 +26,7 @@ import org.apache.iotdb.consensus.pipe.thrift.TPipeConsensusTransferResp; import org.apache.iotdb.db.pipe.connector.protocol.pipeconsensus.PipeConsensusAsyncConnector; import org.apache.iotdb.db.pipe.connector.protocol.thrift.async.handler.PipeTransferTabletInsertionEventHandler; +import org.apache.iotdb.db.pipe.consensus.PipeConsensusConnectorMetrics; import org.apache.iotdb.pipe.api.event.dml.insertion.TabletInsertionEvent; import org.apache.iotdb.pipe.api.exception.PipeException; import org.apache.iotdb.rpc.TSStatusCode; @@ -46,13 +47,20 @@ public abstract class PipeConsensusTabletInsertionEventHandler { - - public PipeConsensusTabletRawEventHandler( - PipeRawTabletInsertionEvent event, - TPipeConsensusTransferReq req, - PipeConsensusAsyncConnector connector) { - super(event, req, connector); - } - - @Override - protected void doTransfer(AsyncPipeConsensusServiceClient client, TPipeConsensusTransferReq req) - throws TException { - client.pipeConsensusTransfer(req, this); - } -} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/pipeconsensus/handler/PipeConsensusTsFileInsertionEventHandler.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/pipeconsensus/handler/PipeConsensusTsFileInsertionEventHandler.java index 4ed42afc63c4f..bc8879946aa79 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/pipeconsensus/handler/PipeConsensusTsFileInsertionEventHandler.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/pipeconsensus/handler/PipeConsensusTsFileInsertionEventHandler.java @@ -31,6 +31,7 @@ import org.apache.iotdb.db.pipe.connector.protocol.pipeconsensus.payload.request.PipeConsensusTsFilePieceWithModReq; import org.apache.iotdb.db.pipe.connector.protocol.pipeconsensus.payload.request.PipeConsensusTsFileSealReq; import org.apache.iotdb.db.pipe.connector.protocol.pipeconsensus.payload.request.PipeConsensusTsFileSealWithModReq; +import org.apache.iotdb.db.pipe.consensus.PipeConsensusConnectorMetrics; import org.apache.iotdb.db.pipe.event.common.tsfile.PipeTsFileInsertionEvent; import org.apache.iotdb.rpc.TSStatusCode; @@ -74,12 +75,19 @@ public class PipeConsensusTsFileInsertionEventHandler private AsyncPipeConsensusServiceClient client; + private final PipeConsensusConnectorMetrics metric; + + private final long createTime; + + private long startTransferPieceTime; + public PipeConsensusTsFileInsertionEventHandler( final PipeTsFileInsertionEvent event, final PipeConsensusAsyncConnector connector, final TCommitId commitId, final TConsensusGroupId consensusGroupId, - final int thisDataNodeId) + final int thisDataNodeId, + final PipeConsensusConnectorMetrics metric) throws FileNotFoundException { this.event = event; this.connector = connector; @@ -102,15 +110,19 @@ public PipeConsensusTsFileInsertionEventHandler( : new RandomAccessFile(tsFile, "r"); isSealSignalSent = new AtomicBoolean(false); + + this.metric = metric; + this.createTime = System.nanoTime(); } public void transfer(final AsyncPipeConsensusServiceClient client) throws TException, IOException { + startTransferPieceTime = System.nanoTime(); + this.client = client; client.setShouldReturnSelf(false); final int readLength = reader.read(readBuffer); - if (readLength == -1) { if (currentFile == modFile) { currentFile = tsFile; @@ -217,6 +229,9 @@ public void onComplete(final TPipeConsensusTransferResp response) { client.setShouldReturnSelf(true); client.returnSelf(); } + + long duration = System.nanoTime() - createTime; + metric.recordConnectorTsFileTransferTimer(duration); } return; } @@ -245,6 +260,8 @@ public void onComplete(final TPipeConsensusTransferResp response) { .handle(status, response.getStatus().getMessage(), tsFile.getName()); } } + long duration = System.nanoTime() - startTransferPieceTime; + metric.recordConnectorTsFilePieceTransferTimer(duration); transfer(client); } catch (final Exception e) { @@ -269,6 +286,7 @@ public void onError(final Exception exception) { LOGGER.warn("Failed to close file reader when failed to transfer file.", e); } finally { connector.addFailureEventToRetryQueue(event); + metric.recordRetryCounter(); if (client != null) { client.setShouldReturnSelf(true); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/thrift/async/handler/PipeTransferTabletBatchEventHandler.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/thrift/async/handler/PipeTransferTabletBatchEventHandler.java index 038da9781538f..adc508e47e883 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/thrift/async/handler/PipeTransferTabletBatchEventHandler.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/thrift/async/handler/PipeTransferTabletBatchEventHandler.java @@ -51,7 +51,7 @@ public class PipeTransferTabletBatchEventHandler implements AsyncMethodCallback< private final List requestCommitIds; private final List events; - private final Map pipeName2BytesAccumulated; + private final Map, Long> pipeName2BytesAccumulated; private final TPipeTransferReq req; private final double reqCompressionRatio; @@ -78,9 +78,12 @@ public PipeTransferTabletBatchEventHandler( } public void transfer(final AsyncPipeDataTransferServiceClient client) throws TException { - for (final Map.Entry entry : pipeName2BytesAccumulated.entrySet()) { + for (final Map.Entry, Long> entry : pipeName2BytesAccumulated.entrySet()) { connector.rateLimitIfNeeded( - entry.getKey(), client.getEndPoint(), (long) (entry.getValue() * reqCompressionRatio)); + entry.getKey().getLeft(), + entry.getKey().getRight(), + client.getEndPoint(), + (long) (entry.getValue() * reqCompressionRatio)); } client.pipeTransfer(req, this); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/thrift/async/handler/PipeTransferTabletInsertionEventHandler.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/thrift/async/handler/PipeTransferTabletInsertionEventHandler.java index 2e54a8c7c0bee..40561121724bc 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/thrift/async/handler/PipeTransferTabletInsertionEventHandler.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/thrift/async/handler/PipeTransferTabletInsertionEventHandler.java @@ -46,26 +46,32 @@ public abstract class PipeTransferTabletInsertionEventHandler endPointAndBatch) { + private void doTransfer(final Pair endPointAndBatch) { final Pair clientAndStatus = clientManager.getClient(endPointAndBatch.getLeft()); final PipeEventBatch batchToTransfer = endPointAndBatch.getRight(); @@ -186,10 +186,11 @@ private void doTransfer(Pair endPointAndBatch) { final double compressionRatio = (double) compressedSize / uncompressedSize; - for (final Map.Entry entry : - batchToTransfer.getPipeName2BytesAccumulated().entrySet()) { + for (final Map.Entry, Long> entry : + batchToTransfer.getPipe2BytesAccumulated().entrySet()) { rateLimitIfNeeded( - entry.getKey(), + entry.getKey().getLeft(), + entry.getKey().getRight(), clientAndStatus.getLeft().getEndPoint(), (long) (entry.getValue() * compressionRatio)); } @@ -262,6 +263,7 @@ private void doTransfer( pipeInsertNodeTabletInsertionEvent.getByteBuffer())); rateLimitIfNeeded( pipeInsertNodeTabletInsertionEvent.getPipeName(), + pipeInsertNodeTabletInsertionEvent.getCreationTime(), clientAndStatus.getLeft().getEndPoint(), req.getBody().length); resp = clientAndStatus.getLeft().pipeTransfer(req); @@ -323,6 +325,7 @@ private void doTransfer(final PipeRawTabletInsertionEvent pipeRawTabletInsertion pipeRawTabletInsertionEvent.isAligned())); rateLimitIfNeeded( pipeRawTabletInsertionEvent.getPipeName(), + pipeRawTabletInsertionEvent.getCreationTime(), clientAndStatus.getLeft().getEndPoint(), req.getBody().length); resp = clientAndStatus.getLeft().pipeTransfer(req); @@ -370,6 +373,7 @@ private void doTransferWrapper(final PipeTsFileInsertionEvent pipeTsFileInsertio private void doTransfer(final PipeTsFileInsertionEvent pipeTsFileInsertionEvent) throws PipeException, IOException { final String pipeName = pipeTsFileInsertionEvent.getPipeName(); + final long creationTime = pipeTsFileInsertionEvent.getCreationTime(); final File tsFile = pipeTsFileInsertionEvent.getTsFile(); final File modFile = pipeTsFileInsertionEvent.getModFile(); final Pair clientAndStatus = clientManager.getClient(); @@ -377,8 +381,8 @@ private void doTransfer(final PipeTsFileInsertionEvent pipeTsFileInsertionEvent) // 1. Transfer tsFile, and mod file if exists and receiver's version >= 2 if (pipeTsFileInsertionEvent.isWithMod() && clientManager.supportModsIfIsDataNodeReceiver()) { - transferFilePieces(pipeName, modFile, clientAndStatus, true); - transferFilePieces(pipeName, tsFile, clientAndStatus, true); + transferFilePieces(pipeName, creationTime, modFile, clientAndStatus, true); + transferFilePieces(pipeName, creationTime, tsFile, clientAndStatus, true); // 2. Transfer file seal signal with mod, which means the file is transferred completely try { final TPipeTransferReq req = @@ -387,6 +391,7 @@ private void doTransfer(final PipeTsFileInsertionEvent pipeTsFileInsertionEvent) modFile.getName(), modFile.length(), tsFile.getName(), tsFile.length())); rateLimitIfNeeded( pipeTsFileInsertionEvent.getPipeName(), + pipeTsFileInsertionEvent.getCreationTime(), clientAndStatus.getLeft().getEndPoint(), req.getBody().length); resp = clientAndStatus.getLeft().pipeTransfer(req); @@ -398,7 +403,7 @@ private void doTransfer(final PipeTsFileInsertionEvent pipeTsFileInsertionEvent) e); } } else { - transferFilePieces(pipeName, tsFile, clientAndStatus, false); + transferFilePieces(pipeName, creationTime, tsFile, clientAndStatus, false); // 2. Transfer file seal signal without mod, which means the file is transferred completely try { final TPipeTransferReq req = @@ -406,6 +411,7 @@ private void doTransfer(final PipeTsFileInsertionEvent pipeTsFileInsertionEvent) PipeTransferTsFileSealReq.toTPipeTransferReq(tsFile.getName(), tsFile.length())); rateLimitIfNeeded( pipeTsFileInsertionEvent.getPipeName(), + pipeTsFileInsertionEvent.getCreationTime(), clientAndStatus.getLeft().getEndPoint(), req.getBody().length); resp = clientAndStatus.getLeft().pipeTransfer(req); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/thrift/sync/IoTDBSchemaRegionConnector.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/thrift/sync/IoTDBSchemaRegionConnector.java index 210bbec3dc0d1..93ec5e4ea439b 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/thrift/sync/IoTDBSchemaRegionConnector.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/thrift/sync/IoTDBSchemaRegionConnector.java @@ -89,15 +89,16 @@ private void doTransferWrapper(final PipeSchemaRegionSnapshotEvent pipeSchemaReg private void doTransfer(final PipeSchemaRegionSnapshotEvent snapshotEvent) throws PipeException, IOException { final String pipeName = snapshotEvent.getPipeName(); + final long creationTime = snapshotEvent.getCreationTime(); final File mTreeSnapshotFile = snapshotEvent.getMTreeSnapshotFile(); final File tagLogSnapshotFile = snapshotEvent.getTagLogSnapshotFile(); final Pair clientAndStatus = clientManager.getClient(); final TPipeTransferResp resp; // 1. Transfer mTreeSnapshotFile, and tLog file if exists - transferFilePieces(pipeName, mTreeSnapshotFile, clientAndStatus, true); + transferFilePieces(pipeName, creationTime, mTreeSnapshotFile, clientAndStatus, true); if (Objects.nonNull(tagLogSnapshotFile)) { - transferFilePieces(pipeName, tagLogSnapshotFile, clientAndStatus, true); + transferFilePieces(pipeName, creationTime, tagLogSnapshotFile, clientAndStatus, true); } // 2. Transfer file seal signal, which means the snapshots are transferred completely try { @@ -114,6 +115,7 @@ private void doTransfer(final PipeSchemaRegionSnapshotEvent snapshotEvent) snapshotEvent.toSealTypeString())); rateLimitIfNeeded( snapshotEvent.getPipeName(), + snapshotEvent.getCreationTime(), clientAndStatus.getLeft().getEndPoint(), req.getBody().length); resp = clientAndStatus.getLeft().pipeTransfer(req); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/writeback/WriteBackConnector.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/writeback/WriteBackConnector.java index ce49050943ffa..8a575922fa776 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/writeback/WriteBackConnector.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/connector/protocol/writeback/WriteBackConnector.java @@ -22,7 +22,7 @@ import org.apache.iotdb.common.rpc.thrift.TSStatus; import org.apache.iotdb.db.auth.AuthorityChecker; import org.apache.iotdb.db.conf.IoTDBDescriptor; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.connector.payload.evolvable.request.PipeTransferTabletBinaryReq; import org.apache.iotdb.db.pipe.connector.payload.evolvable.request.PipeTransferTabletInsertNodeReq; import org.apache.iotdb.db.pipe.connector.payload.evolvable.request.PipeTransferTabletRawReq; @@ -132,7 +132,7 @@ private void doTransfer( pipeInsertNodeTabletInsertionEvent.getInsertNodeViaCacheIfPossible(); if (Objects.isNull(insertNode)) { status = - PipeAgent.receiver() + PipeDataNodeAgent.receiver() .thrift() .receive( PipeTransferTabletBinaryReq.toTPipeTransferReq( diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/consensus/ConsensusPipeDataNodeDispatcher.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/consensus/ConsensusPipeDataNodeDispatcher.java index 82a6231cdd16a..9a95d8337886b 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/consensus/ConsensusPipeDataNodeDispatcher.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/consensus/ConsensusPipeDataNodeDispatcher.java @@ -25,7 +25,7 @@ import org.apache.iotdb.confignode.rpc.thrift.TCreatePipeReq; import org.apache.iotdb.consensus.pipe.consensuspipe.ConsensusPipeDispatcher; import org.apache.iotdb.consensus.pipe.consensuspipe.ConsensusPipeName; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.protocol.client.ConfigNodeClient; import org.apache.iotdb.db.protocol.client.ConfigNodeClientManager; import org.apache.iotdb.db.protocol.client.ConfigNodeInfo; @@ -116,6 +116,6 @@ public void dropPipe(ConsensusPipeName pipeName) throws Exception { throw new PipeException("Failed to drop consensus pipe", e); } // Release corresponding receiver's resource - PipeAgent.receiver().pipeConsensus().handleDropPipeConsensusTask(pipeName); + PipeDataNodeAgent.receiver().pipeConsensus().handleDropPipeConsensusTask(pipeName); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/consensus/ConsensusPipeDataNodeRuntimeAgentGuardian.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/consensus/ConsensusPipeDataNodeRuntimeAgentGuardian.java index 096cfdc6985e1..2f3cf532fc33a 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/consensus/ConsensusPipeDataNodeRuntimeAgentGuardian.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/consensus/ConsensusPipeDataNodeRuntimeAgentGuardian.java @@ -20,7 +20,7 @@ package org.apache.iotdb.db.pipe.consensus; import org.apache.iotdb.consensus.pipe.consensuspipe.ConsensusPipeGuardian; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -37,7 +37,7 @@ public synchronized void start(String id, Runnable guardJob, long intervalInSeco "Registering periodical job {} with interval in seconds {}.", id, intervalInSeconds); this.registered = true; - PipeAgent.runtime().registerPeriodicalJob(id, guardJob, intervalInSeconds); + PipeDataNodeAgent.runtime().registerPeriodicalJob(id, guardJob, intervalInSeconds); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/consensus/PipeConsensusConnectorMetrics.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/consensus/PipeConsensusConnectorMetrics.java new file mode 100644 index 0000000000000..7950fd76744b8 --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/consensus/PipeConsensusConnectorMetrics.java @@ -0,0 +1,290 @@ +/* + * 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.iotdb.db.pipe.consensus; + +import org.apache.iotdb.commons.service.metric.enums.Metric; +import org.apache.iotdb.commons.service.metric.enums.Tag; +import org.apache.iotdb.db.pipe.connector.protocol.pipeconsensus.PipeConsensusAsyncConnector; +import org.apache.iotdb.metrics.AbstractMetricService; +import org.apache.iotdb.metrics.impl.DoNothingMetricManager; +import org.apache.iotdb.metrics.metricsets.IMetricSet; +import org.apache.iotdb.metrics.type.Counter; +import org.apache.iotdb.metrics.type.Timer; +import org.apache.iotdb.metrics.utils.MetricLevel; +import org.apache.iotdb.metrics.utils.MetricType; + +public class PipeConsensusConnectorMetrics implements IMetricSet { + private final PipeConsensusAsyncConnector pipeConsensusAsyncConnector; + + private Timer connectorEnqueueTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + private Timer connectorWALTransferTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + private Timer connectorTsFileTransferTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + private Timer connectorTsFilePieceTransferTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + private Timer retryWALTransferTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + private Timer retryTsFileTransferTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + private Counter retryCounter = DoNothingMetricManager.DO_NOTHING_COUNTER; + + private static final String CONNECTOR = "pipeConsensusAsyncConnector"; + + public PipeConsensusConnectorMetrics(PipeConsensusAsyncConnector pipeConsensusAsyncConnector) { + this.pipeConsensusAsyncConnector = pipeConsensusAsyncConnector; + } + + public void recordConnectorEnqueueTimer(long costTimeInNanos) { + connectorEnqueueTimer.updateNanos(costTimeInNanos); + } + + public void recordConnectorWalTransferTimer(long costTimeInNanos) { + connectorWALTransferTimer.updateNanos(costTimeInNanos); + } + + public void recordConnectorTsFileTransferTimer(long costTimeInNanos) { + connectorTsFileTransferTimer.updateNanos(costTimeInNanos); + } + + public void recordConnectorTsFilePieceTransferTimer(long costTimeInNanos) { + connectorTsFilePieceTransferTimer.updateNanos(costTimeInNanos); + } + + public void recordRetryWALTransferTimer(long costTimeInNanos) { + retryWALTransferTimer.updateNanos(costTimeInNanos); + } + + public void recordRetryTsFileTransferTimer(long costTimeInNanos) { + retryTsFileTransferTimer.updateNanos(costTimeInNanos); + } + + public void recordRetryCounter() { + retryCounter.inc(); + } + + @Override + public void bindTo(AbstractMetricService metricService) { + bindCounter(metricService); + bindAutoGauge(metricService); + bindTimer(metricService); + } + + @Override + public void unbindFrom(AbstractMetricService metricService) { + unbindCounter(metricService); + unbindAutoGauge(metricService); + unbindTimer(metricService); + } + + private void bindCounter(AbstractMetricService metricService) { + metricService.getOrCreateCounter( + Metric.PIPE_RETRY_SEND_EVENT.toString(), + MetricLevel.IMPORTANT, + Tag.NAME.toString(), + CONNECTOR, + Tag.REGION.toString(), + pipeConsensusAsyncConnector.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "pipeConsensusRetryCount"); + } + + private void bindAutoGauge(AbstractMetricService metricService) { + metricService.createAutoGauge( + Metric.PIPE_SEND_EVENT.toString(), + MetricLevel.IMPORTANT, + pipeConsensusAsyncConnector, + PipeConsensusAsyncConnector::getTransferBufferSize, + Tag.NAME.toString(), + CONNECTOR, + Tag.REGION.toString(), + pipeConsensusAsyncConnector.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "transferBufferSize"); + metricService.createAutoGauge( + Metric.PIPE_SEND_EVENT.toString(), + MetricLevel.IMPORTANT, + pipeConsensusAsyncConnector, + PipeConsensusAsyncConnector::getRetryBufferSize, + Tag.NAME.toString(), + CONNECTOR, + Tag.REGION.toString(), + pipeConsensusAsyncConnector.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "retryBufferSize"); + } + + private void bindTimer(AbstractMetricService metricService) { + connectorEnqueueTimer = + metricService.getOrCreateTimer( + Metric.PIPE_SEND_EVENT.toString(), + MetricLevel.IMPORTANT, + Tag.NAME.toString(), + CONNECTOR, + Tag.TYPE.toString(), + "connectorEnqueue", + Tag.REGION.toString(), + pipeConsensusAsyncConnector.getConsensusGroupIdStr()); + connectorTsFilePieceTransferTimer = + metricService.getOrCreateTimer( + Metric.PIPE_SEND_EVENT.toString(), + MetricLevel.IMPORTANT, + Tag.NAME.toString(), + CONNECTOR, + Tag.TYPE.toString(), + "connectorTsFilePieceTransfer", + Tag.REGION.toString(), + pipeConsensusAsyncConnector.getConsensusGroupIdStr()); + connectorTsFileTransferTimer = + metricService.getOrCreateTimer( + Metric.PIPE_SEND_EVENT.toString(), + MetricLevel.IMPORTANT, + Tag.NAME.toString(), + CONNECTOR, + Tag.TYPE.toString(), + "connectorTsFileTransfer", + Tag.REGION.toString(), + pipeConsensusAsyncConnector.getConsensusGroupIdStr()); + connectorWALTransferTimer = + metricService.getOrCreateTimer( + Metric.PIPE_SEND_EVENT.toString(), + MetricLevel.IMPORTANT, + Tag.NAME.toString(), + CONNECTOR, + Tag.TYPE.toString(), + "connectorWALTransfer", + Tag.REGION.toString(), + pipeConsensusAsyncConnector.getConsensusGroupIdStr()); + retryWALTransferTimer = + metricService.getOrCreateTimer( + Metric.PIPE_RETRY_SEND_EVENT.toString(), + MetricLevel.IMPORTANT, + Tag.NAME.toString(), + CONNECTOR, + Tag.TYPE.toString(), + "retryWALTransfer", + Tag.REGION.toString(), + pipeConsensusAsyncConnector.getConsensusGroupIdStr()); + retryTsFileTransferTimer = + metricService.getOrCreateTimer( + Metric.PIPE_RETRY_SEND_EVENT.toString(), + MetricLevel.IMPORTANT, + Tag.NAME.toString(), + CONNECTOR, + Tag.TYPE.toString(), + "retryTsFileTransfer", + Tag.REGION.toString(), + pipeConsensusAsyncConnector.getConsensusGroupIdStr()); + } + + private void unbindCounter(AbstractMetricService metricService) { + retryCounter = DoNothingMetricManager.DO_NOTHING_COUNTER; + + metricService.remove( + MetricType.COUNTER, + Metric.PIPE_RETRY_SEND_EVENT.toString(), + Tag.NAME.toString(), + CONNECTOR, + Tag.REGION.toString(), + pipeConsensusAsyncConnector.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "pipeConsensusRetryCount"); + } + + private void unbindAutoGauge(AbstractMetricService metricService) { + metricService.remove( + MetricType.AUTO_GAUGE, + Metric.PIPE_SEND_EVENT.toString(), + Tag.NAME.toString(), + CONNECTOR, + Tag.REGION.toString(), + pipeConsensusAsyncConnector.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "transferBufferSize"); + metricService.remove( + MetricType.AUTO_GAUGE, + Metric.PIPE_SEND_EVENT.toString(), + Tag.NAME.toString(), + CONNECTOR, + Tag.REGION.toString(), + pipeConsensusAsyncConnector.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "retryBufferSize"); + } + + private void unbindTimer(AbstractMetricService metricService) { + connectorEnqueueTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + connectorWALTransferTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + connectorTsFileTransferTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + connectorTsFilePieceTransferTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + retryWALTransferTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + retryTsFileTransferTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + + metricService.remove( + MetricType.TIMER, + Metric.PIPE_SEND_EVENT.toString(), + Tag.NAME.toString(), + CONNECTOR, + Tag.TYPE.toString(), + "connectorTsFileTransfer", + Tag.REGION.toString(), + pipeConsensusAsyncConnector.getConsensusGroupIdStr()); + metricService.remove( + MetricType.TIMER, + Metric.PIPE_SEND_EVENT.toString(), + Tag.NAME.toString(), + CONNECTOR, + Tag.TYPE.toString(), + "connectorTsFilePieceTransfer", + Tag.REGION.toString(), + pipeConsensusAsyncConnector.getConsensusGroupIdStr()); + metricService.remove( + MetricType.TIMER, + Metric.PIPE_SEND_EVENT.toString(), + Tag.NAME.toString(), + CONNECTOR, + Tag.TYPE.toString(), + "connectorTsFileTransfer", + Tag.REGION.toString(), + pipeConsensusAsyncConnector.getConsensusGroupIdStr()); + metricService.remove( + MetricType.TIMER, + Metric.PIPE_SEND_EVENT.toString(), + Tag.NAME.toString(), + CONNECTOR, + Tag.TYPE.toString(), + "connectorWALTransfer", + Tag.REGION.toString(), + pipeConsensusAsyncConnector.getConsensusGroupIdStr()); + metricService.remove( + MetricType.TIMER, + Metric.PIPE_RETRY_SEND_EVENT.toString(), + Tag.NAME.toString(), + CONNECTOR, + Tag.TYPE.toString(), + "retryWALTransfer", + Tag.REGION.toString(), + pipeConsensusAsyncConnector.getConsensusGroupIdStr()); + metricService.remove( + MetricType.TIMER, + Metric.PIPE_RETRY_SEND_EVENT.toString(), + Tag.NAME.toString(), + CONNECTOR, + Tag.TYPE.toString(), + "retryTsFileTransfer", + Tag.REGION.toString(), + pipeConsensusAsyncConnector.getConsensusGroupIdStr()); + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/consensus/PipeConsensusReceiverMetrics.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/consensus/PipeConsensusReceiverMetrics.java new file mode 100644 index 0000000000000..58d587d8b8d20 --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/consensus/PipeConsensusReceiverMetrics.java @@ -0,0 +1,384 @@ +/* + * 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.iotdb.db.pipe.consensus; + +import org.apache.iotdb.commons.service.metric.enums.Metric; +import org.apache.iotdb.commons.service.metric.enums.Tag; +import org.apache.iotdb.db.pipe.receiver.protocol.pipeconsensus.PipeConsensusReceiver; +import org.apache.iotdb.metrics.AbstractMetricService; +import org.apache.iotdb.metrics.impl.DoNothingMetricManager; +import org.apache.iotdb.metrics.metricsets.IMetricSet; +import org.apache.iotdb.metrics.type.Timer; +import org.apache.iotdb.metrics.utils.MetricLevel; +import org.apache.iotdb.metrics.utils.MetricType; + +public class PipeConsensusReceiverMetrics implements IMetricSet { + private final PipeConsensusReceiver pipeConsensusReceiver; + + private Timer tsFilePieceWriteTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + private Timer tsFilePiecePreCheckTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + private Timer tsFileSealLoadTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + private Timer tsFileSealPreCheckTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + private Timer borrowTsFileWriterTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + private Timer acquireExecutorLockTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + private Timer dispatchWaitingTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + private Timer receiveWALTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + private Timer receiveTsFileTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + private Timer receiveEventTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + + private static final String RECEIVER = "pipeConsensusReceiver"; + + public PipeConsensusReceiverMetrics(PipeConsensusReceiver pipeConsensusReceiver) { + this.pipeConsensusReceiver = pipeConsensusReceiver; + } + + public void recordTsFilePieceWriteTime(long costTimeInNanos) { + tsFilePieceWriteTimer.updateNanos(costTimeInNanos); + } + + public void recordTsFilePiecePreCheckTime(long costTimeInNanos) { + tsFilePiecePreCheckTimer.updateNanos(costTimeInNanos); + } + + public void recordTsFileSealLoadTimer(long costTimeInNanos) { + tsFileSealLoadTimer.updateNanos(costTimeInNanos); + } + + public void recordTsFileSealPreCheckTimer(long costTimeInNanos) { + tsFileSealPreCheckTimer.updateNanos(costTimeInNanos); + } + + public void recordBorrowTsFileWriterTimer(long costTimeInNanos) { + borrowTsFileWriterTimer.updateNanos(costTimeInNanos); + } + + public void recordAcquireExecutorLockTimer(long costTimeInNanos) { + acquireExecutorLockTimer.updateNanos(costTimeInNanos); + } + + public void recordDispatchWaitingTimer(long costTimeInNanos) { + dispatchWaitingTimer.updateNanos(costTimeInNanos); + } + + public void recordReceiveWALTimer(long costTimeInNanos) { + receiveWALTimer.updateNanos(costTimeInNanos); + } + + public void recordReceiveTsFileTimer(long costTimeInNanos) { + receiveTsFileTimer.updateNanos(costTimeInNanos); + } + + public void recordReceiveEventTimer(long costTimeInNanos) { + receiveEventTimer.updateNanos(costTimeInNanos); + } + + @Override + public void bindTo(AbstractMetricService metricService) { + bindAutoGauge(metricService); + bindStageTimer(metricService); + bindReceiveTimer(metricService); + } + + @Override + public void unbindFrom(AbstractMetricService metricService) { + unbindAutoGauge(metricService); + unbindStageTimer(metricService); + unbindReceiveTimer(metricService); + } + + public void bindAutoGauge(AbstractMetricService metricService) { + metricService.createAutoGauge( + Metric.PIPE_RECEIVE_EVENT.toString(), + MetricLevel.IMPORTANT, + pipeConsensusReceiver, + PipeConsensusReceiver::getReceiveBufferSize, + Tag.NAME.toString(), + RECEIVER, + Tag.REGION.toString(), + pipeConsensusReceiver.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "receiveBufferSize"); + metricService.createAutoGauge( + Metric.PIPE_RECEIVE_EVENT.toString(), + MetricLevel.IMPORTANT, + pipeConsensusReceiver, + PipeConsensusReceiver::getWALEventCount, + Tag.NAME.toString(), + RECEIVER, + Tag.REGION.toString(), + pipeConsensusReceiver.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "WALEventCount"); + metricService.createAutoGauge( + Metric.PIPE_RECEIVE_EVENT.toString(), + MetricLevel.IMPORTANT, + pipeConsensusReceiver, + PipeConsensusReceiver::getTsFileEventCount, + Tag.NAME.toString(), + RECEIVER, + Tag.REGION.toString(), + pipeConsensusReceiver.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "tsFileEventCount"); + } + + public void bindStageTimer(AbstractMetricService metricService) { + tsFilePieceWriteTimer = + metricService.getOrCreateTimer( + Metric.STAGE.toString(), + MetricLevel.IMPORTANT, + Tag.NAME.toString(), + RECEIVER, + Tag.REGION.toString(), + pipeConsensusReceiver.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "tsFilePieceWrite"); + tsFilePiecePreCheckTimer = + metricService.getOrCreateTimer( + Metric.STAGE.toString(), + MetricLevel.IMPORTANT, + Tag.NAME.toString(), + RECEIVER, + Tag.REGION.toString(), + pipeConsensusReceiver.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "tsFilePiecePreCheck"); + tsFileSealLoadTimer = + metricService.getOrCreateTimer( + Metric.STAGE.toString(), + MetricLevel.IMPORTANT, + Tag.NAME.toString(), + RECEIVER, + Tag.REGION.toString(), + pipeConsensusReceiver.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "tsFileSealLoad"); + tsFileSealPreCheckTimer = + metricService.getOrCreateTimer( + Metric.STAGE.toString(), + MetricLevel.IMPORTANT, + Tag.NAME.toString(), + RECEIVER, + Tag.REGION.toString(), + pipeConsensusReceiver.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "tsFileSealPreCheck"); + borrowTsFileWriterTimer = + metricService.getOrCreateTimer( + Metric.STAGE.toString(), + MetricLevel.IMPORTANT, + Tag.NAME.toString(), + RECEIVER, + Tag.REGION.toString(), + pipeConsensusReceiver.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "borrowTsFileWriter"); + acquireExecutorLockTimer = + metricService.getOrCreateTimer( + Metric.STAGE.toString(), + MetricLevel.IMPORTANT, + Tag.NAME.toString(), + RECEIVER, + Tag.REGION.toString(), + pipeConsensusReceiver.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "acquireExecutorLock"); + dispatchWaitingTimer = + metricService.getOrCreateTimer( + Metric.STAGE.toString(), + MetricLevel.IMPORTANT, + Tag.NAME.toString(), + RECEIVER, + Tag.REGION.toString(), + pipeConsensusReceiver.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "dispatchWaiting"); + } + + public void bindReceiveTimer(AbstractMetricService metricService) { + receiveEventTimer = + metricService.getOrCreateTimer( + Metric.PIPE_RECEIVE_EVENT.toString(), + MetricLevel.IMPORTANT, + Tag.NAME.toString(), + RECEIVER, + Tag.REGION.toString(), + pipeConsensusReceiver.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "receiveEvent"); + receiveWALTimer = + metricService.getOrCreateTimer( + Metric.PIPE_RECEIVE_EVENT.toString(), + MetricLevel.IMPORTANT, + Tag.NAME.toString(), + RECEIVER, + Tag.REGION.toString(), + pipeConsensusReceiver.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "receiveWALEvent"); + receiveTsFileTimer = + metricService.getOrCreateTimer( + Metric.PIPE_RECEIVE_EVENT.toString(), + MetricLevel.IMPORTANT, + Tag.NAME.toString(), + RECEIVER, + Tag.REGION.toString(), + pipeConsensusReceiver.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "receiveTsFileEvent"); + } + + public void unbindAutoGauge(AbstractMetricService metricService) { + metricService.remove( + MetricType.AUTO_GAUGE, + Metric.PIPE_RECEIVE_EVENT.toString(), + Tag.NAME.toString(), + RECEIVER, + Tag.REGION.toString(), + pipeConsensusReceiver.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "receiveBufferSize"); + metricService.remove( + MetricType.AUTO_GAUGE, + Metric.PIPE_RECEIVE_EVENT.toString(), + Tag.NAME.toString(), + RECEIVER, + Tag.REGION.toString(), + pipeConsensusReceiver.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "WALEventCount"); + metricService.remove( + MetricType.AUTO_GAUGE, + Metric.PIPE_RECEIVE_EVENT.toString(), + Tag.NAME.toString(), + RECEIVER, + Tag.REGION.toString(), + pipeConsensusReceiver.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "tsFileEventCount"); + } + + public void unbindStageTimer(AbstractMetricService metricService) { + tsFilePieceWriteTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + tsFilePiecePreCheckTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + tsFileSealLoadTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + tsFileSealPreCheckTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + borrowTsFileWriterTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + acquireExecutorLockTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + dispatchWaitingTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + metricService.remove( + MetricType.TIMER, + Metric.STAGE.toString(), + Tag.NAME.toString(), + RECEIVER, + Tag.REGION.toString(), + pipeConsensusReceiver.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "tsFilePieceWrite"); + metricService.remove( + MetricType.TIMER, + Metric.STAGE.toString(), + Tag.NAME.toString(), + RECEIVER, + Tag.REGION.toString(), + pipeConsensusReceiver.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "tsFilePiecePreCheck"); + metricService.remove( + MetricType.TIMER, + Metric.STAGE.toString(), + Tag.NAME.toString(), + RECEIVER, + Tag.REGION.toString(), + pipeConsensusReceiver.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "tsFileSealLoad"); + metricService.remove( + MetricType.TIMER, + Metric.STAGE.toString(), + Tag.NAME.toString(), + RECEIVER, + Tag.REGION.toString(), + pipeConsensusReceiver.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "tsFileSealPreCheck"); + metricService.remove( + MetricType.TIMER, + Metric.STAGE.toString(), + Tag.NAME.toString(), + RECEIVER, + Tag.REGION.toString(), + pipeConsensusReceiver.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "borrowTsFileWriter"); + metricService.remove( + MetricType.TIMER, + Metric.STAGE.toString(), + Tag.NAME.toString(), + RECEIVER, + Tag.REGION.toString(), + pipeConsensusReceiver.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "acquireExecutorLock"); + metricService.remove( + MetricType.TIMER, + Metric.STAGE.toString(), + Tag.NAME.toString(), + RECEIVER, + Tag.REGION.toString(), + pipeConsensusReceiver.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "dispatchWaiting"); + } + + public void unbindReceiveTimer(AbstractMetricService metricService) { + receiveWALTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + receiveTsFileTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + receiveEventTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + + metricService.remove( + MetricType.TIMER, + Metric.PIPE_RECEIVE_EVENT.toString(), + Tag.NAME.toString(), + RECEIVER, + Tag.REGION.toString(), + pipeConsensusReceiver.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "receiveWALEvent"); + metricService.remove( + MetricType.TIMER, + Metric.PIPE_RECEIVE_EVENT.toString(), + Tag.NAME.toString(), + RECEIVER, + Tag.REGION.toString(), + pipeConsensusReceiver.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "receiveTsFileEvent"); + metricService.remove( + MetricType.TIMER, + Metric.PIPE_RECEIVE_EVENT.toString(), + Tag.NAME.toString(), + RECEIVER, + Tag.REGION.toString(), + pipeConsensusReceiver.getConsensusGroupIdStr(), + Tag.TYPE.toString(), + "receiveEvent"); + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/consensus/PipeConsensusSubtaskExecutor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/consensus/PipeConsensusSubtaskExecutor.java index 5d99c5038fc67..175a95992cfa9 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/consensus/PipeConsensusSubtaskExecutor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/consensus/PipeConsensusSubtaskExecutor.java @@ -20,9 +20,9 @@ import org.apache.iotdb.commons.concurrent.ThreadName; import org.apache.iotdb.commons.pipe.config.PipeConfig; -import org.apache.iotdb.commons.pipe.execution.executor.PipeSubtaskExecutor; +import org.apache.iotdb.db.pipe.execution.PipeConnectorSubtaskExecutor; -public class PipeConsensusSubtaskExecutor extends PipeSubtaskExecutor { +public class PipeConsensusSubtaskExecutor extends PipeConnectorSubtaskExecutor { public PipeConsensusSubtaskExecutor() { super( diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/consensus/ProgressIndexDataNodeManager.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/consensus/ProgressIndexDataNodeManager.java index 3f7cf9239db69..371349560b47f 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/consensus/ProgressIndexDataNodeManager.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/consensus/ProgressIndexDataNodeManager.java @@ -29,7 +29,7 @@ import org.apache.iotdb.consensus.pipe.consensuspipe.ConsensusPipeName; import org.apache.iotdb.consensus.pipe.consensuspipe.ProgressIndexManager; import org.apache.iotdb.db.conf.IoTDBDescriptor; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.storageengine.StorageEngine; import org.apache.iotdb.db.storageengine.dataregion.tsfile.TsFileManager; import org.apache.iotdb.db.storageengine.dataregion.tsfile.TsFileResource; @@ -108,7 +108,7 @@ private ProgressIndex extractLocalSimpleProgressIndex(ProgressIndex progressInde @Override public ProgressIndex getProgressIndex(ConsensusPipeName consensusPipeName) { - return PipeAgent.task() + return PipeDataNodeAgent.task() .getPipeTaskProgressIndex( consensusPipeName.toString(), consensusPipeName.getConsensusGroupId().getId()); } @@ -118,7 +118,7 @@ public ProgressIndex assignProgressIndex(ConsensusGroupId consensusGroupId) { return groupId2MaxProgressIndex .computeIfAbsent(consensusGroupId, o -> MinimumProgressIndex.INSTANCE) .updateToMinimumEqualOrIsAfterProgressIndex( - PipeAgent.runtime().assignProgressIndexForPipeConsensus()); + PipeDataNodeAgent.runtime().assignProgressIndexForPipeConsensus()); } @Override diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/UserDefinedEnrichedEvent.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/UserDefinedEnrichedEvent.java index ff6e34fffcf09..82829a4542bec 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/UserDefinedEnrichedEvent.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/UserDefinedEnrichedEvent.java @@ -31,7 +31,7 @@ public class UserDefinedEnrichedEvent extends EnrichedEvent { private final UserDefinedEvent userDefinedEvent; private final EnrichedEvent enrichedEvent; - public static Event maybeOf(Event event) { + public static Event maybeOf(final Event event) { return event instanceof UserDefinedEvent && ((UserDefinedEvent) event).getSourceEvent() instanceof EnrichedEvent ? new UserDefinedEnrichedEvent( @@ -39,9 +39,11 @@ public static Event maybeOf(Event event) { : event; } - private UserDefinedEnrichedEvent(UserDefinedEvent userDefinedEvent, EnrichedEvent enrichedEvent) { + private UserDefinedEnrichedEvent( + final UserDefinedEvent userDefinedEvent, final EnrichedEvent enrichedEvent) { super( enrichedEvent.getPipeName(), + enrichedEvent.getCreationTime(), enrichedEvent.getPipeTaskMeta(), enrichedEvent.getPipePattern(), enrichedEvent.getStartTime(), @@ -55,12 +57,12 @@ public UserDefinedEvent getUserDefinedEvent() { } @Override - public boolean internallyIncreaseResourceReferenceCount(String holderMessage) { + public boolean internallyIncreaseResourceReferenceCount(final String holderMessage) { return enrichedEvent.internallyIncreaseResourceReferenceCount(holderMessage); } @Override - public boolean internallyDecreaseResourceReferenceCount(String holderMessage) { + public boolean internallyDecreaseResourceReferenceCount(final String holderMessage) { return enrichedEvent.internallyDecreaseResourceReferenceCount(holderMessage); } @@ -71,13 +73,14 @@ public ProgressIndex getProgressIndex() { @Override public EnrichedEvent shallowCopySelfAndBindPipeTaskMetaForProgressReport( - String pipeName, - PipeTaskMeta pipeTaskMeta, - PipePattern pattern, - long startTime, - long endTime) { + final String pipeName, + final long creationTime, + final PipeTaskMeta pipeTaskMeta, + final PipePattern pattern, + final long startTime, + final long endTime) { return enrichedEvent.shallowCopySelfAndBindPipeTaskMetaForProgressReport( - pipeName, pipeTaskMeta, pattern, startTime, endTime); + pipeName, creationTime, pipeTaskMeta, pattern, startTime, endTime); } @Override @@ -89,4 +92,9 @@ public boolean isGeneratedByPipe() { public boolean mayEventTimeOverlappedWithTimeRange() { return enrichedEvent.mayEventTimeOverlappedWithTimeRange(); } + + @Override + public boolean mayEventPathsOverlappedWithPattern() { + return enrichedEvent.mayEventPathsOverlappedWithPattern(); + } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/heartbeat/PipeHeartbeatEvent.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/heartbeat/PipeHeartbeatEvent.java index 9738f86a5dd40..d3830b6dcf020 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/heartbeat/PipeHeartbeatEvent.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/heartbeat/PipeHeartbeatEvent.java @@ -38,7 +38,6 @@ public class PipeHeartbeatEvent extends EnrichedEvent { private static final Logger LOGGER = LoggerFactory.getLogger(PipeHeartbeatEvent.class); private final String dataRegionId; - private String pipeName; private long timePublished; private long timeAssigned; @@ -60,18 +59,19 @@ public class PipeHeartbeatEvent extends EnrichedEvent { private final boolean shouldPrintMessage; public PipeHeartbeatEvent(final String dataRegionId, final boolean shouldPrintMessage) { - super(null, null, null, Long.MIN_VALUE, Long.MAX_VALUE); + super(null, 0, null, null, Long.MIN_VALUE, Long.MAX_VALUE); this.dataRegionId = dataRegionId; this.shouldPrintMessage = shouldPrintMessage; } public PipeHeartbeatEvent( final String pipeName, + final long creationTime, final PipeTaskMeta pipeTaskMeta, final String dataRegionId, final long timePublished, final boolean shouldPrintMessage) { - super(pipeName, pipeTaskMeta, null, Long.MIN_VALUE, Long.MAX_VALUE); + super(pipeName, creationTime, pipeTaskMeta, null, Long.MIN_VALUE, Long.MAX_VALUE); this.dataRegionId = dataRegionId; this.timePublished = timePublished; this.shouldPrintMessage = shouldPrintMessage; @@ -100,6 +100,7 @@ public ProgressIndex getProgressIndex() { @Override public EnrichedEvent shallowCopySelfAndBindPipeTaskMetaForProgressReport( final String pipeName, + final long creationTime, final PipeTaskMeta pipeTaskMeta, final PipePattern pattern, final long startTime, @@ -107,7 +108,7 @@ public EnrichedEvent shallowCopySelfAndBindPipeTaskMetaForProgressReport( // Should record PipeTaskMeta, for sometimes HeartbeatEvents should report exceptions. // Here we ignore parameters `pattern`, `startTime`, and `endTime`. return new PipeHeartbeatEvent( - pipeName, pipeTaskMeta, dataRegionId, timePublished, shouldPrintMessage); + pipeName, creationTime, pipeTaskMeta, dataRegionId, timePublished, shouldPrintMessage); } @Override @@ -120,6 +121,11 @@ public boolean mayEventTimeOverlappedWithTimeRange() { return true; } + @Override + public boolean mayEventPathsOverlappedWithPattern() { + return true; + } + /////////////////////////////// Whether to print /////////////////////////////// public boolean isShouldPrintMessage() { @@ -128,12 +134,6 @@ public boolean isShouldPrintMessage() { /////////////////////////////// Delay Reporting /////////////////////////////// - public void bindPipeName(final String pipeName) { - if (shouldPrintMessage) { - this.pipeName = pipeName; - } - } - public void onPublished() { if (shouldPrintMessage) { timePublished = System.currentTimeMillis(); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/row/PipeDataTypeTransformer.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/row/PipeDataTypeTransformer.java index 41ffd7f169109..caa98cdad6ace 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/row/PipeDataTypeTransformer.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/row/PipeDataTypeTransformer.java @@ -29,7 +29,7 @@ /** Transform between {@link TSDataType} and {@link org.apache.iotdb.pipe.api.type.Type}. */ public class PipeDataTypeTransformer { - public static List transformToPipeDataTypeList(List tsDataTypeList) { + public static List transformToPipeDataTypeList(final List tsDataTypeList) { return tsDataTypeList == null ? null : tsDataTypeList.stream() @@ -37,11 +37,11 @@ public static List transformToPipeDataTypeList(List tsDataType .collect(Collectors.toList()); } - public static Type transformToPipeDataType(TSDataType tsDataType) { + public static Type transformToPipeDataType(final TSDataType tsDataType) { return tsDataType == null ? null : getPipeDataType(tsDataType.getType()); } - private static Type getPipeDataType(byte type) { + private static Type getPipeDataType(final byte type) { switch (type) { case 0: return Type.BOOLEAN; @@ -55,6 +55,14 @@ private static Type getPipeDataType(byte type) { return Type.DOUBLE; case 5: return Type.TEXT; + case 8: + return Type.TIMESTAMP; + case 9: + return Type.DATE; + case 10: + return Type.BLOB; + case 11: + return Type.STRING; default: throw new IllegalArgumentException("Invalid input: " + type); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/row/PipeRow.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/row/PipeRow.java index c1a6680803f8e..8757b6613c986 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/row/PipeRow.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/row/PipeRow.java @@ -29,6 +29,7 @@ import org.apache.tsfile.utils.BitMap; import org.apache.tsfile.write.schema.IMeasurementSchema; +import java.time.LocalDate; import java.util.Arrays; import java.util.List; @@ -48,15 +49,15 @@ public class PipeRow implements Row { protected final String[] columnNameStringList; public PipeRow( - int rowIndex, - String deviceId, - boolean isAligned, - IMeasurementSchema[] measurementSchemaList, - long[] timestampColumn, - TSDataType[] valueColumnTypes, - Object[] valueColumns, - BitMap[] bitMaps, - String[] columnNameStringList) { + final int rowIndex, + final String deviceId, + final boolean isAligned, + final IMeasurementSchema[] measurementSchemaList, + final long[] timestampColumn, + final TSDataType[] valueColumnTypes, + final Object[] valueColumns, + final BitMap[] bitMaps, + final String[] columnNameStringList) { this.rowIndex = rowIndex; this.deviceId = deviceId; this.isAligned = isAligned; @@ -74,49 +75,57 @@ public long getTime() { } @Override - public int getInt(int columnIndex) { + public int getInt(final int columnIndex) { return ((int[]) valueColumns[columnIndex])[rowIndex]; } @Override - public long getLong(int columnIndex) { + public LocalDate getDate(final int columnIndex) { + return ((LocalDate[]) valueColumns[columnIndex])[rowIndex]; + } + + @Override + public long getLong(final int columnIndex) { return ((long[]) valueColumns[columnIndex])[rowIndex]; } @Override - public float getFloat(int columnIndex) { + public float getFloat(final int columnIndex) { return ((float[]) valueColumns[columnIndex])[rowIndex]; } @Override - public double getDouble(int columnIndex) { + public double getDouble(final int columnIndex) { return ((double[]) valueColumns[columnIndex])[rowIndex]; } @Override - public boolean getBoolean(int columnIndex) { + public boolean getBoolean(final int columnIndex) { return ((boolean[]) valueColumns[columnIndex])[rowIndex]; } @Override - public org.apache.iotdb.pipe.api.type.Binary getBinary(int columnIndex) { + public org.apache.iotdb.pipe.api.type.Binary getBinary(final int columnIndex) { return PipeBinaryTransformer.transformToPipeBinary( ((org.apache.tsfile.utils.Binary[]) valueColumns[columnIndex])[rowIndex]); } @Override - public String getString(int columnIndex) { + public String getString(final int columnIndex) { final org.apache.tsfile.utils.Binary binary = ((org.apache.tsfile.utils.Binary[]) valueColumns[columnIndex])[rowIndex]; return binary == null ? null : binary.getStringValue(TSFileConfig.STRING_CHARSET); } @Override - public Object getObject(int columnIndex) { + public Object getObject(final int columnIndex) { switch (getDataType(columnIndex)) { case INT32: return getInt(columnIndex); + case DATE: + return getDate(columnIndex); case INT64: + case TIMESTAMP: return getLong(columnIndex); case FLOAT: return getFloat(columnIndex); @@ -125,6 +134,8 @@ public Object getObject(int columnIndex) { case BOOLEAN: return getBoolean(columnIndex); case TEXT: + case BLOB: + case STRING: return getBinary(columnIndex); default: throw new UnsupportedOperationException( @@ -135,12 +146,12 @@ public Object getObject(int columnIndex) { } @Override - public Type getDataType(int columnIndex) { + public Type getDataType(final int columnIndex) { return PipeDataTypeTransformer.transformToPipeDataType(valueColumnTypes[columnIndex]); } @Override - public boolean isNull(int columnIndex) { + public boolean isNull(final int columnIndex) { return bitMaps[columnIndex].isMarked(rowIndex); } @@ -150,7 +161,7 @@ public int size() { } @Override - public int getColumnIndex(Path columnName) throws PipeParameterNotValidException { + public int getColumnIndex(final Path columnName) throws PipeParameterNotValidException { for (int i = 0; i < columnNameStringList.length; i++) { if (columnNameStringList[i].equals(columnName.getFullPath())) { return i; @@ -161,7 +172,7 @@ public int getColumnIndex(Path columnName) throws PipeParameterNotValidException } @Override - public String getColumnName(int columnIndex) { + public String getColumnName(final int columnIndex) { return columnNameStringList[columnIndex]; } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/row/PipeRowCollector.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/row/PipeRowCollector.java index 72358210a4eea..c1f7739534dbd 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/row/PipeRowCollector.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/row/PipeRowCollector.java @@ -105,6 +105,7 @@ private void collectTabletInsertionEvent() { tablet, isAligned, sourceEvent == null ? null : sourceEvent.getPipeName(), + sourceEvent == null ? 0 : sourceEvent.getCreationTime(), pipeTaskMeta, sourceEvent, false)); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/schema/PipeSchemaRegionSnapshotEvent.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/schema/PipeSchemaRegionSnapshotEvent.java index d647285bdc633..60bbf95feee66 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/schema/PipeSchemaRegionSnapshotEvent.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/schema/PipeSchemaRegionSnapshotEvent.java @@ -78,7 +78,7 @@ public PipeSchemaRegionSnapshotEvent() { public PipeSchemaRegionSnapshotEvent( final String mTreeSnapshotPath, final String tagLogSnapshotPath, final String databaseName) { - this(mTreeSnapshotPath, tagLogSnapshotPath, databaseName, null, null, null); + this(mTreeSnapshotPath, tagLogSnapshotPath, databaseName, null, 0, null, null); } public PipeSchemaRegionSnapshotEvent( @@ -86,9 +86,10 @@ public PipeSchemaRegionSnapshotEvent( final String tagLogSnapshotPath, final String databaseName, final String pipeName, + final long creationTime, final PipeTaskMeta pipeTaskMeta, final PipePattern pattern) { - super(pipeName, pipeTaskMeta, pattern, PipeResourceManager.snapshot()); + super(pipeName, creationTime, pipeTaskMeta, pattern, PipeResourceManager.snapshot()); this.mTreeSnapshotPath = mTreeSnapshotPath; this.tagLogSnapshotPath = Objects.nonNull(tagLogSnapshotPath) ? tagLogSnapshotPath : ""; this.databaseName = databaseName; @@ -145,12 +146,19 @@ public boolean internallyDecreaseResourceReferenceCount(final String holderMessa @Override public EnrichedEvent shallowCopySelfAndBindPipeTaskMetaForProgressReport( final String pipeName, + final long creationTime, final PipeTaskMeta pipeTaskMeta, final PipePattern pattern, final long startTime, final long endTime) { return new PipeSchemaRegionSnapshotEvent( - mTreeSnapshotPath, tagLogSnapshotPath, databaseName, pipeName, pipeTaskMeta, pattern); + mTreeSnapshotPath, + tagLogSnapshotPath, + databaseName, + pipeName, + creationTime, + pipeTaskMeta, + pattern); } @Override diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/schema/PipeSchemaRegionWritePlanEvent.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/schema/PipeSchemaRegionWritePlanEvent.java index 6e0b5cccf8660..d6eefe086e55c 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/schema/PipeSchemaRegionWritePlanEvent.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/schema/PipeSchemaRegionWritePlanEvent.java @@ -40,16 +40,17 @@ public PipeSchemaRegionWritePlanEvent() { } public PipeSchemaRegionWritePlanEvent(final PlanNode planNode, final boolean isGeneratedByPipe) { - this(planNode, null, null, null, isGeneratedByPipe); + this(planNode, null, 0, null, null, isGeneratedByPipe); } public PipeSchemaRegionWritePlanEvent( final PlanNode planNode, final String pipeName, + final long creationTime, final PipeTaskMeta pipeTaskMeta, final PipePattern pattern, final boolean isGeneratedByPipe) { - super(pipeName, pipeTaskMeta, pattern, isGeneratedByPipe); + super(pipeName, creationTime, pipeTaskMeta, pattern, isGeneratedByPipe); this.planNode = planNode; } @@ -60,12 +61,13 @@ public PlanNode getPlanNode() { @Override public EnrichedEvent shallowCopySelfAndBindPipeTaskMetaForProgressReport( final String pipeName, + final long creationTime, final PipeTaskMeta pipeTaskMeta, final PipePattern pattern, final long startTime, final long endTime) { return new PipeSchemaRegionWritePlanEvent( - planNode, pipeName, pipeTaskMeta, pattern, isGeneratedByPipe); + planNode, pipeName, creationTime, pipeTaskMeta, pattern, isGeneratedByPipe); } @Override diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tablet/PipeInsertNodeTabletInsertionEvent.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tablet/PipeInsertNodeTabletInsertionEvent.java index c4fd1a133c2af..eb6191e1c340b 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tablet/PipeInsertNodeTabletInsertionEvent.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tablet/PipeInsertNodeTabletInsertionEvent.java @@ -26,7 +26,6 @@ import org.apache.iotdb.commons.pipe.pattern.PipePattern; import org.apache.iotdb.commons.pipe.task.meta.PipeTaskMeta; import org.apache.iotdb.db.pipe.resource.PipeResourceManager; -import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeType; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.write.InsertNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.write.InsertRowNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.write.InsertRowsNode; @@ -68,11 +67,11 @@ public class PipeInsertNodeTabletInsertionEvent extends EnrichedEvent private ProgressIndex progressIndex; public PipeInsertNodeTabletInsertionEvent( - WALEntryHandler walEntryHandler, - PartialPath devicePath, - ProgressIndex progressIndex, - boolean isAligned, - boolean isGeneratedByPipe) { + final WALEntryHandler walEntryHandler, + final PartialPath devicePath, + final ProgressIndex progressIndex, + final boolean isAligned, + final boolean isGeneratedByPipe) { this( walEntryHandler, devicePath, @@ -80,6 +79,7 @@ public PipeInsertNodeTabletInsertionEvent( isAligned, isGeneratedByPipe, null, + 0, null, null, Long.MIN_VALUE, @@ -87,17 +87,18 @@ public PipeInsertNodeTabletInsertionEvent( } private PipeInsertNodeTabletInsertionEvent( - WALEntryHandler walEntryHandler, - PartialPath devicePath, - ProgressIndex progressIndex, - boolean isAligned, - boolean isGeneratedByPipe, - String pipeName, - PipeTaskMeta pipeTaskMeta, - PipePattern pattern, - long startTime, - long endTime) { - super(pipeName, pipeTaskMeta, pattern, startTime, endTime); + final WALEntryHandler walEntryHandler, + final PartialPath devicePath, + final ProgressIndex progressIndex, + final boolean isAligned, + final boolean isGeneratedByPipe, + final String pipeName, + final long creationTime, + final PipeTaskMeta pipeTaskMeta, + final PipePattern pattern, + final long startTime, + final long endTime) { + super(pipeName, creationTime, pipeTaskMeta, pattern, startTime, endTime); this.walEntryHandler = walEntryHandler; // Record device path here so there's no need to get it from InsertNode cache later. this.devicePath = devicePath; @@ -129,11 +130,11 @@ public String getDeviceId() { /////////////////////////// EnrichedEvent /////////////////////////// @Override - public boolean internallyIncreaseResourceReferenceCount(String holderMessage) { + public boolean internallyIncreaseResourceReferenceCount(final String holderMessage) { try { PipeResourceManager.wal().pin(walEntryHandler); return true; - } catch (Exception e) { + } catch (final Exception e) { LOGGER.warn( String.format( "Increase reference count for memtable %d error. Holder Message: %s", @@ -144,7 +145,7 @@ public boolean internallyIncreaseResourceReferenceCount(String holderMessage) { } @Override - public boolean internallyDecreaseResourceReferenceCount(String holderMessage) { + public boolean internallyDecreaseResourceReferenceCount(final String holderMessage) { try { PipeResourceManager.wal().unpin(walEntryHandler); // Release the containers' memory. @@ -153,7 +154,7 @@ public boolean internallyDecreaseResourceReferenceCount(String holderMessage) { dataContainers = null; } return true; - } catch (Exception e) { + } catch (final Exception e) { LOGGER.warn( String.format( "Decrease reference count for memtable %d error. Holder Message: %s", @@ -164,7 +165,7 @@ public boolean internallyDecreaseResourceReferenceCount(String holderMessage) { } @Override - public void bindProgressIndex(ProgressIndex progressIndex) { + public void bindProgressIndex(final ProgressIndex progressIndex) { this.progressIndex = progressIndex; } @@ -175,11 +176,12 @@ public ProgressIndex getProgressIndex() { @Override public PipeInsertNodeTabletInsertionEvent shallowCopySelfAndBindPipeTaskMetaForProgressReport( - String pipeName, - PipeTaskMeta pipeTaskMeta, - PipePattern pattern, - long startTime, - long endTime) { + final String pipeName, + final long creationTime, + final PipeTaskMeta pipeTaskMeta, + final PipePattern pattern, + final long startTime, + final long endTime) { return new PipeInsertNodeTabletInsertionEvent( walEntryHandler, devicePath, @@ -187,6 +189,7 @@ public PipeInsertNodeTabletInsertionEvent shallowCopySelfAndBindPipeTaskMetaForP isAligned, isGeneratedByPipe, pipeName, + creationTime, pipeTaskMeta, pattern, startTime, @@ -201,30 +204,73 @@ public boolean isGeneratedByPipe() { @Override public boolean mayEventTimeOverlappedWithTimeRange() { try { - final InsertNode insertNode = getInsertNode(); + final InsertNode insertNode = getInsertNodeViaCacheIfPossible(); + if (Objects.isNull(insertNode)) { + return true; + } + if (insertNode instanceof InsertRowNode) { final long timestamp = ((InsertRowNode) insertNode).getTime(); return startTime <= timestamp && timestamp <= endTime; - } else if (insertNode instanceof InsertTabletNode) { + } + + if (insertNode instanceof InsertTabletNode) { final long[] timestamps = ((InsertTabletNode) insertNode).getTimes(); if (Objects.isNull(timestamps) || timestamps.length == 0) { return false; } // We assume that `timestamps` is ordered. return startTime <= timestamps[timestamps.length - 1] && timestamps[0] <= endTime; - } else if (insertNode instanceof InsertRowsNode) { - for (final InsertRowNode node : ((InsertRowsNode) insertNode).getInsertRowNodeList()) { - final long timestamp = node.getTime(); - if (startTime <= timestamp && timestamp <= endTime) { - return true; - } - } - return false; - } else { - throw new UnSupportedDataTypeException( - String.format("InsertNode type %s is not supported.", insertNode.getClass().getName())); } - } catch (Exception e) { + + if (insertNode instanceof InsertRowsNode) { + return ((InsertRowsNode) insertNode) + .getInsertRowNodeList().stream() + .anyMatch( + insertRowNode -> { + final long timestamp = insertRowNode.getTime(); + return startTime <= timestamp && timestamp <= endTime; + }); + } + + return true; + } catch (final Exception e) { + LOGGER.warn( + "Exception occurred when determining the event time of PipeInsertNodeTabletInsertionEvent({}) overlaps with the time range: [{}, {}]. Returning true to ensure data integrity.", + this, + startTime, + endTime, + e); + return true; + } + } + + @Override + public boolean mayEventPathsOverlappedWithPattern() { + try { + final InsertNode insertNode = getInsertNodeViaCacheIfPossible(); + if (Objects.isNull(insertNode)) { + return true; + } + + if (insertNode instanceof InsertRowNode || insertNode instanceof InsertTabletNode) { + final PartialPath devicePartialPath = insertNode.getDevicePath(); + return Objects.isNull(devicePartialPath) + || pipePattern.mayOverlapWithDevice(devicePartialPath.getIDeviceIDAsFullDevice()); + } + + if (insertNode instanceof InsertRowsNode) { + return ((InsertRowsNode) insertNode) + .getInsertRowNodeList().stream() + .anyMatch( + insertRowNode -> + Objects.isNull(insertRowNode.getDevicePath()) + || pipePattern.mayOverlapWithDevice( + insertRowNode.getDevicePath().getIDeviceIDAsFullDevice())); + } + + return true; + } catch (final Exception e) { LOGGER.warn( "Exception occurred when determining the event time of PipeInsertNodeTabletInsertionEvent({}) overlaps with the time range: [{}, {}]. Returning true to ensure data integrity.", this, @@ -238,7 +284,8 @@ public boolean mayEventTimeOverlappedWithTimeRange() { /////////////////////////// TabletInsertionEvent /////////////////////////// @Override - public Iterable processRowByRow(BiConsumer consumer) { + public Iterable processRowByRow( + final BiConsumer consumer) { return initDataContainers().stream() .map(tabletInsertionDataContainer -> tabletInsertionDataContainer.processRowByRow(consumer)) .flatMap(Collection::stream) @@ -246,7 +293,8 @@ public Iterable processRowByRow(BiConsumer processTablet(BiConsumer consumer) { + public Iterable processTablet( + final BiConsumer consumer) { return initDataContainers().stream() .map(tabletInsertionDataContainer -> tabletInsertionDataContainer.processTablet(consumer)) .flatMap(Collection::stream) @@ -312,27 +360,13 @@ public long count() { /////////////////////////// parsePatternOrTime /////////////////////////// - @Override - public boolean shouldParsePattern() { - final InsertNode node = getInsertNodeViaCacheIfPossible(); - return super.shouldParsePattern() - && Objects.nonNull(pipePattern) - && (Objects.isNull(node) - || (node.getType() == PlanNodeType.INSERT_ROWS - ? ((InsertRowsNode) node) - .getInsertRowNodeList().stream() - .anyMatch( - insertRowNode -> !pipePattern.coversDevice(insertRowNode.getDeviceID())) - : !pipePattern.coversDevice(node.getDeviceID()))); - } - public List toRawTabletInsertionEvents() { final List events = convertToTablets().stream() .map( tablet -> new PipeRawTabletInsertionEvent( - tablet, isAligned, pipeName, pipeTaskMeta, this, false)) + tablet, isAligned, pipeName, creationTime, pipeTaskMeta, this, false)) .filter(event -> !event.hasNoNeedParsingAndIsEmpty()) .collect(Collectors.toList()); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tablet/PipeRawTabletInsertionEvent.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tablet/PipeRawTabletInsertionEvent.java index 285faba201134..5b759ab649afc 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tablet/PipeRawTabletInsertionEvent.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tablet/PipeRawTabletInsertionEvent.java @@ -31,6 +31,7 @@ import org.apache.iotdb.pipe.api.collector.RowCollector; import org.apache.iotdb.pipe.api.event.dml.insertion.TabletInsertionEvent; +import org.apache.tsfile.file.metadata.IDeviceID; import org.apache.tsfile.write.record.Tablet; import java.util.Objects; @@ -52,16 +53,17 @@ public class PipeRawTabletInsertionEvent extends EnrichedEvent implements Tablet private ProgressIndex overridingProgressIndex; private PipeRawTabletInsertionEvent( - Tablet tablet, - boolean isAligned, - EnrichedEvent sourceEvent, - boolean needToReport, - String pipeName, - PipeTaskMeta pipeTaskMeta, - PipePattern pattern, - long startTime, - long endTime) { - super(pipeName, pipeTaskMeta, pattern, startTime, endTime); + final Tablet tablet, + final boolean isAligned, + final EnrichedEvent sourceEvent, + final boolean needToReport, + final String pipeName, + final long creationTime, + final PipeTaskMeta pipeTaskMeta, + final PipePattern pattern, + final long startTime, + final long endTime) { + super(pipeName, creationTime, pipeTaskMeta, pattern, startTime, endTime); this.tablet = Objects.requireNonNull(tablet); this.isAligned = isAligned; this.sourceEvent = sourceEvent; @@ -69,18 +71,20 @@ private PipeRawTabletInsertionEvent( } public PipeRawTabletInsertionEvent( - Tablet tablet, - boolean isAligned, - String pipeName, - PipeTaskMeta pipeTaskMeta, - EnrichedEvent sourceEvent, - boolean needToReport) { + final Tablet tablet, + final boolean isAligned, + final String pipeName, + final long creationTime, + final PipeTaskMeta pipeTaskMeta, + final EnrichedEvent sourceEvent, + final boolean needToReport) { this( tablet, isAligned, sourceEvent, needToReport, pipeName, + creationTime, pipeTaskMeta, null, Long.MIN_VALUE, @@ -88,28 +92,30 @@ public PipeRawTabletInsertionEvent( } @TestOnly - public PipeRawTabletInsertionEvent(Tablet tablet, boolean isAligned) { - this(tablet, isAligned, null, false, null, null, null, Long.MIN_VALUE, Long.MAX_VALUE); + public PipeRawTabletInsertionEvent(final Tablet tablet, final boolean isAligned) { + this(tablet, isAligned, null, false, null, 0, null, null, Long.MIN_VALUE, Long.MAX_VALUE); } @TestOnly - public PipeRawTabletInsertionEvent(Tablet tablet, boolean isAligned, PipePattern pattern) { - this(tablet, isAligned, null, false, null, null, pattern, Long.MIN_VALUE, Long.MAX_VALUE); + public PipeRawTabletInsertionEvent( + final Tablet tablet, final boolean isAligned, final PipePattern pattern) { + this(tablet, isAligned, null, false, null, 0, null, pattern, Long.MIN_VALUE, Long.MAX_VALUE); } @TestOnly - public PipeRawTabletInsertionEvent(Tablet tablet, long startTime, long endTime) { - this(tablet, false, null, false, null, null, null, startTime, endTime); + public PipeRawTabletInsertionEvent( + final Tablet tablet, final long startTime, final long endTime) { + this(tablet, false, null, false, null, 0, null, null, startTime, endTime); } @Override - public boolean internallyIncreaseResourceReferenceCount(String holderMessage) { + public boolean internallyIncreaseResourceReferenceCount(final String holderMessage) { allocatedMemoryBlock = PipeResourceManager.memory().forceAllocateWithRetry(tablet); return true; } @Override - public boolean internallyDecreaseResourceReferenceCount(String holderMessage) { + public boolean internallyDecreaseResourceReferenceCount(final String holderMessage) { allocatedMemoryBlock.close(); // Record the deviceId before the memory is released, @@ -130,7 +136,7 @@ protected void reportProgress() { } @Override - public void bindProgressIndex(ProgressIndex overridingProgressIndex) { + public void bindProgressIndex(final ProgressIndex overridingProgressIndex) { // Normally not all events need to report progress, but if the overridingProgressIndex // is given, indicating that the progress needs to be reported. if (Objects.nonNull(overridingProgressIndex)) { @@ -152,17 +158,19 @@ public ProgressIndex getProgressIndex() { @Override public EnrichedEvent shallowCopySelfAndBindPipeTaskMetaForProgressReport( - String pipeName, - PipeTaskMeta pipeTaskMeta, - PipePattern pattern, - long startTime, - long endTime) { + final String pipeName, + final long creationTime, + final PipeTaskMeta pipeTaskMeta, + final PipePattern pattern, + final long startTime, + final long endTime) { return new PipeRawTabletInsertionEvent( tablet, isAligned, sourceEvent, needToReport, pipeName, + creationTime, pipeTaskMeta, pattern, startTime, @@ -184,6 +192,13 @@ public boolean mayEventTimeOverlappedWithTimeRange() { return startTime <= timestamps[timestamps.length - 1] && timestamps[0] <= endTime; } + @Override + public boolean mayEventPathsOverlappedWithPattern() { + final String deviceId = getDeviceId(); + return Objects.isNull(deviceId) + || pipePattern.mayOverlapWithDevice(IDeviceID.Factory.DEFAULT_FACTORY.create(deviceId)); + } + public void markAsNeedToReport() { this.needToReport = true; } @@ -196,7 +211,8 @@ public String getDeviceId() { /////////////////////////// TabletInsertionEvent /////////////////////////// @Override - public Iterable processRowByRow(BiConsumer consumer) { + public Iterable processRowByRow( + final BiConsumer consumer) { if (dataContainer == null) { dataContainer = new TabletInsertionDataContainer(pipeTaskMeta, this, tablet, isAligned, pipePattern); @@ -205,7 +221,8 @@ public Iterable processRowByRow(BiConsumer processTablet(BiConsumer consumer) { + public Iterable processTablet( + final BiConsumer consumer) { if (dataContainer == null) { dataContainer = new TabletInsertionDataContainer(pipeTaskMeta, this, tablet, isAligned, pipePattern); @@ -241,7 +258,7 @@ public long count() { public PipeRawTabletInsertionEvent parseEventWithPatternOrTime() { return new PipeRawTabletInsertionEvent( - convertToTablet(), isAligned, pipeName, pipeTaskMeta, this, needToReport); + convertToTablet(), isAligned, pipeName, creationTime, pipeTaskMeta, this, needToReport); } public boolean hasNoNeedParsingAndIsEmpty() { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tablet/TabletInsertionDataContainer.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tablet/TabletInsertionDataContainer.java index c7a563bcb0560..be91884f2b0f5 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tablet/TabletInsertionDataContainer.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tablet/TabletInsertionDataContainer.java @@ -37,6 +37,7 @@ import org.apache.tsfile.file.metadata.StringArrayDeviceID; import org.apache.tsfile.utils.Binary; import org.apache.tsfile.utils.BitMap; +import org.apache.tsfile.utils.DateUtils; import org.apache.tsfile.write.UnSupportedDataTypeException; import org.apache.tsfile.write.record.Tablet; import org.apache.tsfile.write.schema.IMeasurementSchema; @@ -45,6 +46,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.time.LocalDate; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -148,7 +150,7 @@ private void parse(final InsertRowNode insertRowNode, final PipePattern pattern) this.isAligned = insertRowNode.isAligned(); final long[] originTimestampColumn = new long[] {insertRowNode.getTime()}; - List rowIndexList = generateRowIndexList(originTimestampColumn); + final List rowIndexList = generateRowIndexList(originTimestampColumn); this.timestampColumn = rowIndexList.stream().mapToLong(i -> originTimestampColumn[i]).toArray(); generateColumnIndexMapper( @@ -177,7 +179,7 @@ private void parse(final InsertRowNode insertRowNode, final PipePattern pattern) this.measurementSchemaList[filteredColumnIndex] = originMeasurementSchemaList[i]; this.columnNameStringList[filteredColumnIndex] = originColumnNameStringList[i]; this.valueColumnTypes[filteredColumnIndex] = originValueColumnTypes[i]; - BitMap bitMap = new BitMap(this.timestampColumn.length); + final BitMap bitMap = new BitMap(this.timestampColumn.length); if (Objects.isNull(originValueColumns[i]) || Objects.isNull(originValueColumnTypes[i])) { this.valueColumns[filteredColumnIndex] = null; bitMap.markAll(); @@ -218,7 +220,7 @@ private void parse(final InsertTabletNode insertTabletNode, final PipePattern pa final long[] originTimestampColumn = insertTabletNode.getTimes(); final int originRowSize = originTimestampColumn.length; - List rowIndexList = generateRowIndexList(originTimestampColumn); + final List rowIndexList = generateRowIndexList(originTimestampColumn); this.timestampColumn = rowIndexList.stream().mapToLong(i -> originTimestampColumn[i]).toArray(); generateColumnIndexMapper( @@ -262,7 +264,7 @@ private void parse(final InsertTabletNode insertTabletNode, final PipePattern pa this.measurementSchemaList[filteredColumnIndex] = originMeasurementSchemaList[i]; this.columnNameStringList[filteredColumnIndex] = originColumnNameStringList[i]; this.valueColumnTypes[filteredColumnIndex] = originValueColumnTypes[i]; - BitMap bitMap = new BitMap(this.timestampColumn.length); + final BitMap bitMap = new BitMap(this.timestampColumn.length); if (Objects.isNull(originValueColumns[i]) || Objects.isNull(originValueColumnTypes[i])) { this.valueColumns[filteredColumnIndex] = null; bitMap.markAll(); @@ -304,7 +306,7 @@ private void parse(final Tablet tablet, final boolean isAligned, final PipePatte final long[] originTimestampColumn = Arrays.copyOf( tablet.timestamps, tablet.rowSize); // tablet.timestamps.length == tablet.maxRowNumber - List rowIndexList = generateRowIndexList(originTimestampColumn); + final List rowIndexList = generateRowIndexList(originTimestampColumn); this.timestampColumn = rowIndexList.stream().mapToLong(i -> originTimestampColumn[i]).toArray(); final List originMeasurementSchemaList = tablet.getSchemas(); @@ -355,7 +357,7 @@ private void parse(final Tablet tablet, final boolean isAligned, final PipePatte this.measurementSchemaList[filteredColumnIndex] = originMeasurementSchemaList.get(i); this.columnNameStringList[filteredColumnIndex] = originColumnNameStringList[i]; this.valueColumnTypes[filteredColumnIndex] = originValueColumnTypes[i]; - BitMap bitMap = new BitMap(this.timestampColumn.length); + final BitMap bitMap = new BitMap(this.timestampColumn.length); if (Objects.isNull(originValueColumns[i]) || Objects.isNull(originValueColumnTypes[i])) { this.valueColumns[filteredColumnIndex] = null; bitMap.markAll(); @@ -425,7 +427,7 @@ private List generateRowIndexList(final long[] originTimestampColumn) { return generateFullRowIndexList(rowCount); } - List rowIndexList = new ArrayList<>(); + final List rowIndexList = new ArrayList<>(); // We assume that `originTimestampColumn` is ordered. if (originTimestampColumn[originTimestampColumn.length - 1] < sourceEvent.getStartTime() || originTimestampColumn[0] > sourceEvent.getEndTime()) { @@ -442,7 +444,7 @@ private List generateRowIndexList(final long[] originTimestampColumn) { return rowIndexList; } - private static List generateFullRowIndexList(int rowCount) { + private static List generateFullRowIndexList(final int rowCount) { if (rowCount <= CACHED_FULL_ROW_INDEX_LIST_ROW_COUNT_UPPER) { return cachedFullRowIndexList.get(rowCount); } @@ -450,20 +452,20 @@ private static List generateFullRowIndexList(int rowCount) { } private static Object filterValueColumnsByRowIndexList( - @NonNull TSDataType type, - @NonNull Object originValueColumn, - @NonNull List rowIndexList, - boolean isSingleOriginValueColumn, - @NonNull BitMap originNullValueColumnBitmap, - @NonNull BitMap nullValueColumnBitmap /* output parameters */) { + @NonNull final TSDataType type, + @NonNull final Object originValueColumn, + @NonNull final List rowIndexList, + final boolean isSingleOriginValueColumn, + @NonNull final BitMap originNullValueColumnBitmap, + @NonNull final BitMap nullValueColumnBitmap /* output parameters */) { switch (type) { case INT32: { - int[] intValueColumns = + final int[] intValueColumns = isSingleOriginValueColumn ? new int[] {(int) originValueColumn} : (int[]) originValueColumn; - int[] valueColumns = new int[rowIndexList.size()]; + final int[] valueColumns = new int[rowIndexList.size()]; for (int i = 0; i < rowIndexList.size(); ++i) { if (originNullValueColumnBitmap.isMarked(rowIndexList.get(i))) { valueColumns[i] = 0; @@ -474,13 +476,52 @@ private static Object filterValueColumnsByRowIndexList( } return valueColumns; } + case DATE: + { + // Always store 'LocalDate[]' to help convert to tablet + final LocalDate[] valueColumns = new LocalDate[rowIndexList.size()]; + if (isSingleOriginValueColumn && originValueColumn instanceof LocalDate + || !isSingleOriginValueColumn && originValueColumn instanceof LocalDate[]) { + // For tablet + final LocalDate[] dateValueColumns = + isSingleOriginValueColumn + ? new LocalDate[] {(LocalDate) originValueColumn} + : (LocalDate[]) originValueColumn; + + for (int i = 0; i < rowIndexList.size(); ++i) { + if (originNullValueColumnBitmap.isMarked(rowIndexList.get(i))) { + valueColumns[i] = LocalDate.MIN; + nullValueColumnBitmap.mark(i); + } else { + valueColumns[i] = dateValueColumns[rowIndexList.get(i)]; + } + } + } else { + // For insertRowNode / insertTabletNode + final int[] intValueColumns = + isSingleOriginValueColumn + ? new int[] {(int) originValueColumn} + : (int[]) originValueColumn; + for (int i = 0; i < rowIndexList.size(); ++i) { + if (originNullValueColumnBitmap.isMarked(rowIndexList.get(i))) { + valueColumns[i] = LocalDate.MIN; + nullValueColumnBitmap.mark(i); + } else { + valueColumns[i] = + DateUtils.parseIntToLocalDate(intValueColumns[rowIndexList.get(i)]); + } + } + } + return valueColumns; + } case INT64: + case TIMESTAMP: { - long[] longValueColumns = + final long[] longValueColumns = isSingleOriginValueColumn ? new long[] {(long) originValueColumn} : (long[]) originValueColumn; - long[] valueColumns = new long[rowIndexList.size()]; + final long[] valueColumns = new long[rowIndexList.size()]; for (int i = 0; i < rowIndexList.size(); ++i) { if (originNullValueColumnBitmap.isMarked(rowIndexList.get(i))) { valueColumns[i] = 0L; @@ -493,11 +534,11 @@ private static Object filterValueColumnsByRowIndexList( } case FLOAT: { - float[] floatValueColumns = + final float[] floatValueColumns = isSingleOriginValueColumn ? new float[] {(float) originValueColumn} : (float[]) originValueColumn; - float[] valueColumns = new float[rowIndexList.size()]; + final float[] valueColumns = new float[rowIndexList.size()]; for (int i = 0; i < rowIndexList.size(); ++i) { if (originNullValueColumnBitmap.isMarked(rowIndexList.get(i))) { valueColumns[i] = 0F; @@ -510,11 +551,11 @@ private static Object filterValueColumnsByRowIndexList( } case DOUBLE: { - double[] doubleValueColumns = + final double[] doubleValueColumns = isSingleOriginValueColumn ? new double[] {(double) originValueColumn} : (double[]) originValueColumn; - double[] valueColumns = new double[rowIndexList.size()]; + final double[] valueColumns = new double[rowIndexList.size()]; for (int i = 0; i < rowIndexList.size(); ++i) { if (originNullValueColumnBitmap.isMarked(rowIndexList.get(i))) { valueColumns[i] = 0D; @@ -527,11 +568,11 @@ private static Object filterValueColumnsByRowIndexList( } case BOOLEAN: { - boolean[] booleanValueColumns = + final boolean[] booleanValueColumns = isSingleOriginValueColumn ? new boolean[] {(boolean) originValueColumn} : (boolean[]) originValueColumn; - boolean[] valueColumns = new boolean[rowIndexList.size()]; + final boolean[] valueColumns = new boolean[rowIndexList.size()]; for (int i = 0; i < rowIndexList.size(); ++i) { if (originNullValueColumnBitmap.isMarked(rowIndexList.get(i))) { valueColumns[i] = false; @@ -543,12 +584,14 @@ private static Object filterValueColumnsByRowIndexList( return valueColumns; } case TEXT: + case BLOB: + case STRING: { - Binary[] binaryValueColumns = + final Binary[] binaryValueColumns = isSingleOriginValueColumn ? new Binary[] {(Binary) originValueColumn} : (Binary[]) originValueColumn; - Binary[] valueColumns = new Binary[rowIndexList.size()]; + final Binary[] valueColumns = new Binary[rowIndexList.size()]; for (int i = 0; i < rowIndexList.size(); ++i) { if (Objects.isNull(binaryValueColumns[rowIndexList.get(i)]) || Objects.isNull(binaryValueColumns[rowIndexList.get(i)].getValues()) @@ -569,7 +612,7 @@ private static Object filterValueColumnsByRowIndexList( //////////////////////////// process //////////////////////////// - public List processRowByRow(BiConsumer consumer) { + public List processRowByRow(final BiConsumer consumer) { if (valueColumns.length == 0 || timestampColumn.length == 0) { return Collections.emptyList(); } @@ -593,7 +636,7 @@ public List processRowByRow(BiConsumer return rowCollector.convertToTabletInsertionEvents(shouldReport); } - public List processTablet(BiConsumer consumer) { + public List processTablet(final BiConsumer consumer) { final PipeRowCollector rowCollector = new PipeRowCollector(pipeTaskMeta, sourceEvent); consumer.accept(convertToTablet(), rowCollector); return rowCollector.convertToTabletInsertionEvents(shouldReport); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/terminate/PipeTerminateEvent.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/terminate/PipeTerminateEvent.java index c1252fe668f96..bf152dfbf1744 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/terminate/PipeTerminateEvent.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/terminate/PipeTerminateEvent.java @@ -24,7 +24,7 @@ import org.apache.iotdb.commons.pipe.event.EnrichedEvent; import org.apache.iotdb.commons.pipe.pattern.PipePattern; import org.apache.iotdb.commons.pipe.task.meta.PipeTaskMeta; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.event.common.tsfile.PipeTsFileInsertionEvent; import org.apache.iotdb.db.pipe.task.PipeDataNodeTask; @@ -38,8 +38,11 @@ public class PipeTerminateEvent extends EnrichedEvent { private final int dataRegionId; public PipeTerminateEvent( - final String pipeName, final PipeTaskMeta pipeTaskMeta, final int dataRegionId) { - super(pipeName, pipeTaskMeta, null, Long.MIN_VALUE, Long.MAX_VALUE); + final String pipeName, + final long creationTime, + final PipeTaskMeta pipeTaskMeta, + final int dataRegionId) { + super(pipeName, creationTime, pipeTaskMeta, null, Long.MIN_VALUE, Long.MAX_VALUE); this.dataRegionId = dataRegionId; } @@ -61,13 +64,14 @@ public ProgressIndex getProgressIndex() { @Override public EnrichedEvent shallowCopySelfAndBindPipeTaskMetaForProgressReport( final String pipeName, + final long creationTime, final PipeTaskMeta pipeTaskMeta, final PipePattern pattern, final long startTime, final long endTime) { // Should record PipeTaskMeta, for the terminateEvent shall report progress to // notify the pipeTask it's completed. - return new PipeTerminateEvent(pipeName, pipeTaskMeta, dataRegionId); + return new PipeTerminateEvent(pipeName, creationTime, pipeTaskMeta, dataRegionId); } @Override @@ -80,9 +84,14 @@ public boolean mayEventTimeOverlappedWithTimeRange() { return true; } + @Override + public boolean mayEventPathsOverlappedWithPattern() { + return true; + } + @Override public void reportProgress() { - PipeAgent.task().markCompleted(pipeName, dataRegionId); + PipeDataNodeAgent.task().markCompleted(pipeName, dataRegionId); } @Override diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tsfile/PipeTsFileInsertionEvent.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tsfile/PipeTsFileInsertionEvent.java index cdab8d422159b..e5e3080ca5d09 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tsfile/PipeTsFileInsertionEvent.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tsfile/PipeTsFileInsertionEvent.java @@ -26,6 +26,7 @@ import org.apache.iotdb.commons.pipe.task.meta.PipeTaskMeta; import org.apache.iotdb.db.pipe.event.common.tablet.PipeRawTabletInsertionEvent; import org.apache.iotdb.db.pipe.resource.PipeResourceManager; +import org.apache.iotdb.db.pipe.resource.tsfile.PipeTsFileResourceManager; import org.apache.iotdb.db.storageengine.dataregion.memtable.TsFileProcessor; import org.apache.iotdb.db.storageengine.dataregion.modification.ModificationFile; import org.apache.iotdb.db.storageengine.dataregion.tsfile.TsFileResource; @@ -33,12 +34,16 @@ import org.apache.iotdb.pipe.api.event.dml.insertion.TsFileInsertionEvent; import org.apache.iotdb.pipe.api.exception.PipeException; +import org.apache.tsfile.file.metadata.IDeviceID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; import java.io.IOException; import java.util.Collections; +import java.util.Map; +import java.util.Objects; +import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; public class PipeTsFileInsertionEvent extends EnrichedEvent implements TsFileInsertionEvent { @@ -59,7 +64,7 @@ public class PipeTsFileInsertionEvent extends EnrichedEvent implements TsFileIns private TsFileInsertionDataContainer dataContainer; public PipeTsFileInsertionEvent( - TsFileResource resource, boolean isLoaded, boolean isGeneratedByPipe) { + final TsFileResource resource, final boolean isLoaded, final boolean isGeneratedByPipe) { // The modFile must be copied before the event is assigned to the listening pipes this( resource, @@ -67,6 +72,7 @@ public PipeTsFileInsertionEvent( isLoaded, isGeneratedByPipe, null, + 0, null, null, Long.MIN_VALUE, @@ -74,16 +80,17 @@ public PipeTsFileInsertionEvent( } public PipeTsFileInsertionEvent( - TsFileResource resource, - boolean isWithMod, - boolean isLoaded, - boolean isGeneratedByPipe, - String pipeName, - PipeTaskMeta pipeTaskMeta, - PipePattern pattern, - long startTime, - long endTime) { - super(pipeName, pipeTaskMeta, pattern, startTime, endTime); + final TsFileResource resource, + final boolean isWithMod, + final boolean isLoaded, + final boolean isGeneratedByPipe, + final String pipeName, + final long creationTime, + final PipeTaskMeta pipeTaskMeta, + final PipePattern pattern, + final long startTime, + final long endTime) { + super(pipeName, creationTime, pipeTaskMeta, pattern, startTime, endTime); this.resource = resource; tsFile = resource.getTsFile(); @@ -135,12 +142,22 @@ public PipeTsFileInsertionEvent( */ public boolean waitForTsFileClose() throws InterruptedException { if (!isClosed.get()) { + isClosed.set(resource.isClosed()); + synchronized (isClosed) { while (!isClosed.get()) { - isClosed.wait(); + isClosed.wait(100); + + final boolean isClosedNow = resource.isClosed(); + if (isClosedNow) { + isClosed.set(true); + isClosed.notifyAll(); + break; + } } } } + // From illustrations above we know If the status is "closed", then the tsFile is flushed // And here we guarantee that the isEmpty() is set before flushing if tsFile is empty // Then we know: "isClosed" --> tsFile flushed --> (isEmpty() <--> tsFile is empty) @@ -176,14 +193,14 @@ public long getFileStartTime() { /////////////////////////// EnrichedEvent /////////////////////////// @Override - public boolean internallyIncreaseResourceReferenceCount(String holderMessage) { + public boolean internallyIncreaseResourceReferenceCount(final String holderMessage) { try { tsFile = PipeResourceManager.tsfile().increaseFileReference(tsFile, true, resource); if (isWithMod) { modFile = PipeResourceManager.tsfile().increaseFileReference(modFile, false, null); } return true; - } catch (Exception e) { + } catch (final Exception e) { LOGGER.warn( String.format( "Increase reference count for TsFile %s or modFile %s error. Holder Message: %s", @@ -194,14 +211,14 @@ public boolean internallyIncreaseResourceReferenceCount(String holderMessage) { } @Override - public boolean internallyDecreaseResourceReferenceCount(String holderMessage) { + public boolean internallyDecreaseResourceReferenceCount(final String holderMessage) { try { PipeResourceManager.tsfile().decreaseFileReference(tsFile); if (isWithMod) { PipeResourceManager.tsfile().decreaseFileReference(modFile); } return true; - } catch (Exception e) { + } catch (final Exception e) { LOGGER.warn( String.format( "Decrease reference count for TsFile %s error. Holder Message: %s", @@ -221,7 +238,7 @@ public ProgressIndex getProgressIndex() { return MinimumProgressIndex.INSTANCE; } return resource.getMaxProgressIndexAfterClose(); - } catch (InterruptedException e) { + } catch (final InterruptedException e) { LOGGER.warn( String.format( "Interrupted when waiting for closing TsFile %s.", resource.getTsFilePath())); @@ -232,17 +249,19 @@ public ProgressIndex getProgressIndex() { @Override public PipeTsFileInsertionEvent shallowCopySelfAndBindPipeTaskMetaForProgressReport( - String pipeName, - PipeTaskMeta pipeTaskMeta, - PipePattern pattern, - long startTime, - long endTime) { + final String pipeName, + final long creationTime, + final PipeTaskMeta pipeTaskMeta, + final PipePattern pattern, + final long startTime, + final long endTime) { return new PipeTsFileInsertionEvent( resource, isWithMod, isLoaded, isGeneratedByPipe, pipeName, + creationTime, pipeTaskMeta, pattern, startTime, @@ -263,28 +282,31 @@ public boolean mayEventTimeOverlappedWithTimeRange() { : resource.getFileStartTime() <= endTime; } - /////////////////////////// TsFileInsertionEvent /////////////////////////// - @Override - public boolean shouldParseTimeOrPattern() { - boolean shouldParseTimeOrPattern = false; + public boolean mayEventPathsOverlappedWithPattern() { + if (!resource.isClosed()) { + return true; + } + try { - shouldParseTimeOrPattern = super.shouldParseTimeOrPattern(); - return shouldParseTimeOrPattern; - } finally { - // Super method will call shouldParsePattern() and then init dataContainer at - // shouldParsePattern(). If shouldParsePattern() returns false, dataContainer will - // not be used, so we need to close the resource here. - if (!shouldParseTimeOrPattern) { - close(); - } + final Map deviceIsAlignedMap = + PipeResourceManager.tsfile() + .getDeviceIsAlignedMapFromCache( + PipeTsFileResourceManager.getHardlinkOrCopiedFileInPipeDir(resource.getTsFile())); + final Set deviceSet = + Objects.nonNull(deviceIsAlignedMap) ? deviceIsAlignedMap.keySet() : resource.getDevices(); + return deviceSet.stream().anyMatch(pipePattern::mayOverlapWithDevice); + } catch (final IOException e) { + LOGGER.warn( + "Pipe {}: failed to get devices from TsFile {}, extract it anyway", + pipeName, + resource.getTsFilePath(), + e); + return true; } } - @Override - public boolean shouldParsePattern() { - return super.shouldParsePattern() && initDataContainer().shouldParsePattern(); - } + /////////////////////////// TsFileInsertionEvent /////////////////////////// @Override public Iterable toTabletInsertionEvents() { @@ -295,7 +317,7 @@ public Iterable toTabletInsertionEvents() { return Collections.emptyList(); } return initDataContainer().toTabletInsertionEvents(); - } catch (InterruptedException e) { + } catch (final InterruptedException e) { Thread.currentThread().interrupt(); close(); @@ -315,7 +337,7 @@ private TsFileInsertionDataContainer initDataContainer() { tsFile, pipePattern, startTime, endTime, pipeTaskMeta, this); } return dataContainer; - } catch (IOException e) { + } catch (final IOException e) { close(); final String errorMsg = String.format("Read TsFile %s error.", resource.getTsFilePath()); @@ -324,7 +346,7 @@ private TsFileInsertionDataContainer initDataContainer() { } } - public long count(boolean skipReportOnCommit) throws IOException { + public long count(final boolean skipReportOnCommit) throws IOException { long count = 0; if (shouldParseTime()) { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tsfile/TsFileInsertionDataContainer.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tsfile/TsFileInsertionDataContainer.java index ee8c4e62bb81a..f79b95f006747 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tsfile/TsFileInsertionDataContainer.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/common/tsfile/TsFileInsertionDataContainer.java @@ -23,6 +23,7 @@ import org.apache.iotdb.commons.pipe.event.EnrichedEvent; import org.apache.iotdb.commons.pipe.pattern.PipePattern; import org.apache.iotdb.commons.pipe.task.meta.PipeTaskMeta; +import org.apache.iotdb.commons.utils.TestOnly; import org.apache.iotdb.db.pipe.event.common.tablet.PipeRawTabletInsertionEvent; import org.apache.iotdb.db.pipe.resource.PipeResourceManager; import org.apache.iotdb.db.pipe.resource.memory.PipeMemoryBlock; @@ -49,11 +50,13 @@ import java.io.IOException; import java.util.ArrayList; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.NoSuchElementException; import java.util.Objects; +import java.util.Set; public class TsFileInsertionDataContainer implements AutoCloseable { @@ -76,6 +79,7 @@ public class TsFileInsertionDataContainer implements AutoCloseable { private boolean shouldParsePattern = false; + @TestOnly public TsFileInsertionDataContainer( final File tsFile, final PipePattern pattern, final long startTime, final long endTime) throws IOException { @@ -121,15 +125,20 @@ public TsFileInsertionDataContainer( deviceIsAlignedMap = readDeviceIsAlignedMap(); memoryRequiredInBytes += PipeMemoryWeighUtil.memoryOfIDeviceId2Bool(deviceIsAlignedMap); - measurementDataTypeMap = tsFileSequenceReader.getFullPathDataTypeMap(); + // Filter devices that may overlap with pattern first + // to avoid reading all time-series of all devices. + final Set devices = filterDevicesByPattern(deviceIsAlignedMap.keySet()); + + measurementDataTypeMap = readFilteredFullPathDataTypeMap(devices); memoryRequiredInBytes += PipeMemoryWeighUtil.memoryOfStr2TSDataType(measurementDataTypeMap); - deviceMeasurementsMap = tsFileSequenceReader.getDeviceMeasurementsMap(); + deviceMeasurementsMap = readFilteredDeviceMeasurementsMap(devices); memoryRequiredInBytes += PipeMemoryWeighUtil.memoryOfIDeviceID2StrList(deviceMeasurementsMap); } allocatedMemoryBlock = PipeResourceManager.memory().forceAllocate(memoryRequiredInBytes); + // Filter again to get the final deviceMeasurementsMap that exactly matches the pattern. deviceMeasurementsMapIterator = filterDeviceMeasurementsMapByPattern(deviceMeasurementsMap).entrySet().iterator(); @@ -196,6 +205,64 @@ private Map readDeviceIsAlignedMap() throws IOException { return deviceIsAlignedResultMap; } + private Set filterDevicesByPattern(final Set devices) { + if (Objects.isNull(pattern) || pattern.isRoot()) { + return devices; + } + + final Set filteredDevices = new HashSet<>(); + for (final IDeviceID device : devices) { + if (pattern.coversDevice(device) || pattern.mayOverlapWithDevice(device)) { + filteredDevices.add(device); + } + } + return filteredDevices; + } + + /** + * This method is similar to {@link TsFileSequenceReader#getFullPathDataTypeMap()}, but only reads + * the given devices. + */ + private Map readFilteredFullPathDataTypeMap(final Set devices) + throws IOException { + final Map result = new HashMap<>(); + + for (IDeviceID device : devices) { + tsFileSequenceReader + .readDeviceMetadata(device) + .values() + .forEach( + timeseriesMetadata -> + result.put( + device.toString() + "." + timeseriesMetadata.getMeasurementId(), + timeseriesMetadata.getTsDataType())); + } + + return result; + } + + /** + * This method is similar to {@link TsFileSequenceReader#getDeviceMeasurementsMap()}, but only + * reads the given devices. + */ + private Map> readFilteredDeviceMeasurementsMap( + final Set devices) throws IOException { + final Map> result = new HashMap<>(); + + for (IDeviceID device : devices) { + tsFileSequenceReader + .readDeviceMetadata(device) + .values() + .forEach( + timeseriesMetadata -> + result + .computeIfAbsent(device, d -> new ArrayList<>()) + .add(timeseriesMetadata.getMeasurementId())); + } + + return result; + } + /** * @return {@link TabletInsertionEvent} in a streaming way */ @@ -251,6 +318,7 @@ public TabletInsertionEvent next() { tablet, isAligned, sourceEvent != null ? sourceEvent.getPipeName() : null, + sourceEvent != null ? sourceEvent.getCreationTime() : 0, pipeTaskMeta, sourceEvent, true); @@ -261,6 +329,7 @@ public TabletInsertionEvent next() { tablet, isAligned, sourceEvent != null ? sourceEvent.getPipeName() : null, + sourceEvent != null ? sourceEvent.getCreationTime() : 0, pipeTaskMeta, sourceEvent, false); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/realtime/PipeRealtimeEvent.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/realtime/PipeRealtimeEvent.java index 0717dc4d5c3e4..3617b18dcb70b 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/realtime/PipeRealtimeEvent.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/event/realtime/PipeRealtimeEvent.java @@ -60,7 +60,13 @@ public PipeRealtimeEvent( // PipeTaskMeta is used to report the progress of the event, the PipeRealtimeEvent // is only used in the realtime event extractor, which does not need to report the progress // of the event, so the pipeTaskMeta is always null. - super(event != null ? event.getPipeName() : null, pipeTaskMeta, pattern, startTime, endTime); + super( + event != null ? event.getPipeName() : null, + event != null ? event.getCreationTime() : 0, + pipeTaskMeta, + pattern, + startTime, + endTime); this.event = event; this.tsFileEpoch = tsFileEpoch; @@ -125,10 +131,6 @@ public ProgressIndex getProgressIndex() { return event.getProgressIndex(); } - /** - * If pipe's pattern is database-level, then no need to parse event by pattern cause pipes are - * data-region-level. - */ @Override public void skipParsingPattern() { event.skipParsingPattern(); @@ -139,16 +141,37 @@ public void skipParsingTime() { event.skipParsingTime(); } + @Override + public boolean shouldParseTime() { + return event.shouldParseTime(); + } + + @Override + public boolean shouldParsePattern() { + return event.shouldParsePattern(); + } + + @Override + public boolean mayEventTimeOverlappedWithTimeRange() { + return event.mayEventTimeOverlappedWithTimeRange(); + } + + @Override + public boolean mayEventPathsOverlappedWithPattern() { + return event.mayEventPathsOverlappedWithPattern(); + } + @Override public PipeRealtimeEvent shallowCopySelfAndBindPipeTaskMetaForProgressReport( final String pipeName, + final long creationTime, final PipeTaskMeta pipeTaskMeta, final PipePattern pattern, final long startTime, final long endTime) { return new PipeRealtimeEvent( event.shallowCopySelfAndBindPipeTaskMetaForProgressReport( - pipeName, pipeTaskMeta, pattern, startTime, endTime), + pipeName, creationTime, pipeTaskMeta, pattern, startTime, endTime), this.tsFileEpoch, this.device2Measurements, pipeTaskMeta, @@ -162,11 +185,6 @@ public boolean isGeneratedByPipe() { return event.isGeneratedByPipe(); } - @Override - public boolean mayEventTimeOverlappedWithTimeRange() { - return event.mayEventTimeOverlappedWithTimeRange(); - } - @Override public String toString() { return "PipeRealtimeEvent{" diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/execution/PipeConnectorSubtaskExecutor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/execution/PipeConnectorSubtaskExecutor.java index ce832091c1dc4..ea03c8ce4a008 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/execution/PipeConnectorSubtaskExecutor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/execution/PipeConnectorSubtaskExecutor.java @@ -28,10 +28,11 @@ public class PipeConnectorSubtaskExecutor extends PipeSubtaskExecutor { public PipeConnectorSubtaskExecutor() { super( PipeConfig.getInstance().getPipeSubtaskExecutorMaxThreadNum(), - ThreadName.PIPE_CONNECTOR_EXECUTOR_POOL); + ThreadName.PIPE_CONNECTOR_EXECUTOR_POOL, + true); } - public PipeConnectorSubtaskExecutor(int corePoolSize, ThreadName threadName) { - super(corePoolSize, threadName); + public PipeConnectorSubtaskExecutor(final int corePoolSize, final ThreadName threadName) { + super(corePoolSize, threadName, true); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/execution/PipeProcessorSubtaskExecutor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/execution/PipeProcessorSubtaskExecutor.java index a4b36d3664cea..6d5a8ca89fc9f 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/execution/PipeProcessorSubtaskExecutor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/execution/PipeProcessorSubtaskExecutor.java @@ -28,6 +28,7 @@ public class PipeProcessorSubtaskExecutor extends PipeSubtaskExecutor { public PipeProcessorSubtaskExecutor() { super( PipeConfig.getInstance().getPipeSubtaskExecutorMaxThreadNum(), - ThreadName.PIPE_PROCESSOR_EXECUTOR_POOL); + ThreadName.PIPE_PROCESSOR_EXECUTOR_POOL, + false); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/dataregion/historical/PipeHistoricalDataRegionTsFileExtractor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/dataregion/historical/PipeHistoricalDataRegionTsFileExtractor.java index dc86e82e361d6..2da64eb7e1769 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/dataregion/historical/PipeHistoricalDataRegionTsFileExtractor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/dataregion/historical/PipeHistoricalDataRegionTsFileExtractor.java @@ -33,6 +33,7 @@ import org.apache.iotdb.db.pipe.event.common.tsfile.PipeTsFileInsertionEvent; import org.apache.iotdb.db.pipe.extractor.dataregion.DataRegionListeningFilter; import org.apache.iotdb.db.pipe.resource.PipeResourceManager; +import org.apache.iotdb.db.pipe.resource.tsfile.PipeTsFileResourceManager; import org.apache.iotdb.db.storageengine.StorageEngine; import org.apache.iotdb.db.storageengine.dataregion.DataRegion; import org.apache.iotdb.db.storageengine.dataregion.tsfile.TsFileManager; @@ -45,6 +46,7 @@ import org.apache.iotdb.pipe.api.event.Event; import org.apache.iotdb.pipe.api.exception.PipeParameterNotValidException; +import org.apache.tsfile.file.metadata.IDeviceID; import org.apache.tsfile.utils.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -59,13 +61,17 @@ import java.util.Map; import java.util.Objects; import java.util.Queue; +import java.util.Set; import java.util.stream.Collectors; import static org.apache.iotdb.commons.pipe.config.constant.PipeExtractorConstant.EXTRACTOR_END_TIME_KEY; import static org.apache.iotdb.commons.pipe.config.constant.PipeExtractorConstant.EXTRACTOR_HISTORY_ENABLE_DEFAULT_VALUE; import static org.apache.iotdb.commons.pipe.config.constant.PipeExtractorConstant.EXTRACTOR_HISTORY_ENABLE_KEY; import static org.apache.iotdb.commons.pipe.config.constant.PipeExtractorConstant.EXTRACTOR_HISTORY_END_TIME_KEY; +import static org.apache.iotdb.commons.pipe.config.constant.PipeExtractorConstant.EXTRACTOR_HISTORY_LOOSE_RANGE_DEFAULT_VALUE; import static org.apache.iotdb.commons.pipe.config.constant.PipeExtractorConstant.EXTRACTOR_HISTORY_LOOSE_RANGE_KEY; +import static org.apache.iotdb.commons.pipe.config.constant.PipeExtractorConstant.EXTRACTOR_HISTORY_LOOSE_RANGE_PATH_VALUE; +import static org.apache.iotdb.commons.pipe.config.constant.PipeExtractorConstant.EXTRACTOR_HISTORY_LOOSE_RANGE_TIME_VALUE; import static org.apache.iotdb.commons.pipe.config.constant.PipeExtractorConstant.EXTRACTOR_HISTORY_START_TIME_KEY; import static org.apache.iotdb.commons.pipe.config.constant.PipeExtractorConstant.EXTRACTOR_MODS_ENABLE_DEFAULT_VALUE; import static org.apache.iotdb.commons.pipe.config.constant.PipeExtractorConstant.EXTRACTOR_MODS_ENABLE_KEY; @@ -87,6 +93,8 @@ public class PipeHistoricalDataRegionTsFileExtractor implements PipeHistoricalDa private static final long PIPE_MIN_FLUSH_INTERVAL_IN_MS = 2000; private String pipeName; + private long creationTime; + private PipeTaskMeta pipeTaskMeta; private ProgressIndex startIndex; @@ -101,6 +109,7 @@ public class PipeHistoricalDataRegionTsFileExtractor implements PipeHistoricalDa private long historicalDataExtractionTimeLowerBound; // Arrival time private boolean sloppyTimeRange; // true to disable time range filter after extraction + private boolean sloppyPattern; // true to disable pattern filter after extraction private Pair listeningOptionPair; private boolean shouldExtractInsertion; @@ -123,6 +132,26 @@ public void validate(final PipeParameterValidator validator) { throw new PipeParameterNotValidException(e.getMessage()); } + final Set sloppyOptionSet = + Arrays.stream( + parameters + .getStringOrDefault( + Arrays.asList( + EXTRACTOR_HISTORY_LOOSE_RANGE_KEY, SOURCE_HISTORY_LOOSE_RANGE_KEY), + EXTRACTOR_HISTORY_LOOSE_RANGE_DEFAULT_VALUE) + .split(",")) + .map(String::trim) + .filter(s -> !s.isEmpty()) + .map(String::toLowerCase) + .collect(Collectors.toSet()); + sloppyTimeRange = sloppyOptionSet.remove(EXTRACTOR_HISTORY_LOOSE_RANGE_TIME_VALUE); + sloppyPattern = sloppyOptionSet.remove(EXTRACTOR_HISTORY_LOOSE_RANGE_PATH_VALUE); + if (!sloppyOptionSet.isEmpty()) { + throw new PipeParameterNotValidException( + String.format( + "Parameters in set %s are not allowed in 'history.loose-range'", sloppyOptionSet)); + } + if (parameters.hasAnyAttributes( SOURCE_START_TIME_KEY, EXTRACTOR_START_TIME_KEY, @@ -152,6 +181,8 @@ public void validate(final PipeParameterValidator validator) { EXTRACTOR_END_TIME_KEY, historicalDataExtractionEndTime)); } + } catch (final PipeParameterNotValidException e) { + throw e; } catch (final Exception e) { // compatible with the current validation framework throw new PipeParameterNotValidException(e.getMessage()); @@ -221,6 +252,7 @@ public void customize( (PipeTaskExtractorRuntimeEnvironment) configuration.getRuntimeEnvironment(); pipeName = environment.getPipeName(); + creationTime = environment.getCreationTime(); pipeTaskMeta = environment.getPipeTaskMeta(); startIndex = environment.getPipeTaskMeta().getProgressIndex(); @@ -280,19 +312,6 @@ public void customize( } } - sloppyTimeRange = - Arrays.stream( - parameters - .getStringOrDefault( - Arrays.asList( - EXTRACTOR_HISTORY_LOOSE_RANGE_KEY, SOURCE_HISTORY_LOOSE_RANGE_KEY), - "") - .split(",")) - .map(String::trim) - .map(String::toLowerCase) - .collect(Collectors.toSet()) - .contains("time"); - shouldTransferModFile = parameters.getBooleanOrDefault( Arrays.asList(SOURCE_MODS_ENABLE_KEY, EXTRACTOR_MODS_ENABLE_KEY), @@ -309,17 +328,20 @@ public void customize( PipeExtractorConstant.EXTRACTOR_MODE_DEFAULT_VALUE) .equalsIgnoreCase(PipeExtractorConstant.EXTRACTOR_MODE_QUERY_VALUE); - LOGGER.info( - "Pipe {}@{}: historical data extraction time range, start time {}({}), end time {}({}), sloppy time range {}, should transfer mod file {}, should terminate pipe on all historical events consumed {}", - pipeName, - dataRegionId, - DateTimeUtils.convertLongToDate(historicalDataExtractionStartTime), - historicalDataExtractionStartTime, - DateTimeUtils.convertLongToDate(historicalDataExtractionEndTime), - historicalDataExtractionEndTime, - sloppyTimeRange, - shouldTransferModFile, - shouldTerminatePipeOnAllHistoricalEventsConsumed); + if (LOGGER.isInfoEnabled()) { + LOGGER.info( + "Pipe {}@{}: historical data extraction time range, start time {}({}), end time {}({}), sloppy pattern {}, sloppy time range {}, should transfer mod file {}, should terminate pipe on all historical events consumed {}", + pipeName, + dataRegionId, + DateTimeUtils.convertLongToDate(historicalDataExtractionStartTime), + historicalDataExtractionStartTime, + DateTimeUtils.convertLongToDate(historicalDataExtractionEndTime), + historicalDataExtractionEndTime, + sloppyPattern, + sloppyTimeRange, + shouldTransferModFile, + shouldTerminatePipeOnAllHistoricalEventsConsumed); + } } private void flushDataRegionAllTsFiles() { @@ -399,7 +421,8 @@ public synchronized void start() { !resource.isClosed() || mayTsFileContainUnprocessedData(resource) && isTsFileResourceOverlappedWithTimeRange(resource) - && isTsFileGeneratedAfterExtractionTimeLowerBound(resource)) + && isTsFileGeneratedAfterExtractionTimeLowerBound(resource) + && mayTsFileResourceOverlappedWithPattern(resource)) .collect(Collectors.toList()); resourceList.addAll(sequenceTsFileResources); @@ -412,7 +435,8 @@ && isTsFileGeneratedAfterExtractionTimeLowerBound(resource)) !resource.isClosed() || mayTsFileContainUnprocessedData(resource) && isTsFileResourceOverlappedWithTimeRange(resource) - && isTsFileGeneratedAfterExtractionTimeLowerBound(resource)) + && isTsFileGeneratedAfterExtractionTimeLowerBound(resource) + && mayTsFileResourceOverlappedWithPattern(resource)) .collect(Collectors.toList()); resourceList.addAll(unsequenceTsFileResources); @@ -474,6 +498,35 @@ private boolean mayTsFileContainUnprocessedData(final TsFileResource resource) { return !startIndex.isAfter(resource.getMaxProgressIndexAfterClose()); } + private boolean mayTsFileResourceOverlappedWithPattern(final TsFileResource resource) { + if (!sloppyPattern) { + return true; + } + + final Set deviceSet; + try { + final Map deviceIsAlignedMap = + PipeResourceManager.tsfile() + .getDeviceIsAlignedMapFromCache( + PipeTsFileResourceManager.getHardlinkOrCopiedFileInPipeDir(resource.getTsFile())); + deviceSet = + Objects.nonNull(deviceIsAlignedMap) ? deviceIsAlignedMap.keySet() : resource.getDevices(); + } catch (final IOException e) { + LOGGER.warn( + "Pipe {}@{}: failed to get devices from TsFile {}, extract it anyway", + pipeName, + dataRegionId, + resource.getTsFilePath(), + e); + return true; + } + + return deviceSet.stream() + .anyMatch( + // TODO: use IDeviceID + deviceID -> pipePattern.mayOverlapWithDevice(deviceID)); + } + private boolean isTsFileResourceOverlappedWithTimeRange(final TsFileResource resource) { return !(resource.getFileEndTime() < historicalDataExtractionStartTime || historicalDataExtractionEndTime < resource.getFileStartTime()); @@ -513,7 +566,7 @@ public synchronized Event supply() { if (resource == null) { isTerminateSignalSent = true; final PipeTerminateEvent terminateEvent = - new PipeTerminateEvent(pipeName, pipeTaskMeta, dataRegionId); + new PipeTerminateEvent(pipeName, creationTime, pipeTaskMeta, dataRegionId); terminateEvent.increaseReferenceCount( PipeHistoricalDataRegionTsFileExtractor.class.getName()); return terminateEvent; @@ -526,11 +579,12 @@ public synchronized Event supply() { false, false, pipeName, + creationTime, pipeTaskMeta, pipePattern, historicalDataExtractionStartTime, historicalDataExtractionEndTime); - if (isDbNameCoveredByPattern) { + if (sloppyPattern || isDbNameCoveredByPattern) { event.skipParsingPattern(); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/dataregion/realtime/PipeRealtimeDataRegionExtractor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/dataregion/realtime/PipeRealtimeDataRegionExtractor.java index c4bec4246e483..5c976b41a7b20 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/dataregion/realtime/PipeRealtimeDataRegionExtractor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/dataregion/realtime/PipeRealtimeDataRegionExtractor.java @@ -28,7 +28,7 @@ import org.apache.iotdb.commons.pipe.task.connection.UnboundedBlockingPendingQueue; import org.apache.iotdb.commons.pipe.task.meta.PipeTaskMeta; import org.apache.iotdb.commons.utils.TimePartitionUtils; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.event.common.heartbeat.PipeHeartbeatEvent; import org.apache.iotdb.db.pipe.event.realtime.PipeRealtimeEvent; import org.apache.iotdb.db.pipe.extractor.dataregion.DataRegionListeningFilter; @@ -54,6 +54,7 @@ import java.util.Arrays; import java.util.List; import java.util.Objects; +import java.util.Set; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.atomic.AtomicReference; import java.util.stream.Collectors; @@ -61,7 +62,10 @@ import static org.apache.iotdb.commons.pipe.config.constant.PipeExtractorConstant.EXTRACTOR_END_TIME_KEY; import static org.apache.iotdb.commons.pipe.config.constant.PipeExtractorConstant.EXTRACTOR_MODS_ENABLE_DEFAULT_VALUE; import static org.apache.iotdb.commons.pipe.config.constant.PipeExtractorConstant.EXTRACTOR_MODS_ENABLE_KEY; +import static org.apache.iotdb.commons.pipe.config.constant.PipeExtractorConstant.EXTRACTOR_REALTIME_LOOSE_RANGE_DEFAULT_VALUE; import static org.apache.iotdb.commons.pipe.config.constant.PipeExtractorConstant.EXTRACTOR_REALTIME_LOOSE_RANGE_KEY; +import static org.apache.iotdb.commons.pipe.config.constant.PipeExtractorConstant.EXTRACTOR_REALTIME_LOOSE_RANGE_PATH_VALUE; +import static org.apache.iotdb.commons.pipe.config.constant.PipeExtractorConstant.EXTRACTOR_REALTIME_LOOSE_RANGE_TIME_VALUE; import static org.apache.iotdb.commons.pipe.config.constant.PipeExtractorConstant.EXTRACTOR_START_TIME_KEY; import static org.apache.iotdb.commons.pipe.config.constant.PipeExtractorConstant.SOURCE_END_TIME_KEY; import static org.apache.iotdb.commons.pipe.config.constant.PipeExtractorConstant.SOURCE_MODS_ENABLE_KEY; @@ -74,6 +78,7 @@ public abstract class PipeRealtimeDataRegionExtractor implements PipeExtractor { LoggerFactory.getLogger(PipeRealtimeDataRegionExtractor.class); protected String pipeName; + protected long creationTime; protected String dataRegionId; protected PipeTaskMeta pipeTaskMeta; @@ -86,7 +91,7 @@ public abstract class PipeRealtimeDataRegionExtractor implements PipeExtractor { protected long realtimeDataExtractionStartTime = Long.MIN_VALUE; // Event time protected long realtimeDataExtractionEndTime = Long.MAX_VALUE; // Event time - private boolean disableSkippingTimeParse = false; + private boolean disableCheckingDataRegionTimePartitionCovering = false; private long startTimePartitionIdLowerBound; // calculated by realtimeDataExtractionStartTime private long endTimePartitionIdUpperBound; // calculated by realtimeDataExtractionEndTime @@ -101,6 +106,7 @@ public abstract class PipeRealtimeDataRegionExtractor implements PipeExtractor { private boolean shouldTransferModFile; // Whether to transfer mods private boolean sloppyTimeRange; // true to disable time range filter after extraction + private boolean sloppyPattern; // true to disable pattern filter after extraction // This queue is used to store pending events extracted by the method extract(). The method // supply() will poll events from this queue and send them to the next pipe plugin. @@ -141,10 +147,32 @@ public void validate(final PipeParameterValidator validator) throws Exception { EXTRACTOR_END_TIME_KEY, realtimeDataExtractionEndTime)); } + } catch (final PipeParameterNotValidException e) { + throw e; } catch (final Exception e) { // compatible with the current validation framework throw new PipeParameterNotValidException(e.getMessage()); } + + final Set sloppyOptionSet = + Arrays.stream( + parameters + .getStringOrDefault( + Arrays.asList( + EXTRACTOR_REALTIME_LOOSE_RANGE_KEY, SOURCE_REALTIME_LOOSE_RANGE_KEY), + EXTRACTOR_REALTIME_LOOSE_RANGE_DEFAULT_VALUE) + .split(",")) + .map(String::trim) + .filter(s -> !s.isEmpty()) + .map(String::toLowerCase) + .collect(Collectors.toSet()); + sloppyTimeRange = sloppyOptionSet.remove(EXTRACTOR_REALTIME_LOOSE_RANGE_TIME_VALUE); + sloppyPattern = sloppyOptionSet.remove(EXTRACTOR_REALTIME_LOOSE_RANGE_PATH_VALUE); + if (!sloppyOptionSet.isEmpty()) { + throw new PipeParameterNotValidException( + String.format( + "Parameters in set %s are not allowed in 'realtime.loose-range'", sloppyOptionSet)); + } } @Override @@ -167,7 +195,7 @@ public void customize( // indexed by the taskID of IoTDBDataRegionExtractor. To avoid PipeRealtimeDataRegionExtractor // holding a reference to IoTDBDataRegionExtractor, the taskID should be constructed to // match that of IoTDBDataRegionExtractor. - final long creationTime = environment.getCreationTime(); + creationTime = environment.getCreationTime(); taskID = pipeName + "_" + dataRegionId + "_" + creationTime; pipePattern = PipePattern.parsePipePatternFromSourceParameters(parameters); @@ -202,18 +230,13 @@ public void customize( Arrays.asList(SOURCE_MODS_ENABLE_KEY, EXTRACTOR_MODS_ENABLE_KEY), EXTRACTOR_MODS_ENABLE_DEFAULT_VALUE || shouldExtractDeletion); - sloppyTimeRange = - Arrays.stream( - parameters - .getStringOrDefault( - Arrays.asList( - EXTRACTOR_REALTIME_LOOSE_RANGE_KEY, SOURCE_REALTIME_LOOSE_RANGE_KEY), - "") - .split(",")) - .map(String::trim) - .map(String::toLowerCase) - .collect(Collectors.toSet()) - .contains("time"); + if (LOGGER.isInfoEnabled()) { + LOGGER.info( + "Pipe {}@{}: realtime data region extractor is initialized with parameters: {}.", + pipeName, + dataRegionId, + parameters); + } } @Override @@ -261,28 +284,37 @@ public final void extract(final PipeRealtimeEvent event) { event.skipParsingPattern(); } - if (!disableSkippingTimeParse && Objects.nonNull(dataRegionTimePartitionIdBound.get())) { + if (!disableCheckingDataRegionTimePartitionCovering + && Objects.nonNull(dataRegionTimePartitionIdBound.get())) { if (isDataRegionTimePartitionCoveredByTimeRange()) { event.skipParsingTime(); } else { // Since we only record the upper and lower bounds that time partition has ever reached, if // the time partition cannot be covered by the time range during query, it will not be // possible later. - disableSkippingTimeParse = true; + disableCheckingDataRegionTimePartitionCovering = true; } } // 1. Check if time parsing is necessary. If not, it means that the timestamps of the data // contained in this event are definitely within the time range [start time, end time]. - // Otherwise, - // 2. Check if the timestamps of the data contained in this event intersect with the time range. - // If there is no intersection, it indicates that this data will be filtered out by the - // extractor, and the extract process is skipped. - if (!event.shouldParseTime() || event.getEvent().mayEventTimeOverlappedWithTimeRange()) { + // 2. Check if the event's data timestamps may intersect with the time range. If not, it means + // that the data timestamps of this event are definitely not within the time range. + // 3. Check if pattern parsing is necessary. If not, it means that the paths of the data + // contained in this event are definitely covered by the pattern. + // 4. Check if the event's data paths may intersect with the pattern. If not, it means that the + // data of this event is definitely not overlapped with the pattern. + if ((!event.shouldParseTime() || event.getEvent().mayEventTimeOverlappedWithTimeRange()) + && (!event.shouldParsePattern() || event.getEvent().mayEventPathsOverlappedWithPattern())) { if (sloppyTimeRange) { // only skip parsing time for events whose data timestamps may intersect with the time range event.skipParsingTime(); } + if (sloppyPattern) { + // only skip parsing pattern for events whose data paths may intersect with the pattern + event.skipParsingPattern(); + } + doExtract(event); } else { event.decreaseReferenceCount(PipeRealtimeDataRegionExtractor.class.getName(), false); @@ -340,7 +372,8 @@ protected void extractDeletion(final PipeRealtimeEvent event) { + "has reached capacity, discard deletion event %s", this.getClass().getSimpleName(), this, event); LOGGER.error(errorMessage); - PipeAgent.runtime().report(pipeTaskMeta, new PipeRuntimeNonCriticalException(errorMessage)); + PipeDataNodeAgent.runtime() + .report(pipeTaskMeta, new PipeRuntimeNonCriticalException(errorMessage)); // Ignore the event. event.decreaseReferenceCount(PipeRealtimeDataRegionExtractor.class.getName(), false); @@ -378,7 +411,8 @@ protected Event supplyDeletion(final PipeRealtimeEvent event) { + "the data represented by this event is lost", event.getEvent()); LOGGER.error(errorMessage); - PipeAgent.runtime().report(pipeTaskMeta, new PipeRuntimeNonCriticalException(errorMessage)); + PipeDataNodeAgent.runtime() + .report(pipeTaskMeta, new PipeRuntimeNonCriticalException(errorMessage)); return null; } } @@ -387,6 +421,10 @@ public final String getPipeName() { return pipeName; } + public final long getCreationTime() { + return creationTime; + } + public final PipeTaskMeta getPipeTaskMeta() { return pipeTaskMeta; } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/dataregion/realtime/PipeRealtimeDataRegionHybridExtractor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/dataregion/realtime/PipeRealtimeDataRegionHybridExtractor.java index a0f075298a59e..9854fa963a26b 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/dataregion/realtime/PipeRealtimeDataRegionHybridExtractor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/dataregion/realtime/PipeRealtimeDataRegionHybridExtractor.java @@ -22,7 +22,7 @@ import org.apache.iotdb.commons.exception.pipe.PipeRuntimeNonCriticalException; import org.apache.iotdb.commons.pipe.config.PipeConfig; import org.apache.iotdb.db.conf.IoTDBDescriptor; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.event.common.heartbeat.PipeHeartbeatEvent; import org.apache.iotdb.db.pipe.event.common.schema.PipeSchemaRegionWritePlanEvent; import org.apache.iotdb.db.pipe.event.common.tsfile.PipeTsFileInsertionEvent; @@ -113,7 +113,7 @@ private void extractTabletInsertion(final PipeRealtimeEvent event) { + "has reached capacity, discard tablet event %s, current state %s", this, event, event.getTsFileEpoch().getState(this)); LOGGER.error(errorMessage); - PipeAgent.runtime() + PipeDataNodeAgent.runtime() .report(pipeTaskMeta, new PipeRuntimeNonCriticalException(errorMessage)); // Ignore the tablet event. @@ -184,7 +184,7 @@ private void extractTsFileInsertion(final PipeRealtimeEvent event) { + "has reached capacity, discard TsFile event %s, current state %s", this, event, event.getTsFileEpoch().getState(this)); LOGGER.error(errorMessage); - PipeAgent.runtime() + PipeDataNodeAgent.runtime() .report(pipeTaskMeta, new PipeRuntimeNonCriticalException(errorMessage)); // Ignore the tsfile event. @@ -360,7 +360,7 @@ private Event supplyTsFileInsertion(final PipeRealtimeEvent event) { + "the data represented by this event is lost", event.getEvent()); LOGGER.error(errorMessage); - PipeAgent.runtime() + PipeDataNodeAgent.runtime() .report(pipeTaskMeta, new PipeRuntimeNonCriticalException(errorMessage)); return null; } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/dataregion/realtime/PipeRealtimeDataRegionLogExtractor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/dataregion/realtime/PipeRealtimeDataRegionLogExtractor.java index ed1d0f93a8286..40d8616a18135 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/dataregion/realtime/PipeRealtimeDataRegionLogExtractor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/dataregion/realtime/PipeRealtimeDataRegionLogExtractor.java @@ -20,7 +20,7 @@ package org.apache.iotdb.db.pipe.extractor.dataregion.realtime; import org.apache.iotdb.commons.exception.pipe.PipeRuntimeNonCriticalException; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.event.common.heartbeat.PipeHeartbeatEvent; import org.apache.iotdb.db.pipe.event.common.schema.PipeSchemaRegionWritePlanEvent; import org.apache.iotdb.db.pipe.event.common.tsfile.PipeTsFileInsertionEvent; @@ -70,7 +70,8 @@ private void extractTabletInsertion(PipeRealtimeEvent event) { + "has reached capacity, discard tablet event %s, current state %s", this, event, event.getTsFileEpoch().getState(this)); LOGGER.error(errorMessage); - PipeAgent.runtime().report(pipeTaskMeta, new PipeRuntimeNonCriticalException(errorMessage)); + PipeDataNodeAgent.runtime() + .report(pipeTaskMeta, new PipeRuntimeNonCriticalException(errorMessage)); // ignore this event. event.decreaseReferenceCount(PipeRealtimeDataRegionLogExtractor.class.getName(), false); @@ -101,7 +102,8 @@ private void extractTsFileInsertion(PipeRealtimeEvent event) { + "has reached capacity, discard loaded tsFile event %s, current state %s", this, event, event.getTsFileEpoch().getState(this)); LOGGER.error(errorMessage); - PipeAgent.runtime().report(pipeTaskMeta, new PipeRuntimeNonCriticalException(errorMessage)); + PipeDataNodeAgent.runtime() + .report(pipeTaskMeta, new PipeRuntimeNonCriticalException(errorMessage)); // ignore this event. event.decreaseReferenceCount(PipeRealtimeDataRegionLogExtractor.class.getName(), false); @@ -144,7 +146,8 @@ public Event supply() { + "the data represented by this event is lost", realtimeEvent.getEvent()); LOGGER.error(errorMessage); - PipeAgent.runtime().report(pipeTaskMeta, new PipeRuntimeNonCriticalException(errorMessage)); + PipeDataNodeAgent.runtime() + .report(pipeTaskMeta, new PipeRuntimeNonCriticalException(errorMessage)); } realtimeEvent.decreaseReferenceCount( diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/dataregion/realtime/PipeRealtimeDataRegionTsFileExtractor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/dataregion/realtime/PipeRealtimeDataRegionTsFileExtractor.java index ad92796c79177..57e00fa51c1a1 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/dataregion/realtime/PipeRealtimeDataRegionTsFileExtractor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/dataregion/realtime/PipeRealtimeDataRegionTsFileExtractor.java @@ -20,7 +20,7 @@ package org.apache.iotdb.db.pipe.extractor.dataregion.realtime; import org.apache.iotdb.commons.exception.pipe.PipeRuntimeNonCriticalException; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.event.common.heartbeat.PipeHeartbeatEvent; import org.apache.iotdb.db.pipe.event.common.schema.PipeSchemaRegionWritePlanEvent; import org.apache.iotdb.db.pipe.event.realtime.PipeRealtimeEvent; @@ -64,7 +64,8 @@ protected void doExtract(PipeRealtimeEvent event) { + "has reached capacity, discard TsFile event %s, current state %s", this, event, event.getTsFileEpoch().getState(this)); LOGGER.error(errorMessage); - PipeAgent.runtime().report(pipeTaskMeta, new PipeRuntimeNonCriticalException(errorMessage)); + PipeDataNodeAgent.runtime() + .report(pipeTaskMeta, new PipeRuntimeNonCriticalException(errorMessage)); // Ignore the event. event.decreaseReferenceCount(PipeRealtimeDataRegionTsFileExtractor.class.getName(), false); @@ -106,7 +107,8 @@ public Event supply() { + "the data represented by this event is lost", realtimeEvent.getEvent()); LOGGER.error(errorMessage); - PipeAgent.runtime().report(pipeTaskMeta, new PipeRuntimeNonCriticalException(errorMessage)); + PipeDataNodeAgent.runtime() + .report(pipeTaskMeta, new PipeRuntimeNonCriticalException(errorMessage)); } realtimeEvent.decreaseReferenceCount( diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/dataregion/realtime/assigner/PipeDataRegionAssigner.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/dataregion/realtime/assigner/PipeDataRegionAssigner.java index e85fd5b0a1d15..16f9ebf61d922 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/dataregion/realtime/assigner/PipeDataRegionAssigner.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/dataregion/realtime/assigner/PipeDataRegionAssigner.java @@ -76,6 +76,7 @@ public void assignToExtractor(PipeRealtimeEvent event, long sequence, boolean en final PipeRealtimeEvent copiedEvent = event.shallowCopySelfAndBindPipeTaskMetaForProgressReport( extractor.getPipeName(), + extractor.getCreationTime(), extractor.getPipeTaskMeta(), extractor.getPipePattern(), extractor.getRealtimeDataExtractionStartTime(), @@ -90,7 +91,6 @@ public void assignToExtractor(PipeRealtimeEvent event, long sequence, boolean en extractor.extract(copiedEvent); if (innerEvent instanceof PipeHeartbeatEvent) { - ((PipeHeartbeatEvent) innerEvent).bindPipeName(extractor.getPipeName()); ((PipeHeartbeatEvent) innerEvent).onAssigned(); } }); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/dataregion/realtime/listener/PipeInsertionDataNodeListener.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/dataregion/realtime/listener/PipeInsertionDataNodeListener.java index 1b6282cac9844..3eb118701a78e 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/dataregion/realtime/listener/PipeInsertionDataNodeListener.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/dataregion/realtime/listener/PipeInsertionDataNodeListener.java @@ -20,7 +20,7 @@ package org.apache.iotdb.db.pipe.extractor.dataregion.realtime.listener; import org.apache.iotdb.commons.pipe.config.PipeConfig; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.event.realtime.PipeRealtimeEventFactory; import org.apache.iotdb.db.pipe.extractor.dataregion.realtime.PipeRealtimeDataRegionExtractor; import org.apache.iotdb.db.pipe.extractor.dataregion.realtime.assigner.PipeDataRegionAssigner; @@ -149,7 +149,7 @@ public void listenToDeleteData(DeleteDataNode node) { /////////////////////////////// singleton /////////////////////////////// private PipeInsertionDataNodeListener() { - PipeAgent.runtime() + PipeDataNodeAgent.runtime() .registerPeriodicalJob( "PipeInsertionDataNodeListener#listenToHeartbeat(false)", () -> listenToHeartbeat(false), diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/schemaregion/IoTDBSchemaRegionExtractor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/schemaregion/IoTDBSchemaRegionExtractor.java index 3682095999b39..209593979c410 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/schemaregion/IoTDBSchemaRegionExtractor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/extractor/schemaregion/IoTDBSchemaRegionExtractor.java @@ -29,7 +29,7 @@ import org.apache.iotdb.consensus.exception.ConsensusException; import org.apache.iotdb.db.conf.IoTDBDescriptor; import org.apache.iotdb.db.consensus.SchemaRegionConsensusImpl; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.event.common.schema.PipeSchemaRegionSnapshotEvent; import org.apache.iotdb.db.pipe.event.common.schema.PipeSchemaRegionWritePlanEvent; import org.apache.iotdb.db.pipe.metric.PipeDataNodeRemainingEventAndTimeMetrics; @@ -81,14 +81,15 @@ public void customize( @Override public void start() throws Exception { // Delay the start process to schema region leader ready - if (!PipeAgent.runtime().isSchemaLeaderReady(schemaRegionId) + if (!PipeDataNodeAgent.runtime().isSchemaLeaderReady(schemaRegionId) || hasBeenStarted.get() || hasBeenClosed.get()) { return; } // Try open the queue if it is the first task - if (PipeAgent.runtime().increaseAndGetSchemaListenerReferenceCount(schemaRegionId) == 1) { + if (PipeDataNodeAgent.runtime().increaseAndGetSchemaListenerReferenceCount(schemaRegionId) + == 1) { SchemaRegionConsensusImpl.getInstance() .write(schemaRegionId, new PipeOperateSchemaQueueNode(new PlanNodeId(""), true)); } @@ -113,7 +114,7 @@ protected void triggerSnapshot() { // This method will return events only after schema region leader gets ready @Override public synchronized EnrichedEvent supply() throws Exception { - return PipeAgent.runtime().isSchemaLeaderReady(schemaRegionId) ? super.supply() : null; + return PipeDataNodeAgent.runtime().isSchemaLeaderReady(schemaRegionId) ? super.supply() : null; } @Override @@ -133,7 +134,7 @@ protected Optional trimRealtimeEventByPipePattern( @Override protected AbstractPipeListeningQueue getListeningQueue() { - return PipeAgent.runtime().schemaListener(schemaRegionId); + return PipeDataNodeAgent.runtime().schemaListener(schemaRegionId); } @Override @@ -166,7 +167,7 @@ public synchronized void close() throws Exception { if (!listenedTypeSet.isEmpty()) { // The queue is not closed here, and is closed iff the PipeMetaKeeper // has no schema pipe after one successful sync - PipeAgent.runtime().decreaseAndGetSchemaListenerReferenceCount(schemaRegionId); + PipeDataNodeAgent.runtime().decreaseAndGetSchemaListenerReferenceCount(schemaRegionId); } if (Objects.nonNull(taskID)) { PipeSchemaRegionExtractorMetrics.getInstance().deregister(taskID); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/metric/PipeDataNodeRemainingEventAndTimeMetrics.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/metric/PipeDataNodeRemainingEventAndTimeMetrics.java index c1ecb8460b4d0..cff505d444e00 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/metric/PipeDataNodeRemainingEventAndTimeMetrics.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/metric/PipeDataNodeRemainingEventAndTimeMetrics.java @@ -19,17 +19,13 @@ package org.apache.iotdb.db.pipe.metric; -import org.apache.iotdb.commons.consensus.DataRegionId; -import org.apache.iotdb.commons.consensus.SchemaRegionId; -import org.apache.iotdb.commons.pipe.config.plugin.env.PipeTaskRuntimeEnvironment; import org.apache.iotdb.commons.pipe.progress.PipeEventCommitManager; import org.apache.iotdb.commons.service.metric.enums.Metric; import org.apache.iotdb.commons.service.metric.enums.Tag; import org.apache.iotdb.db.pipe.extractor.dataregion.IoTDBDataRegionExtractor; import org.apache.iotdb.db.pipe.extractor.schemaregion.IoTDBSchemaRegionExtractor; import org.apache.iotdb.db.pipe.task.subtask.connector.PipeConnectorSubtask; -import org.apache.iotdb.db.schemaengine.SchemaEngine; -import org.apache.iotdb.db.storageengine.StorageEngine; +import org.apache.iotdb.db.pipe.task.subtask.processor.PipeProcessorSubtask; import org.apache.iotdb.metrics.AbstractMetricService; import org.apache.iotdb.metrics.metricsets.IMetricSet; import org.apache.iotdb.metrics.utils.MetricLevel; @@ -128,6 +124,17 @@ public void register(final IoTDBDataRegionExtractor extractor) { } } + public void register(final PipeProcessorSubtask processorSubtask) { + // The metric is global thus the regionId is omitted + final String pipeID = processorSubtask.getPipeName() + "_" + processorSubtask.getCreationTime(); + remainingEventAndTimeOperatorMap + .computeIfAbsent(pipeID, k -> new PipeDataNodeRemainingEventAndTimeOperator()) + .register(processorSubtask); + if (Objects.nonNull(metricService)) { + createMetrics(pipeID); + } + } + public void register( final PipeConnectorSubtask connectorSubtask, final String pipeName, final long creationTime) { // The metric is global thus the regionId is omitted @@ -151,6 +158,26 @@ public void register(final IoTDBSchemaRegionExtractor extractor) { } } + public void thawRate(final String pipeID) { + if (!remainingEventAndTimeOperatorMap.containsKey(pipeID)) { + // In dataNode, the "thawRate" may be called when there are no subtasks, and we call + // "startPipe". + // We thaw it later in "startPipeTask". + return; + } + remainingEventAndTimeOperatorMap.get(pipeID).thawRate(true); + } + + public void freezeRate(final String pipeID) { + if (!remainingEventAndTimeOperatorMap.containsKey(pipeID)) { + // In dataNode, the "freezeRate" may be called when there are no subtasks, and we call + // "stopPipe" after calling "startPipe". + // We do nothing because in that case the rate is not thawed initially + return; + } + remainingEventAndTimeOperatorMap.get(pipeID).freezeRate(true); + } + public void deregister(final String pipeID) { if (!remainingEventAndTimeOperatorMap.containsKey(pipeID)) { LOGGER.warn( @@ -163,13 +190,7 @@ public void deregister(final String pipeID) { } } - public void markRegionCommit(final PipeTaskRuntimeEnvironment pipeTaskRuntimeEnvironment) { - // Filter commit attempt from assigner - final String pipeName = pipeTaskRuntimeEnvironment.getPipeName(); - final int regionId = pipeTaskRuntimeEnvironment.getRegionId(); - final long creationTime = pipeTaskRuntimeEnvironment.getCreationTime(); - final String pipeID = pipeName + "_" + creationTime; - + public void markRegionCommit(final String pipeID, final boolean isDataRegion) { if (Objects.isNull(metricService)) { return; } @@ -181,19 +202,10 @@ public void markRegionCommit(final PipeTaskRuntimeEnvironment pipeTaskRuntimeEnv pipeID); return; } - // Prevent not set pipeName / creation times & potential differences between pipeNames and - // creation times - if (!Objects.equals(pipeName, operator.getPipeName()) - || !Objects.equals(creationTime, operator.getCreationTime())) { - return; - } - // Prevent empty region-ids - if (StorageEngine.getInstance().getAllDataRegionIds().contains(new DataRegionId(regionId))) { + if (isDataRegion) { operator.markDataRegionCommit(); - } - - if (SchemaEngine.getInstance().getAllSchemaRegionIds().contains(new SchemaRegionId(regionId))) { + } else { operator.markSchemaRegionCommit(); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/metric/PipeDataNodeRemainingEventAndTimeOperator.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/metric/PipeDataNodeRemainingEventAndTimeOperator.java index f7a08295f408d..8963c7019c29c 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/metric/PipeDataNodeRemainingEventAndTimeOperator.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/metric/PipeDataNodeRemainingEventAndTimeOperator.java @@ -19,61 +19,56 @@ package org.apache.iotdb.db.pipe.metric; +import org.apache.iotdb.commons.enums.PipeRemainingTimeRateAverageTime; import org.apache.iotdb.commons.pipe.config.PipeConfig; +import org.apache.iotdb.commons.pipe.metric.PipeRemainingOperator; import org.apache.iotdb.db.pipe.extractor.dataregion.IoTDBDataRegionExtractor; import org.apache.iotdb.db.pipe.extractor.schemaregion.IoTDBSchemaRegionExtractor; import org.apache.iotdb.db.pipe.task.subtask.connector.PipeConnectorSubtask; +import org.apache.iotdb.db.pipe.task.subtask.processor.PipeProcessorSubtask; +import org.apache.iotdb.pipe.api.event.Event; import com.codahale.metrics.Clock; import com.codahale.metrics.ExponentialMovingAverages; import com.codahale.metrics.Meter; +import java.util.Collections; +import java.util.Objects; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; - -class PipeDataNodeRemainingEventAndTimeOperator { - - private static final long DATA_NODE_REMAINING_MAX_SECONDS = 365 * 24 * 60 * 60L; // 1 year - - private String pipeName; - private long creationTime = 0; - - private final ConcurrentMap - dataRegionExtractors = new ConcurrentHashMap<>(); - private final ConcurrentMap dataRegionConnectors = - new ConcurrentHashMap<>(); - private final ConcurrentMap - schemaRegionExtractors = new ConcurrentHashMap<>(); - private final Meter dataRegionCommitMeter = - new Meter(new ExponentialMovingAverages(), Clock.defaultClock()); - private final Meter schemaRegionCommitMeter = - new Meter(new ExponentialMovingAverages(), Clock.defaultClock()); - - private double lastDataRegionCommitSmoothingValue = Long.MIN_VALUE; - private double lastSchemaRegionCommitSmoothingValue = Long.MIN_VALUE; - - //////////////////////////// Tags //////////////////////////// - - String getPipeName() { - return pipeName; - } - - long getCreationTime() { - return creationTime; - } +import java.util.concurrent.atomic.AtomicReference; + +class PipeDataNodeRemainingEventAndTimeOperator extends PipeRemainingOperator { + private final Set dataRegionExtractors = + Collections.newSetFromMap(new ConcurrentHashMap<>()); + private final Set dataRegionProcessors = + Collections.newSetFromMap(new ConcurrentHashMap<>()); + private final Set dataRegionConnectors = + Collections.newSetFromMap(new ConcurrentHashMap<>()); + private final Set schemaRegionExtractors = + Collections.newSetFromMap(new ConcurrentHashMap<>()); + private final AtomicReference dataRegionCommitMeter = new AtomicReference<>(null); + private final AtomicReference schemaRegionCommitMeter = new AtomicReference<>(null); + + private double lastDataRegionCommitSmoothingValue = Long.MAX_VALUE; + private double lastSchemaRegionCommitSmoothingValue = Long.MAX_VALUE; //////////////////////////// Remaining event & time calculation //////////////////////////// long getRemainingEvents() { - return dataRegionExtractors.keySet().stream() + return dataRegionExtractors.stream() .map(IoTDBDataRegionExtractor::getEventCount) .reduce(Integer::sum) .orElse(0) - + dataRegionConnectors.keySet().stream() + + dataRegionProcessors.stream() + .map(processorSubtask -> processorSubtask.getEventCount(false)) + .reduce(Integer::sum) + .orElse(0) + + dataRegionConnectors.stream() .map(connectorSubtask -> connectorSubtask.getEventCount(pipeName)) .reduce(Integer::sum) .orElse(0) - + schemaRegionExtractors.keySet().stream() + + schemaRegionExtractors.stream() .map(IoTDBSchemaRegionExtractor::getUnTransferredEventCount) .reduce(Long::sum) .orElse(0L); @@ -82,39 +77,45 @@ long getRemainingEvents() { /** * This will calculate the estimated remaining time of pipe. * - *

Note: The events in pipe assigner are omitted. + *

Note: The {@link Event}s in pipe assigner are omitted. * * @return The estimated remaining time */ double getRemainingTime() { - final double pipeRemainingTimeCommitRateSmoothingFactor = - PipeConfig.getInstance().getPipeRemainingTimeCommitRateSmoothingFactor(); + final PipeRemainingTimeRateAverageTime pipeRemainingTimeCommitRateAverageTime = + PipeConfig.getInstance().getPipeRemainingTimeCommitRateAverageTime(); // Do not take heartbeat event into account final int totalDataRegionWriteEventCount = - dataRegionExtractors.keySet().stream() + dataRegionExtractors.stream() .map(IoTDBDataRegionExtractor::getEventCount) .reduce(Integer::sum) .orElse(0) - + dataRegionConnectors.keySet().stream() + + dataRegionProcessors.stream() + .map(processorSubtask -> processorSubtask.getEventCount(true)) + .reduce(Integer::sum) + .orElse(0) + + dataRegionConnectors.stream() .map(connectorSubtask -> connectorSubtask.getEventCount(pipeName)) .reduce(Integer::sum) .orElse(0) - - dataRegionExtractors.keySet().stream() + - dataRegionExtractors.stream() .map(IoTDBDataRegionExtractor::getPipeHeartbeatEventCount) .reduce(Integer::sum) .orElse(0) - - dataRegionConnectors.keySet().stream() + - dataRegionConnectors.stream() .map(PipeConnectorSubtask::getPipeHeartbeatEventCount) .reduce(Integer::sum) .orElse(0); - lastDataRegionCommitSmoothingValue = - lastDataRegionCommitSmoothingValue == Long.MIN_VALUE - ? dataRegionCommitMeter.getOneMinuteRate() - : pipeRemainingTimeCommitRateSmoothingFactor * dataRegionCommitMeter.getOneMinuteRate() - + (1 - pipeRemainingTimeCommitRateSmoothingFactor) - * lastDataRegionCommitSmoothingValue; + dataRegionCommitMeter.updateAndGet( + meter -> { + if (Objects.nonNull(meter)) { + lastDataRegionCommitSmoothingValue = + pipeRemainingTimeCommitRateAverageTime.getMeterRate(meter); + } + return meter; + }); final double dataRegionRemainingTime; if (totalDataRegionWriteEventCount <= 0) { dataRegionRemainingTime = 0; @@ -126,18 +127,19 @@ long getRemainingEvents() { } final long totalSchemaRegionWriteEventCount = - schemaRegionExtractors.keySet().stream() + schemaRegionExtractors.stream() .map(IoTDBSchemaRegionExtractor::getUnTransferredEventCount) .reduce(Long::sum) .orElse(0L); - lastSchemaRegionCommitSmoothingValue = - lastSchemaRegionCommitSmoothingValue == Long.MIN_VALUE - ? schemaRegionCommitMeter.getOneMinuteRate() - : pipeRemainingTimeCommitRateSmoothingFactor - * schemaRegionCommitMeter.getOneMinuteRate() - + (1 - pipeRemainingTimeCommitRateSmoothingFactor) - * lastSchemaRegionCommitSmoothingValue; + schemaRegionCommitMeter.updateAndGet( + meter -> { + if (Objects.nonNull(meter)) { + lastSchemaRegionCommitSmoothingValue = + pipeRemainingTimeCommitRateAverageTime.getMeterRate(meter); + } + return meter; + }); final double schemaRegionRemainingTime; if (totalSchemaRegionWriteEventCount <= 0) { schemaRegionRemainingTime = 0; @@ -148,40 +150,82 @@ long getRemainingEvents() { : totalSchemaRegionWriteEventCount / lastSchemaRegionCommitSmoothingValue; } + if (totalDataRegionWriteEventCount + totalSchemaRegionWriteEventCount == 0) { + notifyEmpty(); + } else { + notifyNonEmpty(); + } + final double result = Math.max(dataRegionRemainingTime, schemaRegionRemainingTime); - return result >= DATA_NODE_REMAINING_MAX_SECONDS ? DATA_NODE_REMAINING_MAX_SECONDS : result; + return result >= REMAINING_MAX_SECONDS ? REMAINING_MAX_SECONDS : result; } //////////////////////////// Register & deregister (pipe integration) //////////////////////////// void register(final IoTDBDataRegionExtractor extractor) { setNameAndCreationTime(extractor.getPipeName(), extractor.getCreationTime()); - dataRegionExtractors.put(extractor, extractor); + dataRegionExtractors.add(extractor); + } + + void register(final PipeProcessorSubtask processorSubtask) { + setNameAndCreationTime(processorSubtask.getPipeName(), processorSubtask.getCreationTime()); + dataRegionProcessors.add(processorSubtask); } void register( final PipeConnectorSubtask connectorSubtask, final String pipeName, final long creationTime) { setNameAndCreationTime(pipeName, creationTime); - dataRegionConnectors.put(connectorSubtask, connectorSubtask); + dataRegionConnectors.add(connectorSubtask); } void register(final IoTDBSchemaRegionExtractor extractor) { setNameAndCreationTime(extractor.getPipeName(), extractor.getCreationTime()); - schemaRegionExtractors.put(extractor, extractor); - } - - private void setNameAndCreationTime(final String pipeName, final long creationTime) { - this.pipeName = pipeName; - this.creationTime = creationTime; + schemaRegionExtractors.add(extractor); } //////////////////////////// Rate //////////////////////////// void markDataRegionCommit() { - dataRegionCommitMeter.mark(); + dataRegionCommitMeter.updateAndGet( + meter -> { + if (Objects.nonNull(meter)) { + meter.mark(); + } + return meter; + }); } void markSchemaRegionCommit() { - schemaRegionCommitMeter.mark(); + schemaRegionCommitMeter.updateAndGet( + meter -> { + if (Objects.nonNull(meter)) { + meter.mark(); + } + return meter; + }); + } + + //////////////////////////// Switch //////////////////////////// + + // Thread-safe & Idempotent + @Override + public synchronized void thawRate(final boolean isStartPipe) { + super.thawRate(isStartPipe); + // The stopped pipe's rate should only be thawed by "startPipe" command + if (isStopped) { + return; + } + dataRegionCommitMeter.compareAndSet( + null, new Meter(new ExponentialMovingAverages(), Clock.defaultClock())); + schemaRegionCommitMeter.compareAndSet( + null, new Meter(new ExponentialMovingAverages(), Clock.defaultClock())); + } + + // Thread-safe & Idempotent + @Override + public synchronized void freezeRate(final boolean isStopPipe) { + super.freezeRate(isStopPipe); + dataRegionCommitMeter.set(null); + schemaRegionCommitMeter.set(null); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/metric/PipeDataRegionConnectorMetrics.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/metric/PipeDataRegionConnectorMetrics.java index ef41dd993f717..f467cac20bdfd 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/metric/PipeDataRegionConnectorMetrics.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/metric/PipeDataRegionConnectorMetrics.java @@ -280,7 +280,7 @@ public void markTabletEvent(final String taskID) { } final Rate rate = tabletRateMap.get(taskID); if (rate == null) { - LOGGER.warn( + LOGGER.info( "Failed to mark pipe data region connector tablet event, PipeConnectorSubtask({}) does not exist", taskID); return; @@ -294,7 +294,7 @@ public void markTsFileEvent(final String taskID) { } final Rate rate = tsFileRateMap.get(taskID); if (rate == null) { - LOGGER.warn( + LOGGER.info( "Failed to mark pipe data region connector tsfile event, PipeConnectorSubtask({}) does not exist", taskID); return; diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/metric/PipeDataRegionEventCounter.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/metric/PipeDataRegionEventCounter.java index 0e1aa557ec06c..0aed61801ef9d 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/metric/PipeDataRegionEventCounter.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/metric/PipeDataRegionEventCounter.java @@ -21,6 +21,7 @@ import org.apache.iotdb.commons.pipe.metric.PipeEventCounter; import org.apache.iotdb.db.pipe.event.common.heartbeat.PipeHeartbeatEvent; +import org.apache.iotdb.db.pipe.event.realtime.PipeRealtimeEvent; import org.apache.iotdb.pipe.api.event.Event; import org.apache.iotdb.pipe.api.event.dml.insertion.TabletInsertionEvent; import org.apache.iotdb.pipe.api.event.dml.insertion.TsFileInsertionEvent; @@ -51,6 +52,9 @@ public Integer getPipeHeartbeatEventCount() { @Override public void increaseEventCount(Event event) { + if (event instanceof PipeRealtimeEvent) { + event = ((PipeRealtimeEvent) event).getEvent(); + } if (Objects.isNull(event)) { return; } @@ -65,6 +69,9 @@ public void increaseEventCount(Event event) { @Override public void decreaseEventCount(Event event) { + if (event instanceof PipeRealtimeEvent) { + event = ((PipeRealtimeEvent) event).getEvent(); + } if (Objects.isNull(event)) { return; } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/metric/PipeDataRegionExtractorMetrics.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/metric/PipeDataRegionExtractorMetrics.java index 6382297d71fc0..d18b4de51e493 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/metric/PipeDataRegionExtractorMetrics.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/metric/PipeDataRegionExtractorMetrics.java @@ -316,7 +316,7 @@ public void markTabletEvent(final String taskID) { } final Rate rate = tabletRateMap.get(taskID); if (rate == null) { - LOGGER.warn( + LOGGER.info( "Failed to mark pipe data region extractor tablet event, IoTDBDataRegionExtractor({}) does not exist", taskID); return; @@ -330,7 +330,7 @@ public void markTsFileEvent(final String taskID) { } final Rate rate = tsFileRateMap.get(taskID); if (rate == null) { - LOGGER.warn( + LOGGER.info( "Failed to mark pipe data region extractor tsfile event, IoTDBDataRegionExtractor({}) does not exist", taskID); return; @@ -344,7 +344,7 @@ public void markPipeHeartbeatEvent(final String taskID) { } final Rate rate = pipeHeartbeatRateMap.get(taskID); if (rate == null) { - LOGGER.warn( + LOGGER.info( "Failed to mark pipe data region extractor heartbeat event, IoTDBDataRegionExtractor({}) does not exist", taskID); return; @@ -359,7 +359,7 @@ public void setRecentProcessedTsFileEpochState( } final Gauge gauge = recentProcessedTsFileEpochStateMap.get(taskID); if (gauge == null) { - LOGGER.warn( + LOGGER.info( "Failed to set recent processed tsfile epoch state, PipeRealtimeDataRegionExtractor({}) does not exist", taskID); return; diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/metric/PipeProcessorMetrics.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/metric/PipeProcessorMetrics.java index 8cc2383c847f5..7f6697430bd5e 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/metric/PipeProcessorMetrics.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/metric/PipeProcessorMetrics.java @@ -55,20 +55,20 @@ public class PipeProcessorMetrics implements IMetricSet { //////////////////////////// bindTo & unbindFrom (metric framework) //////////////////////////// @Override - public void bindTo(AbstractMetricService metricService) { + public void bindTo(final AbstractMetricService metricService) { this.metricService = metricService; - ImmutableSet taskIDs = ImmutableSet.copyOf(processorMap.keySet()); - for (String taskID : taskIDs) { + final ImmutableSet taskIDs = ImmutableSet.copyOf(processorMap.keySet()); + for (final String taskID : taskIDs) { createMetrics(taskID); } } - private void createMetrics(String taskID) { + private void createMetrics(final String taskID) { createRate(taskID); } - private void createRate(String taskID) { - PipeProcessorSubtask processor = processorMap.get(taskID); + private void createRate(final String taskID) { + final PipeProcessorSubtask processor = processorMap.get(taskID); // process event rate tabletRateMap.put( taskID, @@ -106,9 +106,9 @@ private void createRate(String taskID) { } @Override - public void unbindFrom(AbstractMetricService metricService) { - ImmutableSet taskIDs = ImmutableSet.copyOf(processorMap.keySet()); - for (String taskID : taskIDs) { + public void unbindFrom(final AbstractMetricService metricService) { + final ImmutableSet taskIDs = ImmutableSet.copyOf(processorMap.keySet()); + for (final String taskID : taskIDs) { deregister(taskID); } if (!processorMap.isEmpty()) { @@ -116,12 +116,12 @@ public void unbindFrom(AbstractMetricService metricService) { } } - private void removeMetrics(String taskID) { + private void removeMetrics(final String taskID) { removeAutoGauge(taskID); removeRate(taskID); } - private void removeAutoGauge(String taskID) { + private void removeAutoGauge(final String taskID) { PipeProcessorSubtask processor = processorMap.get(taskID); // pending event count metricService.remove( @@ -153,7 +153,7 @@ private void removeAutoGauge(String taskID) { String.valueOf(processor.getCreationTime())); } - private void removeRate(String taskID) { + private void removeRate(final String taskID) { PipeProcessorSubtask processor = processorMap.get(taskID); // process event rate metricService.remove( @@ -190,15 +190,15 @@ private void removeRate(String taskID) { //////////////////////////// register & deregister (pipe integration) //////////////////////////// - public void register(@NonNull PipeProcessorSubtask pipeProcessorSubtask) { - String taskID = pipeProcessorSubtask.getTaskID(); + public void register(@NonNull final PipeProcessorSubtask pipeProcessorSubtask) { + final String taskID = pipeProcessorSubtask.getTaskID(); processorMap.putIfAbsent(taskID, pipeProcessorSubtask); if (Objects.nonNull(metricService)) { createMetrics(taskID); } } - public void deregister(String taskID) { + public void deregister(final String taskID) { if (!processorMap.containsKey(taskID)) { LOGGER.warn( "Failed to deregister pipe processor metrics, PipeProcessorSubtask({}) does not exist", @@ -211,13 +211,13 @@ public void deregister(String taskID) { processorMap.remove(taskID); } - public void markTabletEvent(String taskID) { + public void markTabletEvent(final String taskID) { if (Objects.isNull(metricService)) { return; } - Rate rate = tabletRateMap.get(taskID); + final Rate rate = tabletRateMap.get(taskID); if (rate == null) { - LOGGER.warn( + LOGGER.info( "Failed to mark pipe processor tablet event, PipeProcessorSubtask({}) does not exist", taskID); return; @@ -225,13 +225,13 @@ public void markTabletEvent(String taskID) { rate.mark(); } - public void markTsFileEvent(String taskID) { + public void markTsFileEvent(final String taskID) { if (Objects.isNull(metricService)) { return; } - Rate rate = tsFileRateMap.get(taskID); + final Rate rate = tsFileRateMap.get(taskID); if (rate == null) { - LOGGER.warn( + LOGGER.info( "Failed to mark pipe processor tsfile event, PipeProcessorSubtask({}) does not exist", taskID); return; @@ -239,13 +239,13 @@ public void markTsFileEvent(String taskID) { rate.mark(); } - public void markPipeHeartbeatEvent(String taskID) { + public void markPipeHeartbeatEvent(final String taskID) { if (Objects.isNull(metricService)) { return; } - Rate rate = pipeHeartbeatRateMap.get(taskID); + final Rate rate = pipeHeartbeatRateMap.get(taskID); if (rate == null) { - LOGGER.warn( + LOGGER.info( "Failed to mark pipe processor heartbeat event, PipeProcessorSubtask({}) does not exist", taskID); return; diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/metric/PipeSchemaRegionConnectorMetrics.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/metric/PipeSchemaRegionConnectorMetrics.java index 52553c4ebb229..e3062c9bd7835 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/metric/PipeSchemaRegionConnectorMetrics.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/metric/PipeSchemaRegionConnectorMetrics.java @@ -129,7 +129,7 @@ public void markSchemaEvent(final String taskID) { } final Rate rate = schemaRateMap.get(taskID); if (rate == null) { - LOGGER.warn( + LOGGER.info( "Failed to mark pipe schema region write plan event, PipeConnectorSubtask({}) does not exist", taskID); return; diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/AggregateProcessor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/AggregateProcessor.java index dde1fab5a2802..3e6ed81f7136a 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/AggregateProcessor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/AggregateProcessor.java @@ -29,7 +29,7 @@ import org.apache.iotdb.commons.pipe.event.EnrichedEvent; import org.apache.iotdb.commons.pipe.task.meta.PipeTaskMeta; import org.apache.iotdb.commons.utils.PathUtils; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.agent.plugin.dataregion.PipeDataRegionPluginAgent; import org.apache.iotdb.db.pipe.event.common.row.PipeResetTabletRow; import org.apache.iotdb.db.pipe.event.common.row.PipeRow; @@ -56,14 +56,17 @@ import org.apache.iotdb.pipe.api.event.dml.insertion.TsFileInsertionEvent; import org.apache.iotdb.pipe.api.exception.PipeException; +import org.apache.tsfile.common.conf.TSFileConfig; import org.apache.tsfile.common.constant.TsFileConstant; import org.apache.tsfile.enums.TSDataType; +import org.apache.tsfile.utils.Binary; import org.apache.tsfile.utils.BitMap; import org.apache.tsfile.utils.Pair; import org.apache.tsfile.write.schema.MeasurementSchema; import java.io.IOException; import java.nio.ByteBuffer; +import java.time.LocalDate; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -247,7 +250,7 @@ public void customize( // Load the useful aggregators' and their corresponding intermediate results' computational // logic. final Set declaredIntermediateResultSet = new HashSet<>(); - final PipeDataRegionPluginAgent agent = PipeAgent.plugin().dataRegion(); + final PipeDataRegionPluginAgent agent = PipeDataNodeAgent.plugin().dataRegion(); for (final String pipePluginName : agent.getSubProcessorNamesWithSpecifiedParent(AbstractOperatorProcessor.class)) { // Children are allowed to validate and configure the computational logic @@ -450,7 +453,13 @@ private Map> processRow( state.updateWindows( timestamp, row.getInt(index), outputMinReportIntervalMilliseconds); break; + case DATE: + result = + state.updateWindows( + timestamp, row.getDate(index), outputMinReportIntervalMilliseconds); + break; case INT64: + case TIMESTAMP: result = state.updateWindows( timestamp, row.getLong(index), outputMinReportIntervalMilliseconds); @@ -466,10 +475,16 @@ private Map> processRow( timestamp, row.getDouble(index), outputMinReportIntervalMilliseconds); break; case TEXT: + case STRING: result = state.updateWindows( timestamp, row.getString(index), outputMinReportIntervalMilliseconds); break; + case BLOB: + result = + state.updateWindows( + timestamp, row.getBinary(index), outputMinReportIntervalMilliseconds); + break; default: throw new UnsupportedOperationException( String.format("The type %s is not supported", row.getDataType(index))); @@ -620,7 +635,11 @@ public void collectWindowOutputs( case INT32: valueColumns[columnIndex] = new int[distinctOutputs.size()]; break; + case DATE: + valueColumns[columnIndex] = new LocalDate[distinctOutputs.size()]; + break; case INT64: + case TIMESTAMP: valueColumns[columnIndex] = new long[distinctOutputs.size()]; break; case FLOAT: @@ -630,7 +649,9 @@ public void collectWindowOutputs( valueColumns[columnIndex] = new double[distinctOutputs.size()]; break; case TEXT: - valueColumns[columnIndex] = new String[distinctOutputs.size()]; + case BLOB: + case STRING: + valueColumns[columnIndex] = new Binary[distinctOutputs.size()]; break; default: throw new UnsupportedOperationException( @@ -649,7 +670,12 @@ public void collectWindowOutputs( ((int[]) valueColumns[columnIndex])[rowIndex] = (int) aggregatedResults.get(columnNameStringList[columnIndex]).getRight(); break; + case DATE: + ((LocalDate[]) valueColumns[columnIndex])[rowIndex] = + (LocalDate) aggregatedResults.get(columnNameStringList[columnIndex]).getRight(); + break; case INT64: + case TIMESTAMP: ((long[]) valueColumns[columnIndex])[rowIndex] = (long) aggregatedResults.get(columnNameStringList[columnIndex]).getRight(); break; @@ -662,8 +688,19 @@ public void collectWindowOutputs( (double) aggregatedResults.get(columnNameStringList[columnIndex]).getRight(); break; case TEXT: - ((String[]) valueColumns[columnIndex])[rowIndex] = - (String) aggregatedResults.get(columnNameStringList[columnIndex]).getRight(); + case STRING: + ((Binary[]) valueColumns[columnIndex])[rowIndex] = + aggregatedResults.get(columnNameStringList[columnIndex]).getRight() + instanceof Binary + ? (Binary) aggregatedResults.get(columnNameStringList[columnIndex]).getRight() + : new Binary( + (String) + aggregatedResults.get(columnNameStringList[columnIndex]).getRight(), + TSFileConfig.STRING_CHARSET); + break; + case BLOB: + ((Binary[]) valueColumns[columnIndex])[rowIndex] = + (Binary) aggregatedResults.get(columnNameStringList[columnIndex]).getRight(); break; default: throw new UnsupportedOperationException( diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/TimeSeriesRuntimeState.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/TimeSeriesRuntimeState.java index 64864e087250e..2cb9a41469032 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/TimeSeriesRuntimeState.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/TimeSeriesRuntimeState.java @@ -25,6 +25,7 @@ import org.apache.iotdb.db.pipe.processor.aggregate.window.datastructure.WindowOutput; import org.apache.iotdb.db.pipe.processor.aggregate.window.datastructure.WindowState; import org.apache.iotdb.db.pipe.processor.aggregate.window.processor.AbstractWindowingProcessor; +import org.apache.iotdb.pipe.api.type.Binary; import org.apache.tsfile.utils.Pair; import org.apache.tsfile.utils.PublicBAOS; @@ -33,6 +34,7 @@ import java.io.DataOutputStream; import java.io.IOException; import java.nio.ByteBuffer; +import java.time.LocalDate; import java.util.ArrayList; import java.util.Iterator; import java.util.List; @@ -165,6 +167,52 @@ public Pair, Pair> updateWindows( return output; } + public Pair, Pair> updateWindows( + final long timestamp, final LocalDate value, final long outputMinReportIntervalMilliseconds) + throws IOException { + Pair, Pair> output = null; + + if (timestamp <= lastReportTimeStamp) { + return null; + } + final Set addedWindows = + windowingProcessor.mayAddWindow(currentOpeningWindows, timestamp, value); + if (Objects.nonNull(addedWindows)) { + addedWindows.forEach( + window -> + window.initWindow( + intermediateResultName2OperatorSupplierMap, + aggregatorOutputName2OperatorMap, + systemParameters)); + } + final Iterator windowIterator = currentOpeningWindows.iterator(); + while (windowIterator.hasNext()) { + final TimeSeriesWindow window = windowIterator.next(); + final Pair stateWindowOutputPair = + window.updateIntermediateResult(timestamp, value); + if (Objects.isNull(stateWindowOutputPair)) { + continue; + } + if (stateWindowOutputPair.getLeft().isEmit() + && Objects.nonNull(stateWindowOutputPair.getRight())) { + outputList.add(stateWindowOutputPair.getRight()); + lastReportTimeStamp = + Math.max(lastReportTimeStamp, stateWindowOutputPair.getRight().getProgressTime()); + } + if (stateWindowOutputPair.getLeft().isPurge()) { + windowIterator.remove(); + } + } + if (!outputList.isEmpty()) { + output = + new Pair<>( + new ArrayList<>(outputList), + getTimestampWindowBufferPair(outputMinReportIntervalMilliseconds)); + outputList.clear(); + } + return output; + } + public Pair, Pair> updateWindows( final long timestamp, final long value, final long outputMinReportIntervalMilliseconds) throws IOException { @@ -349,6 +397,52 @@ public Pair, Pair> updateWindows( return output; } + public Pair, Pair> updateWindows( + final long timestamp, final Binary value, final long outputMinReportIntervalMilliseconds) + throws IOException { + Pair, Pair> output = null; + + if (timestamp <= lastReportTimeStamp) { + return null; + } + final Set addedWindows = + windowingProcessor.mayAddWindow(currentOpeningWindows, timestamp, value); + if (Objects.nonNull(addedWindows)) { + addedWindows.forEach( + window -> + window.initWindow( + intermediateResultName2OperatorSupplierMap, + aggregatorOutputName2OperatorMap, + systemParameters)); + } + final Iterator windowIterator = currentOpeningWindows.iterator(); + while (windowIterator.hasNext()) { + final TimeSeriesWindow window = windowIterator.next(); + final Pair stateWindowOutputPair = + window.updateIntermediateResult(timestamp, value); + if (Objects.isNull(stateWindowOutputPair)) { + continue; + } + if (stateWindowOutputPair.getLeft().isEmit() + && Objects.nonNull(stateWindowOutputPair.getRight())) { + outputList.add(stateWindowOutputPair.getRight()); + lastReportTimeStamp = + Math.max(lastReportTimeStamp, stateWindowOutputPair.getRight().getProgressTime()); + } + if (stateWindowOutputPair.getLeft().isPurge()) { + windowIterator.remove(); + } + } + if (!outputList.isEmpty()) { + output = + new Pair<>( + new ArrayList<>(outputList), + getTimestampWindowBufferPair(outputMinReportIntervalMilliseconds)); + outputList.clear(); + } + return output; + } + public List forceOutput() { return currentOpeningWindows.stream() .map(TimeSeriesWindow::forceOutput) diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/operator/intermediateresult/CustomizedReadableIntermediateResults.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/operator/intermediateresult/CustomizedReadableIntermediateResults.java index 9af6bcae73631..f9c9c5f828809 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/operator/intermediateresult/CustomizedReadableIntermediateResults.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/operator/intermediateresult/CustomizedReadableIntermediateResults.java @@ -19,20 +19,28 @@ package org.apache.iotdb.db.pipe.processor.aggregate.operator.intermediateresult; +import org.apache.iotdb.commons.conf.CommonDescriptor; +import org.apache.iotdb.pipe.api.type.Binary; +import org.apache.iotdb.rpc.RpcUtils; + import org.apache.tsfile.enums.TSDataType; +import org.apache.tsfile.utils.BytesUtils; +import org.apache.tsfile.utils.DateUtils; import org.apache.tsfile.utils.Pair; +import java.time.LocalDate; +import java.time.ZoneId; import java.util.Map; public class CustomizedReadableIntermediateResults { private final Map> intermediateResults; public CustomizedReadableIntermediateResults( - Map> intermediateResults) { + final Map> intermediateResults) { this.intermediateResults = intermediateResults; } - public boolean getBoolean(String key) { + public boolean getBoolean(final String key) { final Pair typeResultPair = intermediateResults.get(key); if (typeResultPair.getLeft() == TSDataType.BOOLEAN) { return (boolean) typeResultPair.getRight(); @@ -41,7 +49,7 @@ public boolean getBoolean(String key) { String.format("The type %s cannot be casted to boolean.", typeResultPair.getLeft())); } - public int getInt(String key) { + public int getInt(final String key) { final Pair typeResultPair = intermediateResults.get(key); final TSDataType type = typeResultPair.getLeft(); @@ -49,7 +57,10 @@ public int getInt(String key) { switch (type) { case INT32: return (int) value; + case DATE: + return DateUtils.parseDateExpressionToInt((LocalDate) value); case INT64: + case TIMESTAMP: return (int) (long) value; case FLOAT: return (int) (float) value; @@ -61,7 +72,7 @@ public int getInt(String key) { } } - public long getLong(String key) { + public long getLong(final String key) { final Pair typeResultPair = intermediateResults.get(key); final TSDataType type = typeResultPair.getLeft(); @@ -69,7 +80,10 @@ public long getLong(String key) { switch (type) { case INT32: return (int) value; + case DATE: + return DateUtils.parseDateExpressionToInt((LocalDate) value); case INT64: + case TIMESTAMP: return (long) value; case FLOAT: return (long) (float) value; @@ -81,7 +95,7 @@ public long getLong(String key) { } } - public float getFloat(String key) { + public float getFloat(final String key) { final Pair typeResultPair = intermediateResults.get(key); final TSDataType type = typeResultPair.getLeft(); @@ -89,7 +103,10 @@ public float getFloat(String key) { switch (type) { case INT32: return (int) value; + case DATE: + return DateUtils.parseDateExpressionToInt((LocalDate) value); case INT64: + case TIMESTAMP: return (long) value; case FLOAT: return (float) value; @@ -101,7 +118,7 @@ public float getFloat(String key) { } } - public double getDouble(String key) { + public double getDouble(final String key) { final Pair typeResultPair = intermediateResults.get(key); final TSDataType type = typeResultPair.getLeft(); @@ -109,7 +126,10 @@ public double getDouble(String key) { switch (type) { case INT32: return (int) value; + case DATE: + return DateUtils.parseDateExpressionToInt((LocalDate) value); case INT64: + case TIMESTAMP: return (long) value; case FLOAT: return (float) value; @@ -123,7 +143,7 @@ public double getDouble(String key) { // Note: This method will cast any decimal types to string without throwing // any exceptions. - public String getString(String key) { + public String getString(final String key) { final Pair typeResultPair = intermediateResults.get(key); final TSDataType type = typeResultPair.getLeft(); @@ -133,14 +153,25 @@ public String getString(String key) { return Boolean.toString((boolean) value); case INT32: return Integer.toString((int) value); + case DATE: + return ((LocalDate) value).toString(); case INT64: return Long.toString((long) value); + case TIMESTAMP: + return RpcUtils.formatDatetime( + RpcUtils.DEFAULT_TIME_FORMAT, + CommonDescriptor.getInstance().getConfig().getTimestampPrecision(), + (long) value, + ZoneId.systemDefault()); case FLOAT: return Float.toString((float) value); case DOUBLE: return Double.toString((double) value); case TEXT: + case STRING: return (String) value; + case BLOB: + return BytesUtils.parseBlobByteArrayToString(((Binary) value).getValues()); default: throw new UnsupportedOperationException( String.format("The type %s cannot be casted to string.", typeResultPair.getLeft())); @@ -148,11 +179,11 @@ public String getString(String key) { } // The caller may cast the object by itself. - public Object getObject(String key) { + public Object getObject(final String key) { return intermediateResults.get(key).getRight(); } - public TSDataType getType(String key) { + public TSDataType getType(final String key) { return intermediateResults.get(key).getLeft(); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/operator/intermediateresult/IntermediateResultOperator.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/operator/intermediateresult/IntermediateResultOperator.java index d68191885775a..95e1a9cb0d1e6 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/operator/intermediateresult/IntermediateResultOperator.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/operator/intermediateresult/IntermediateResultOperator.java @@ -19,12 +19,15 @@ package org.apache.iotdb.db.pipe.processor.aggregate.operator.intermediateresult; +import org.apache.iotdb.pipe.api.type.Binary; + import org.apache.tsfile.enums.TSDataType; import org.apache.tsfile.utils.Pair; import java.io.DataOutputStream; import java.io.IOException; import java.nio.ByteBuffer; +import java.time.LocalDate; import java.util.Map; /** @@ -53,7 +56,7 @@ public interface IntermediateResultOperator { * * @param systemParams the system parameters */ - void configureSystemParameters(Map systemParams); + void configureSystemParameters(final Map systemParams); /** * The operator may init its value and typically set the output intermediate value type by the @@ -66,17 +69,21 @@ public interface IntermediateResultOperator { * @param initialInput the initial data * @return if the input type is supported */ - boolean initAndGetIsSupport(boolean initialInput, long initialTimestamp); + boolean initAndGetIsSupport(final boolean initialInput, final long initialTimestamp); + + boolean initAndGetIsSupport(final int initialInput, final long initialTimestamp); + + boolean initAndGetIsSupport(final LocalDate initialInput, final long initialTimestamp); - boolean initAndGetIsSupport(int initialInput, long initialTimestamp); + boolean initAndGetIsSupport(final long initialInput, final long initialTimestamp); - boolean initAndGetIsSupport(long initialInput, long initialTimestamp); + boolean initAndGetIsSupport(final float initialInput, final long initialTimestamp); - boolean initAndGetIsSupport(float initialInput, long initialTimestamp); + boolean initAndGetIsSupport(final double initialInput, final long initialTimestamp); - boolean initAndGetIsSupport(double initialInput, long initialTimestamp); + boolean initAndGetIsSupport(final String initialInput, final long initialTimestamp); - boolean initAndGetIsSupport(String initialInput, long initialTimestamp); + boolean initAndGetIsSupport(final Binary initialInput, final long initialTimestamp); /** * Use the input to update the intermediate result. The input is all raw types instead of Object @@ -84,17 +91,21 @@ public interface IntermediateResultOperator { * * @param input the inputs */ - void updateValue(boolean input, long timestamp); + void updateValue(final boolean input, final long timestamp); + + void updateValue(final int input, final long timestamp); + + void updateValue(final LocalDate input, final long timestamp); - void updateValue(int input, long timestamp); + void updateValue(final long input, final long timestamp); - void updateValue(long input, long timestamp); + void updateValue(final float input, final long timestamp); - void updateValue(float input, long timestamp); + void updateValue(final double input, final long timestamp); - void updateValue(double input, long timestamp); + void updateValue(final String input, final long timestamp); - void updateValue(String input, long timestamp); + void updateValue(final Binary input, final long timestamp); /** * Get the result and its type to calculate the aggregated value. If the type is List, Map or @@ -106,8 +117,8 @@ public interface IntermediateResultOperator { * Serialize its intermediate result to the outputStream to allow shutdown restart. The operator * may as well serialize its own status. */ - void serialize(DataOutputStream outputStream) throws IOException; + void serialize(final DataOutputStream outputStream) throws IOException; /** Deserialize the object from byteBuffer to allow shutdown restart */ - void deserialize(ByteBuffer byteBuffer) throws IOException; + void deserialize(final ByteBuffer byteBuffer) throws IOException; } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/operator/intermediateresult/sametype/numeric/AbstractSameTypeNumericOperator.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/operator/intermediateresult/sametype/numeric/AbstractSameTypeNumericOperator.java index 8069c17c03728..eab8b64256047 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/operator/intermediateresult/sametype/numeric/AbstractSameTypeNumericOperator.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/operator/intermediateresult/sametype/numeric/AbstractSameTypeNumericOperator.java @@ -20,6 +20,7 @@ package org.apache.iotdb.db.pipe.processor.aggregate.operator.intermediateresult.sametype.numeric; import org.apache.iotdb.db.pipe.processor.aggregate.operator.intermediateresult.IntermediateResultOperator; +import org.apache.iotdb.pipe.api.type.Binary; import org.apache.tsfile.enums.TSDataType; import org.apache.tsfile.utils.Pair; @@ -28,6 +29,7 @@ import java.io.DataOutputStream; import java.io.IOException; import java.nio.ByteBuffer; +import java.time.LocalDate; import java.util.Map; /** @@ -43,56 +45,78 @@ public abstract class AbstractSameTypeNumericOperator implements IntermediateRes protected double doubleValue; @Override - public void configureSystemParameters(Map systemParams) { + public void configureSystemParameters(final Map systemParams) { // Do nothing } @Override - public boolean initAndGetIsSupport(boolean initialInput, long initialTimestamp) { + public boolean initAndGetIsSupport(final boolean initialInput, final long initialTimestamp) { return false; } @Override - public boolean initAndGetIsSupport(int initialInput, long initialTimestamp) { + public boolean initAndGetIsSupport(final int initialInput, final long initialTimestamp) { outPutDataType = TSDataType.INT32; return true; } @Override - public boolean initAndGetIsSupport(long initialInput, long initialTimestamp) { + public boolean initAndGetIsSupport(final LocalDate initialInput, final long initialTimestamp) { + return false; + } + + @Override + public boolean initAndGetIsSupport(final long initialInput, final long initialTimestamp) { outPutDataType = TSDataType.INT64; return true; } @Override - public boolean initAndGetIsSupport(float initialInput, long initialTimestamp) { + public boolean initAndGetIsSupport(final float initialInput, final long initialTimestamp) { outPutDataType = TSDataType.FLOAT; return true; } @Override - public boolean initAndGetIsSupport(double initialInput, long initialTimestamp) { + public boolean initAndGetIsSupport(final double initialInput, final long initialTimestamp) { outPutDataType = TSDataType.DOUBLE; return true; } @Override - public boolean initAndGetIsSupport(String initialInput, long initialTimestamp) { + public boolean initAndGetIsSupport(final String initialInput, final long initialTimestamp) { + return false; + } + + @Override + public boolean initAndGetIsSupport(final Binary initialInput, final long initialTimestamp) { return false; } @Override - public void updateValue(boolean input, long timestamp) { + public void updateValue(final boolean input, final long timestamp) { throw new UnsupportedOperationException( "AbstractSameTypeNumericOperator does not support boolean input"); } @Override - public void updateValue(String input, long timestamp) { + public void updateValue(final LocalDate input, final long timestamp) { + throw new UnsupportedOperationException( + "AbstractSameTypeNumericOperator does not support date input"); + } + + @Override + public void updateValue(final String input, final long timestamp) { throw new UnsupportedOperationException( "AbstractSameTypeNumericOperator does not support string input"); } + @Override + public void updateValue(final Binary input, final long timestamp) { + throw new UnsupportedOperationException( + "AbstractSameTypeNumericOperator does not support binary input"); + } + @Override public Pair getResult() { switch (outPutDataType) { @@ -110,7 +134,7 @@ public Pair getResult() { } @Override - public void serialize(DataOutputStream outputStream) throws IOException { + public void serialize(final DataOutputStream outputStream) throws IOException { outPutDataType.serializeTo(outputStream); switch (outPutDataType) { case INT32: @@ -131,7 +155,7 @@ public void serialize(DataOutputStream outputStream) throws IOException { } @Override - public void deserialize(ByteBuffer byteBuffer) throws IOException { + public void deserialize(final ByteBuffer byteBuffer) throws IOException { outPutDataType = TSDataType.deserializeFrom(byteBuffer); switch (outPutDataType) { case INT32: diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/operator/intermediateresult/specifictype/doubletype/FractionPoweredSumOperator.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/operator/intermediateresult/specifictype/doubletype/FractionPoweredSumOperator.java index e80f05e455ada..a49d90c6ede7b 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/operator/intermediateresult/specifictype/doubletype/FractionPoweredSumOperator.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/operator/intermediateresult/specifictype/doubletype/FractionPoweredSumOperator.java @@ -20,6 +20,7 @@ package org.apache.iotdb.db.pipe.processor.aggregate.operator.intermediateresult.specifictype.doubletype; import org.apache.iotdb.db.pipe.processor.aggregate.operator.intermediateresult.IntermediateResultOperator; +import org.apache.iotdb.pipe.api.type.Binary; import org.apache.tsfile.enums.TSDataType; import org.apache.tsfile.utils.Pair; @@ -28,6 +29,7 @@ import java.io.DataOutputStream; import java.io.IOException; import java.nio.ByteBuffer; +import java.time.LocalDate; import java.util.Map; public class FractionPoweredSumOperator implements IntermediateResultOperator { @@ -41,7 +43,7 @@ public class FractionPoweredSumOperator implements IntermediateResultOperator { * * @param power the power to use */ - public FractionPoweredSumOperator(double power) { + public FractionPoweredSumOperator(final double power) { this.power = power; } @@ -51,88 +53,110 @@ public String getName() { } @Override - public void configureSystemParameters(Map systemParams) { + public void configureSystemParameters(final Map systemParams) { // Do nothing } @Override - public boolean initAndGetIsSupport(boolean initialInput, long initialTimestamp) { + public boolean initAndGetIsSupport(final boolean initialInput, final long initialTimestamp) { return false; } @Override - public boolean initAndGetIsSupport(int initialInput, long initialTimestamp) { + public boolean initAndGetIsSupport(final int initialInput, final long initialTimestamp) { sum = Math.pow(initialInput, power); return true; } @Override - public boolean initAndGetIsSupport(long initialInput, long initialTimestamp) { + public boolean initAndGetIsSupport(final LocalDate initialInput, final long initialTimestamp) { + return false; + } + + @Override + public boolean initAndGetIsSupport(final long initialInput, final long initialTimestamp) { sum = Math.pow(initialInput, power); return true; } @Override - public boolean initAndGetIsSupport(float initialInput, long initialTimestamp) { + public boolean initAndGetIsSupport(final float initialInput, final long initialTimestamp) { sum = Math.pow(initialInput, power); return true; } @Override - public boolean initAndGetIsSupport(double initialInput, long initialTimestamp) { + public boolean initAndGetIsSupport(final double initialInput, final long initialTimestamp) { sum = Math.pow(initialInput, power); return true; } @Override - public boolean initAndGetIsSupport(String initialInput, long initialTimestamp) { + public boolean initAndGetIsSupport(final String initialInput, final long initialTimestamp) { + return false; + } + + @Override + public boolean initAndGetIsSupport(final Binary initialInput, final long initialTimestamp) { return false; } @Override - public void updateValue(boolean input, long timestamp) { + public void updateValue(final boolean input, final long timestamp) { throw new UnsupportedOperationException( "FractionPoweredSumOperator does not support boolean input"); } @Override - public void updateValue(int input, long timestamp) { + public void updateValue(final int input, final long timestamp) { sum += Math.pow(input, power); } @Override - public void updateValue(long input, long timestamp) { + public void updateValue(final LocalDate input, final long timestamp) { + throw new UnsupportedOperationException( + "FractionPoweredSumOperator does not support date input"); + } + + @Override + public void updateValue(final long input, final long timestamp) { sum += Math.pow(input, power); } @Override - public void updateValue(float input, long timestamp) { + public void updateValue(final float input, final long timestamp) { sum += Math.pow(input, power); } @Override - public void updateValue(double input, long timestamp) { + public void updateValue(final double input, final long timestamp) { sum += Math.pow(input, power); } @Override - public void updateValue(String input, long timestamp) { + public void updateValue(final String input, final long timestamp) { throw new UnsupportedOperationException( "FractionPoweredSumOperator does not support string input"); } + @Override + public void updateValue(final Binary initialInput, final long initialTimestamp) { + throw new UnsupportedOperationException( + "FractionPoweredSumOperator does not support binary input"); + } + @Override public Pair getResult() { return new Pair<>(TSDataType.DOUBLE, sum); } @Override - public void serialize(DataOutputStream outputStream) throws IOException { + public void serialize(final DataOutputStream outputStream) throws IOException { ReadWriteIOUtils.write(sum, outputStream); } @Override - public void deserialize(ByteBuffer byteBuffer) throws IOException { + public void deserialize(final ByteBuffer byteBuffer) throws IOException { sum = ReadWriteIOUtils.readDouble(byteBuffer); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/operator/intermediateresult/specifictype/integertype/CountOperator.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/operator/intermediateresult/specifictype/integertype/CountOperator.java index 4e5397fe6735f..a42dfa179425a 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/operator/intermediateresult/specifictype/integertype/CountOperator.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/operator/intermediateresult/specifictype/integertype/CountOperator.java @@ -20,6 +20,7 @@ package org.apache.iotdb.db.pipe.processor.aggregate.operator.intermediateresult.specifictype.integertype; import org.apache.iotdb.db.pipe.processor.aggregate.operator.intermediateresult.IntermediateResultOperator; +import org.apache.iotdb.pipe.api.type.Binary; import org.apache.tsfile.enums.TSDataType; import org.apache.tsfile.utils.Pair; @@ -28,6 +29,7 @@ import java.io.DataOutputStream; import java.io.IOException; import java.nio.ByteBuffer; +import java.time.LocalDate; import java.util.Map; public class CountOperator implements IntermediateResultOperator { @@ -39,73 +41,95 @@ public String getName() { } @Override - public void configureSystemParameters(Map systemParams) { + public void configureSystemParameters(final Map systemParams) { // Do nothing } @Override - public boolean initAndGetIsSupport(boolean initialInput, long initialTimestamp) { + public boolean initAndGetIsSupport(final boolean initialInput, final long initialTimestamp) { count = 1; return true; } @Override - public boolean initAndGetIsSupport(int initialInput, long initialTimestamp) { + public boolean initAndGetIsSupport(final int initialInput, final long initialTimestamp) { count = 1; return true; } @Override - public boolean initAndGetIsSupport(long initialInput, long initialTimestamp) { + public boolean initAndGetIsSupport(final LocalDate initialInput, final long initialTimestamp) { count = 1; return true; } @Override - public boolean initAndGetIsSupport(float initialInput, long initialTimestamp) { + public boolean initAndGetIsSupport(final long initialInput, final long initialTimestamp) { count = 1; return true; } @Override - public boolean initAndGetIsSupport(double initialInput, long initialTimestamp) { + public boolean initAndGetIsSupport(final float initialInput, final long initialTimestamp) { count = 1; return true; } @Override - public boolean initAndGetIsSupport(String initialInput, long initialTimestamp) { + public boolean initAndGetIsSupport(final double initialInput, final long initialTimestamp) { count = 1; return true; } @Override - public void updateValue(boolean input, long timestamp) { + public boolean initAndGetIsSupport(final String initialInput, final long initialTimestamp) { + count = 1; + return true; + } + + @Override + public boolean initAndGetIsSupport(final Binary initialInput, final long initialTimestamp) { + count = 1; + return true; + } + + @Override + public void updateValue(final boolean input, final long timestamp) { + ++count; + } + + @Override + public void updateValue(final int input, final long timestamp) { + ++count; + } + + @Override + public void updateValue(LocalDate input, long timestamp) { ++count; } @Override - public void updateValue(int input, long timestamp) { + public void updateValue(final long input, final long timestamp) { ++count; } @Override - public void updateValue(long input, long timestamp) { + public void updateValue(final float input, final long timestamp) { ++count; } @Override - public void updateValue(float input, long timestamp) { + public void updateValue(final double input, final long timestamp) { ++count; } @Override - public void updateValue(double input, long timestamp) { + public void updateValue(final String input, final long timestamp) { ++count; } @Override - public void updateValue(String input, long timestamp) { + public void updateValue(Binary input, long timestamp) { ++count; } @@ -115,12 +139,12 @@ public Pair getResult() { } @Override - public void serialize(DataOutputStream outputStream) throws IOException { + public void serialize(final DataOutputStream outputStream) throws IOException { ReadWriteIOUtils.write(count, outputStream); } @Override - public void deserialize(ByteBuffer byteBuffer) throws IOException { + public void deserialize(final ByteBuffer byteBuffer) throws IOException { count = ReadWriteIOUtils.readInt(byteBuffer); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/window/datastructure/TimeSeriesWindow.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/window/datastructure/TimeSeriesWindow.java index 511d9a61fb00e..6cd046fb594fc 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/window/datastructure/TimeSeriesWindow.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/window/datastructure/TimeSeriesWindow.java @@ -23,6 +23,7 @@ import org.apache.iotdb.db.pipe.processor.aggregate.operator.intermediateresult.CustomizedReadableIntermediateResults; import org.apache.iotdb.db.pipe.processor.aggregate.operator.intermediateresult.IntermediateResultOperator; import org.apache.iotdb.db.pipe.processor.aggregate.window.processor.AbstractWindowingProcessor; +import org.apache.iotdb.pipe.api.type.Binary; import org.apache.tsfile.enums.TSDataType; import org.apache.tsfile.utils.Pair; @@ -33,6 +34,7 @@ import java.io.DataOutputStream; import java.io.IOException; import java.nio.ByteBuffer; +import java.time.LocalDate; import java.util.Collections; import java.util.HashMap; import java.util.Iterator; @@ -213,6 +215,61 @@ public Pair updateIntermediateResult( return state.isEmit() ? stateOutputPair : null; } + public Pair updateIntermediateResult( + final long timestamp, final LocalDate value) { + final Pair stateOutputPair = + processor.updateAndMaySetWindowState(this, timestamp, value); + final WindowState state = stateOutputPair.getLeft(); + + if (state.isEmitWithoutCompute()) { + stateOutputPair.getRight().setAggregatedResults(getAggregatedResults(TSDataType.DATE)); + } + + if (state.isCalculate()) { + final Iterator>> iterator = + intermediateResultName2tsTypeAndOperatorMap.entrySet().iterator(); + Map.Entry> entry; + + while (iterator.hasNext()) { + entry = iterator.next(); + final IntermediateResultOperator operator = entry.getValue().getRight(); + if (entry.getValue().getLeft() == TSDataType.UNKNOWN) { + if (!operator.initAndGetIsSupport(value, timestamp)) { + // Remove unsupported aggregated results + aggregatedOutputName2OperatorMap + .entrySet() + .removeIf( + entry1 -> + entry1 + .getValue() + .getDeclaredIntermediateValueNames() + .contains(operator.getName())); + // If no aggregated values can be calculated, purge the window + if (aggregatedOutputName2OperatorMap.isEmpty()) { + return new Pair<>(WindowState.PURGE, null); + } + // Remove unsupported intermediate values + iterator.remove(); + continue; + } + entry.getValue().setLeft(TSDataType.DATE); + } else if (entry.getValue().getLeft() != TSDataType.DATE) { + LOGGER.warn( + "Different data type encountered in one window, will purge. Previous type: {}, now type: {}", + entry.getValue().getLeft(), + TSDataType.DATE); + return new Pair<>(WindowState.PURGE, null); + } else { + operator.updateValue(value, timestamp); + } + } + } + if (state.isEmitWithCompute()) { + stateOutputPair.getRight().setAggregatedResults(getAggregatedResults(TSDataType.DATE)); + } + return state.isEmit() ? stateOutputPair : null; + } + public Pair updateIntermediateResult( final long timestamp, final long value) { final Pair stateOutputPair = @@ -431,6 +488,60 @@ public Pair updateIntermediateResult( return state.isEmit() ? stateOutputPair : null; } + public Pair updateIntermediateResult( + final long timestamp, final Binary value) { + final Pair stateOutputPair = + processor.updateAndMaySetWindowState(this, timestamp, value); + final WindowState state = stateOutputPair.getLeft(); + + if (state.isEmitWithoutCompute()) { + stateOutputPair.getRight().setAggregatedResults(getAggregatedResults(TSDataType.BLOB)); + } + if (state.isCalculate()) { + final Iterator>> iterator = + intermediateResultName2tsTypeAndOperatorMap.entrySet().iterator(); + Map.Entry> entry; + + while (iterator.hasNext()) { + entry = iterator.next(); + final IntermediateResultOperator operator = entry.getValue().getRight(); + if (entry.getValue().getLeft() == TSDataType.UNKNOWN) { + if (!operator.initAndGetIsSupport(value, timestamp)) { + // Remove unsupported aggregated results + aggregatedOutputName2OperatorMap + .entrySet() + .removeIf( + entry1 -> + entry1 + .getValue() + .getDeclaredIntermediateValueNames() + .contains(operator.getName())); + // If no aggregated values can be calculated, purge the window + if (aggregatedOutputName2OperatorMap.isEmpty()) { + return new Pair<>(WindowState.PURGE, null); + } + // Remove unsupported intermediate values + iterator.remove(); + continue; + } + entry.getValue().setLeft(TSDataType.BLOB); + } else if (entry.getValue().getLeft() != TSDataType.BLOB) { + LOGGER.warn( + "Different data type encountered in one window, will purge. Previous type: {}, now type: {}", + entry.getValue().getLeft(), + TSDataType.BLOB); + return new Pair<>(WindowState.PURGE, null); + } else { + operator.updateValue(value, timestamp); + } + } + } + if (state.isEmitWithCompute()) { + stateOutputPair.getRight().setAggregatedResults(getAggregatedResults(TSDataType.BLOB)); + } + return state.isEmit() ? stateOutputPair : null; + } + public WindowOutput forceOutput() { return processor .forceOutput(this) diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/window/processor/AbstractSimpleTimeWindowingProcessor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/window/processor/AbstractSimpleTimeWindowingProcessor.java index b74cbb09181fe..c7acd0441c84f 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/window/processor/AbstractSimpleTimeWindowingProcessor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/window/processor/AbstractSimpleTimeWindowingProcessor.java @@ -22,82 +22,106 @@ import org.apache.iotdb.db.pipe.processor.aggregate.window.datastructure.TimeSeriesWindow; import org.apache.iotdb.db.pipe.processor.aggregate.window.datastructure.WindowOutput; import org.apache.iotdb.db.pipe.processor.aggregate.window.datastructure.WindowState; +import org.apache.iotdb.pipe.api.type.Binary; import org.apache.tsfile.utils.Pair; +import java.time.LocalDate; import java.util.List; import java.util.Set; public abstract class AbstractSimpleTimeWindowingProcessor extends AbstractWindowingProcessor { public Set mayAddWindow( - List windowList, long timeStamp, boolean value) { + final List windowList, final long timeStamp, final boolean value) { return mayAddWindow(windowList, timeStamp); } public Set mayAddWindow( - List windowList, long timeStamp, int value) { + final List windowList, final long timeStamp, final int value) { return mayAddWindow(windowList, timeStamp); } public Set mayAddWindow( - List windowList, long timeStamp, long value) { + final List windowList, final long timeStamp, final LocalDate value) { return mayAddWindow(windowList, timeStamp); } public Set mayAddWindow( - List windowList, long timeStamp, float value) { + final List windowList, final long timeStamp, final long value) { return mayAddWindow(windowList, timeStamp); } public Set mayAddWindow( - List windowList, long timeStamp, double value) { + final List windowList, final long timeStamp, final float value) { return mayAddWindow(windowList, timeStamp); } public Set mayAddWindow( - List windowList, long timeStamp, String value) { + final List windowList, final long timeStamp, final double value) { + return mayAddWindow(windowList, timeStamp); + } + + public Set mayAddWindow( + final List windowList, final long timeStamp, final String value) { + return mayAddWindow(windowList, timeStamp); + } + + public Set mayAddWindow( + final List windowList, final long timeStamp, final Binary value) { return mayAddWindow(windowList, timeStamp); } public abstract Set mayAddWindow( - List windowList, long timeStamp); + final List windowList, final long timeStamp); + + @Override + public Pair updateAndMaySetWindowState( + final TimeSeriesWindow window, final long timeStamp, final boolean value) { + return updateAndMaySetWindowState(window, timeStamp); + } + + @Override + public Pair updateAndMaySetWindowState( + final TimeSeriesWindow window, final long timeStamp, final int value) { + return updateAndMaySetWindowState(window, timeStamp); + } @Override public Pair updateAndMaySetWindowState( - TimeSeriesWindow window, long timeStamp, boolean value) { + final TimeSeriesWindow window, final long timeStamp, final LocalDate value) { return updateAndMaySetWindowState(window, timeStamp); } @Override public Pair updateAndMaySetWindowState( - TimeSeriesWindow window, long timeStamp, int value) { + final TimeSeriesWindow window, final long timeStamp, final long value) { return updateAndMaySetWindowState(window, timeStamp); } @Override public Pair updateAndMaySetWindowState( - TimeSeriesWindow window, long timeStamp, long value) { + final TimeSeriesWindow window, final long timeStamp, final float value) { return updateAndMaySetWindowState(window, timeStamp); } @Override public Pair updateAndMaySetWindowState( - TimeSeriesWindow window, long timeStamp, float value) { + final TimeSeriesWindow window, final long timeStamp, final double value) { return updateAndMaySetWindowState(window, timeStamp); } @Override public Pair updateAndMaySetWindowState( - TimeSeriesWindow window, long timeStamp, double value) { + final TimeSeriesWindow window, final long timeStamp, final String value) { return updateAndMaySetWindowState(window, timeStamp); } @Override public Pair updateAndMaySetWindowState( - TimeSeriesWindow window, long timeStamp, String value) { + final TimeSeriesWindow window, final long timeStamp, final Binary value) { return updateAndMaySetWindowState(window, timeStamp); } public abstract Pair updateAndMaySetWindowState( - TimeSeriesWindow window, long timeStamp); + final TimeSeriesWindow window, final long timeStamp); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/window/processor/AbstractWindowingProcessor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/window/processor/AbstractWindowingProcessor.java index 7f8d1ba70a5af..384db345b8592 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/window/processor/AbstractWindowingProcessor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/aggregate/window/processor/AbstractWindowingProcessor.java @@ -24,11 +24,13 @@ import org.apache.iotdb.db.pipe.processor.aggregate.window.datastructure.TimeSeriesWindow; import org.apache.iotdb.db.pipe.processor.aggregate.window.datastructure.WindowOutput; import org.apache.iotdb.db.pipe.processor.aggregate.window.datastructure.WindowState; +import org.apache.iotdb.pipe.api.type.Binary; import org.apache.tsfile.utils.Pair; import java.io.DataOutputStream; import java.nio.ByteBuffer; +import java.time.LocalDate; import java.util.List; import java.util.Set; @@ -47,22 +49,28 @@ public abstract class AbstractWindowingProcessor extends AbstractFormalProcessor * @return The added windows */ public abstract Set mayAddWindow( - List windowList, long timeStamp, boolean value); + final List windowList, final long timeStamp, final boolean value); public abstract Set mayAddWindow( - List windowList, long timeStamp, int value); + final List windowList, final long timeStamp, final int value); public abstract Set mayAddWindow( - List windowList, long timeStamp, long value); + final List windowList, final long timeStamp, final LocalDate value); public abstract Set mayAddWindow( - List windowList, long timeStamp, float value); + final List windowList, final long timeStamp, final long value); public abstract Set mayAddWindow( - List windowList, long timeStamp, double value); + final List windowList, final long timeStamp, final float value); public abstract Set mayAddWindow( - List windowList, long timeStamp, String value); + final List windowList, final long timeStamp, final double value); + + public abstract Set mayAddWindow( + final List windowList, final long timeStamp, final String value); + + public abstract Set mayAddWindow( + final List windowList, final long timeStamp, final Binary value); /** * The {@link AbstractWindowingProcessor} may decide whether a {@link TimeSeriesWindow} shall be @@ -76,24 +84,30 @@ public abstract Set mayAddWindow( * restarted. */ public abstract Pair updateAndMaySetWindowState( - TimeSeriesWindow window, long timeStamp, boolean value); + final TimeSeriesWindow window, final long timeStamp, final boolean value); + + public abstract Pair updateAndMaySetWindowState( + final TimeSeriesWindow window, final long timeStamp, final int value); + + public abstract Pair updateAndMaySetWindowState( + final TimeSeriesWindow window, final long timeStamp, final LocalDate value); public abstract Pair updateAndMaySetWindowState( - TimeSeriesWindow window, long timeStamp, int value); + final TimeSeriesWindow window, final long timeStamp, final long value); public abstract Pair updateAndMaySetWindowState( - TimeSeriesWindow window, long timeStamp, long value); + final TimeSeriesWindow window, final long timeStamp, final float value); public abstract Pair updateAndMaySetWindowState( - TimeSeriesWindow window, long timeStamp, float value); + final TimeSeriesWindow window, final long timeStamp, final double value); public abstract Pair updateAndMaySetWindowState( - TimeSeriesWindow window, long timeStamp, double value); + final TimeSeriesWindow window, final long timeStamp, final String value); public abstract Pair updateAndMaySetWindowState( - TimeSeriesWindow window, long timeStamp, String value); + final TimeSeriesWindow window, final long timeStamp, final Binary value); - public abstract WindowOutput forceOutput(TimeSeriesWindow window); + public abstract WindowOutput forceOutput(final TimeSeriesWindow window); /** * Serialize the customized attributes in a window to an output stream @@ -102,7 +116,7 @@ public abstract Pair updateAndMaySetWindowState( * @param outputStream the outputStream */ public void serializeCustomizedAttributes( - TimeSeriesWindow window, DataOutputStream outputStream) { + final TimeSeriesWindow window, final DataOutputStream outputStream) { // Do nothing by default } @@ -111,7 +125,8 @@ public void serializeCustomizedAttributes( * * @param byteBuffer the customized attributes in one window */ - public void deserializeCustomizedAttributes(TimeSeriesWindow window, ByteBuffer byteBuffer) { + public void deserializeCustomizedAttributes( + final TimeSeriesWindow window, final ByteBuffer byteBuffer) { // Do nothing by default } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/downsampling/PartialPathLastObjectCache.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/downsampling/PartialPathLastObjectCache.java index bbee9babed948..ece3963c6f478 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/downsampling/PartialPathLastObjectCache.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/downsampling/PartialPathLastObjectCache.java @@ -40,15 +40,15 @@ public abstract class PartialPathLastObjectCache implements AutoCloseable { private final Cache partialPath2ObjectCache; - public PartialPathLastObjectCache(long memoryLimitInBytes) { + protected PartialPathLastObjectCache(final long memoryLimitInBytes) { allocatedMemoryBlock = PipeResourceManager.memory() .tryAllocate(memoryLimitInBytes) .setShrinkMethod(oldMemory -> Math.max(oldMemory / 2, 1)) .setShrinkCallback( (oldMemory, newMemory) -> { - memoryUsageCheatFactor.set( - memoryUsageCheatFactor.get() * ((double) oldMemory / newMemory)); + memoryUsageCheatFactor.updateAndGet( + factor -> factor * ((double) oldMemory / newMemory)); LOGGER.info( "PartialPathLastObjectCache.allocatedMemoryBlock has shrunk from {} to {}.", oldMemory, @@ -57,8 +57,8 @@ public PartialPathLastObjectCache(long memoryLimitInBytes) { .setExpandMethod(oldMemory -> Math.min(Math.max(oldMemory, 1) * 2, memoryLimitInBytes)) .setExpandCallback( (oldMemory, newMemory) -> { - memoryUsageCheatFactor.set( - memoryUsageCheatFactor.get() / ((double) newMemory / oldMemory)); + memoryUsageCheatFactor.updateAndGet( + factor -> factor / ((double) newMemory / oldMemory)); LOGGER.info( "PartialPathLastObjectCache.allocatedMemoryBlock has expanded from {} to {}.", oldMemory, @@ -87,15 +87,15 @@ public PartialPathLastObjectCache(long memoryLimitInBytes) { .build(); } - protected abstract long calculateMemoryUsage(T object); + protected abstract long calculateMemoryUsage(final T object); /////////////////////////// Getter & Setter /////////////////////////// - public T getPartialPathLastObject(String partialPath) { + public T getPartialPathLastObject(final String partialPath) { return partialPath2ObjectCache.getIfPresent(partialPath); } - public void setPartialPathLastObject(String partialPath, T object) { + public void setPartialPathLastObject(final String partialPath, final T object) { partialPath2ObjectCache.put(partialPath, object); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/downsampling/changing/ChangingValueFilter.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/downsampling/changing/ChangingValueFilter.java index cc83fbeb21ec8..7dc8c87c09b2d 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/downsampling/changing/ChangingValueFilter.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/downsampling/changing/ChangingValueFilter.java @@ -21,6 +21,7 @@ import org.apache.iotdb.pipe.api.type.Binary; +import java.time.LocalDate; import java.util.Objects; public class ChangingValueFilter { @@ -36,26 +37,28 @@ public class ChangingValueFilter { private T lastStoredValue; public ChangingValueFilter( - ChangingValueSamplingProcessor processor, long firstTimestamp, T firstValue) { + final ChangingValueSamplingProcessor processor, + final long firstTimestamp, + final T firstValue) { this.processor = processor; init(firstTimestamp, firstValue); } - private void init(long firstTimestamp, T firstValue) { + private void init(final long firstTimestamp, final T firstValue) { lastStoredTimestamp = firstTimestamp; lastStoredValue = firstValue; } - public boolean filter(long timestamp, T value) { + public boolean filter(final long timestamp, final T value) { try { return tryFilter(timestamp, value); - } catch (Exception e) { + } catch (final Exception e) { init(timestamp, value); return true; } } - private boolean tryFilter(long timestamp, T value) { + private boolean tryFilter(final long timestamp, final T value) { final long timeDiff = Math.abs(timestamp - lastStoredTimestamp); if (timeDiff <= processor.getCompressionMinTimeInterval()) { @@ -67,8 +70,11 @@ private boolean tryFilter(long timestamp, T value) { return true; } - // For boolean and string type, we only compare the value - if (value instanceof Boolean || value instanceof String || value instanceof Binary) { + // For non-numerical types, we only compare the value + if (value instanceof Boolean + || value instanceof String + || value instanceof Binary + || value instanceof LocalDate) { if (Objects.equals(lastStoredValue, value)) { return false; } @@ -88,7 +94,7 @@ private boolean tryFilter(long timestamp, T value) { return false; } - private void reset(long timestamp, T value) { + private void reset(final long timestamp, final T value) { lastStoredTimestamp = timestamp; lastStoredValue = value; } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/downsampling/sdt/SwingingDoorTrendingFilter.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/downsampling/sdt/SwingingDoorTrendingFilter.java index 8d9e73deb0701..850cbd3ed0729 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/downsampling/sdt/SwingingDoorTrendingFilter.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/downsampling/sdt/SwingingDoorTrendingFilter.java @@ -21,6 +21,7 @@ import org.apache.iotdb.pipe.api.type.Binary; +import java.time.LocalDate; import java.util.Objects; public class SwingingDoorTrendingFilter { @@ -56,12 +57,14 @@ public class SwingingDoorTrendingFilter { private T lastStoredValue; public SwingingDoorTrendingFilter( - SwingingDoorTrendingSamplingProcessor processor, long firstTimestamp, T firstValue) { + final SwingingDoorTrendingSamplingProcessor processor, + final long firstTimestamp, + final T firstValue) { this.processor = processor; init(firstTimestamp, firstValue); } - private void init(long firstTimestamp, T firstValue) { + private void init(final long firstTimestamp, final T firstValue) { upperDoor = Double.MIN_VALUE; lowerDoor = Double.MAX_VALUE; @@ -72,16 +75,16 @@ private void init(long firstTimestamp, T firstValue) { lastStoredValue = firstValue; } - public boolean filter(long timestamp, T value) { + public boolean filter(final long timestamp, final T value) { try { return tryFilter(timestamp, value); - } catch (Exception e) { + } catch (final Exception e) { init(timestamp, value); return true; } } - private boolean tryFilter(long timestamp, T value) { + private boolean tryFilter(final long timestamp, final T value) { final long timeDiff = timestamp - lastStoredTimestamp; final long absTimeDiff = Math.abs(timeDiff); @@ -95,7 +98,10 @@ private boolean tryFilter(long timestamp, T value) { } // For boolean and string type, we only compare the value - if (value instanceof Boolean || value instanceof String || value instanceof Binary) { + if (value instanceof Boolean + || value instanceof String + || value instanceof Binary + || value instanceof LocalDate) { if (Objects.equals(lastStoredValue, value)) { return false; } @@ -138,7 +144,7 @@ private boolean tryFilter(long timestamp, T value) { return false; } - private void reset(long timestamp, T value) { + private void reset(final long timestamp, final T value) { upperDoor = Double.MIN_VALUE; lowerDoor = Double.MAX_VALUE; diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/twostage/combiner/PipeCombineHandler.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/twostage/combiner/PipeCombineHandler.java index 55ef5afbfe9de..afa4e2cd64a1a 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/twostage/combiner/PipeCombineHandler.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/twostage/combiner/PipeCombineHandler.java @@ -27,7 +27,7 @@ import org.apache.iotdb.confignode.rpc.thrift.TRegionInfo; import org.apache.iotdb.confignode.rpc.thrift.TShowRegionReq; import org.apache.iotdb.confignode.rpc.thrift.TShowRegionResp; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.processor.twostage.exchange.payload.FetchCombineResultResponse; import org.apache.iotdb.db.pipe.processor.twostage.operator.Operator; import org.apache.iotdb.db.pipe.processor.twostage.state.State; @@ -147,7 +147,7 @@ private Map fetchExpectedRegionId2DataNodeIdMap() { } final Set pipeRelatedRegionIdSet = - new HashSet<>(PipeAgent.task().getPipeTaskRegionIdSet(pipeName, creationTime)); + new HashSet<>(PipeDataNodeAgent.task().getPipeTaskRegionIdSet(pipeName, creationTime)); pipeRelatedRegionIdSet.removeIf( regionId -> !ALL_REGION_ID_2_DATANODE_ID_MAP.containsKey(regionId)); if (LOGGER.isInfoEnabled()) { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/twostage/combiner/PipeCombineHandlerManager.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/twostage/combiner/PipeCombineHandlerManager.java index c08cd23d0c8c4..1b8342af77e97 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/twostage/combiner/PipeCombineHandlerManager.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/twostage/combiner/PipeCombineHandlerManager.java @@ -20,7 +20,7 @@ package org.apache.iotdb.db.pipe.processor.twostage.combiner; import org.apache.iotdb.commons.pipe.config.PipeConfig; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.processor.twostage.exchange.payload.CombineRequest; import org.apache.iotdb.db.pipe.processor.twostage.exchange.payload.FetchCombineResultRequest; import org.apache.iotdb.db.pipe.processor.twostage.exchange.payload.FetchCombineResultResponse; @@ -146,7 +146,7 @@ private static String generatePipeId(String pipeName, long creationTime) { /////////////////////////////// Singleton /////////////////////////////// private PipeCombineHandlerManager() { - PipeAgent.runtime() + PipeDataNodeAgent.runtime() .registerPeriodicalJob( "CombineHandlerManager#fetchExpectedRegionIdSetAndCleanOutdatedCombiner", this::fetchExpectedRegionIdSetAndCleanOutdatedCombiner, diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/twostage/plugin/TwoStageCountProcessor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/twostage/plugin/TwoStageCountProcessor.java index 630a4f1f0c6a5..fc6104a8108c4 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/twostage/plugin/TwoStageCountProcessor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/processor/twostage/plugin/TwoStageCountProcessor.java @@ -253,7 +253,7 @@ private void collectGlobalCountIfNecessary(EventCollector eventCollector) throws tablet.addValue(outputSeries.getMeasurement(), 0, timestampCountPair.right); eventCollector.collect( - new PipeRawTabletInsertionEvent(tablet, false, null, null, null, false)); + new PipeRawTabletInsertionEvent(tablet, false, null, 0, null, null, false)); PipeCombineHandlerManager.getInstance() .updateLastCombinedValue(pipeName, creationTime, timestampCountPair); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/receiver/protocol/airgap/IoTDBAirGapReceiver.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/receiver/protocol/airgap/IoTDBAirGapReceiver.java index 4cd97d7cb37ac..9fd3bcd40927a 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/receiver/protocol/airgap/IoTDBAirGapReceiver.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/receiver/protocol/airgap/IoTDBAirGapReceiver.java @@ -25,7 +25,7 @@ import org.apache.iotdb.commons.pipe.connector.payload.airgap.AirGapELanguageConstant; import org.apache.iotdb.commons.pipe.connector.payload.airgap.AirGapOneByteResponse; import org.apache.iotdb.commons.pipe.connector.payload.airgap.AirGapPseudoTPipeTransferRequest; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.receiver.protocol.thrift.IoTDBDataNodeReceiverAgent; import org.apache.iotdb.pipe.api.exception.PipeConnectionException; import org.apache.iotdb.rpc.TSStatusCode; @@ -63,7 +63,7 @@ public IoTDBAirGapReceiver(final Socket socket, final long receiverId) { this.socket = socket; this.receiverId = receiverId; - agent = PipeAgent.receiver().thrift(); + agent = PipeDataNodeAgent.receiver().thrift(); } @Override @@ -90,7 +90,7 @@ public void runMayThrow() throws Throwable { e); throw e; } finally { - PipeAgent.receiver().thrift().handleClientExit(); + PipeDataNodeAgent.receiver().thrift().handleClientExit(); socket.close(); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/receiver/protocol/pipeconsensus/PipeConsensusReceiver.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/receiver/protocol/pipeconsensus/PipeConsensusReceiver.java index 60a0b88beb902..d6b106705a12f 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/receiver/protocol/pipeconsensus/PipeConsensusReceiver.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/receiver/protocol/pipeconsensus/PipeConsensusReceiver.java @@ -30,6 +30,7 @@ import org.apache.iotdb.commons.pipe.connector.payload.pipeconsensus.response.PipeConsensusTransferFilePieceResp; import org.apache.iotdb.commons.pipe.connector.payload.thrift.response.PipeTransferFilePieceResp; import org.apache.iotdb.commons.pipe.receiver.IoTDBReceiverAgent; +import org.apache.iotdb.commons.service.metric.MetricService; import org.apache.iotdb.consensus.exception.ConsensusGroupNotExistException; import org.apache.iotdb.consensus.pipe.PipeConsensus; import org.apache.iotdb.consensus.pipe.PipeConsensusServerImpl; @@ -46,6 +47,7 @@ import org.apache.iotdb.db.pipe.connector.protocol.pipeconsensus.payload.request.PipeConsensusTsFilePieceReq; import org.apache.iotdb.db.pipe.connector.protocol.pipeconsensus.payload.request.PipeConsensusTsFileSealReq; import org.apache.iotdb.db.pipe.connector.protocol.pipeconsensus.payload.request.PipeConsensusTsFileSealWithModReq; +import org.apache.iotdb.db.pipe.consensus.PipeConsensusReceiverMetrics; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.write.InsertNode; import org.apache.iotdb.db.storageengine.StorageEngine; import org.apache.iotdb.db.storageengine.dataregion.tsfile.TsFileResource; @@ -89,15 +91,17 @@ public class PipeConsensusReceiver { * IOTDB_CONFIG.getPipeConsensusPipelineSize(); private static final long CLOSE_TSFILE_WRITER_MAX_WAIT_TIME_IN_MS = 5000; private static final long RETRY_WAIT_TIME = 500; - private final RequestExecutor requestExecutor = new RequestExecutor(); + private final RequestExecutor requestExecutor; private final PipeConsensus pipeConsensus; private final ConsensusGroupId consensusGroupId; - // Used to buffer TsFile when transfer TsFile asynchronously. + private final ConsensusPipeName consensusPipeName; private final List receiverBaseDirsName; + // Used to buffer TsFile when transfer TsFile asynchronously. private final PipeConsensusTsFileWriterPool pipeConsensusTsFileWriterPool = new PipeConsensusTsFileWriterPool(); private final AtomicReference receiverFileDirWithIdSuffix = new AtomicReference<>(); - private FolderManager folderManager; + private final PipeConsensusReceiverMetrics pipeConsensusReceiverMetrics; + private final FolderManager folderManager; public PipeConsensusReceiver( PipeConsensus pipeConsensus, @@ -105,24 +109,32 @@ public PipeConsensusReceiver( ConsensusPipeName consensusPipeName) { this.pipeConsensus = pipeConsensus; this.consensusGroupId = consensusGroupId; + this.pipeConsensusReceiverMetrics = new PipeConsensusReceiverMetrics(this); + this.requestExecutor = new RequestExecutor(pipeConsensusReceiverMetrics); + this.consensusPipeName = consensusPipeName; + MetricService.getInstance().addMetricSet(pipeConsensusReceiverMetrics); // Each pipeConsensusReceiver has its own base directories. for example, a default dir path is - // data/datanode/system/pipe/consensus/receiver/__consensus{consensusGroupId}_{leaderDataNodeId}_{followerDataNodeId} + // data/datanode/system/pipe/consensus/receiver/__consensus.{consensusGroupId}_{leaderDataNodeId}_{followerDataNodeId} receiverBaseDirsName = - Arrays.stream(IoTDBDescriptor.getInstance().getConfig().getPipeConsensusReceiverFileDirs()) - .map(s -> s + File.separator + consensusPipeName) - .collect(Collectors.toList()); + Arrays.asList(IoTDBDescriptor.getInstance().getConfig().getPipeConsensusReceiverFileDirs()); try { this.folderManager = new FolderManager(receiverBaseDirsName, DirectoryStrategyType.SEQUENCE_STRATEGY); - initiateTsFileBufferFolder(); } catch (Exception e) { LOGGER.error( "Fail to create pipeConsensus receiver file folders allocation strategy because all disks of folders are full.", e); throw new RuntimeException(e); } + + try { + initiateTsFileBufferFolder(); + } catch (Exception e) { + LOGGER.error("Fail to initiate file buffer folder, Error msg: {}", e.getMessage()); + throw new RuntimeException(e); + } } /** @@ -130,6 +142,7 @@ public PipeConsensusReceiver( * load event must be synchronized. */ public TPipeConsensusTransferResp receive(final TPipeConsensusTransferReq req) { + long startNanos = System.nanoTime(); // PreCheck: if there are these cases: read-only; null impl; inactive impl, etc. The receiver // will reject synchronization. TPipeConsensusTransferResp resp = preCheckForReceiver(req); @@ -144,18 +157,26 @@ public TPipeConsensusTransferResp receive(final TPipeConsensusTransferReq req) { case TRANSFER_TS_FILE_PIECE_WITH_MOD: // Just take a place in requestExecutor's buffer, the further seal request will remove // its place from buffer. - requestExecutor.onRequest(req, true); - return loadEvent(req); + requestExecutor.onRequest(req, true, false); + resp = loadEvent(req); + break; case TRANSFER_TS_FILE_SEAL: case TRANSFER_TS_FILE_SEAL_WITH_MOD: - // TODO: check memory when logging wal(in further version) + // TODO: check memory when logging WAL(in further version) + resp = requestExecutor.onRequest(req, false, true); + break; case TRANSFER_TABLET_BINARY: case TRANSFER_TABLET_INSERT_NODE: // TODO: support batch transfer(in further version) case TRANSFER_TABLET_BATCH: default: - return requestExecutor.onRequest(req, false); + resp = requestExecutor.onRequest(req, false, false); + break; } + // update receive an event's duration + long durationNanos = System.nanoTime() - startNanos; + pipeConsensusReceiverMetrics.recordReceiveEventTimer(durationNanos); + return resp; } // Unknown request type, which means the request can not be handled by this receiver, // maybe the version of the receiver is not compatible with the sender @@ -185,8 +206,7 @@ private TPipeConsensusTransferResp preCheckForReceiver(final TPipeConsensusTrans if (impl.isReadOnly()) { String message = String.format( - "PipeConsensus-ConsensusGroupId-%s: fail to receive because system is read-only.", - groupId); + "PipeConsensus-PipeName-%s: fail to receive because system is read-only.", groupId); if (LOGGER.isErrorEnabled()) { LOGGER.error(message); } @@ -196,7 +216,7 @@ private TPipeConsensusTransferResp preCheckForReceiver(final TPipeConsensusTrans if (!impl.isActive()) { String message = String.format( - "PipeConsensus-ConsensusGroupId-%s: fail to receive because peer is inactive and not ready.", + "PipeConsensus-PipeName-%s: fail to receive because peer is inactive and not ready.", groupId); if (LOGGER.isWarnEnabled()) { LOGGER.warn(message); @@ -245,13 +265,13 @@ private TPipeConsensusTransferResp loadEvent(final TPipeConsensusTransferReq req TSStatusCode.PIPE_CONSENSUS_TYPE_ERROR, String.format("Unknown PipeConsensusRequestType %s.", rawRequestType)); LOGGER.warn( - "PipeConsensus-ConsensusGroupId-{}: Unknown PipeRequestType, response status = {}.", - consensusGroupId, + "PipeConsensus-PipeName-{}: Unknown PipeRequestType, response status = {}.", + consensusPipeName, status); return new TPipeConsensusTransferResp(status); } catch (Exception e) { final String error = String.format("Serialization error during pipe receiving, %s", e); - LOGGER.warn("PipeConsensus-ConsensusGroupId-{}: {}", consensusGroupId, error, e); + LOGGER.warn("PipeConsensus-PipeName-{}: {}", consensusPipeName, error, e); return new TPipeConsensusTransferResp(RpcUtils.getStatus(TSStatusCode.PIPE_ERROR, error)); } } @@ -259,8 +279,7 @@ private TPipeConsensusTransferResp loadEvent(final TPipeConsensusTransferReq req private TPipeConsensusTransferResp handleTransferTabletInsertNode( final PipeConsensusTabletInsertNodeReq req) throws ConsensusGroupNotExistException { LOGGER.info( - "PipeConsensus-ConsensusGroupId-{}: starting to receive tablet insertNode", - consensusGroupId); + "PipeConsensus-PipeName-{}: starting to receive tablet insertNode", consensusPipeName); PipeConsensusServerImpl impl = Optional.ofNullable(pipeConsensus.getImpl(consensusGroupId)) .orElseThrow(() -> new ConsensusGroupNotExistException(consensusGroupId)); @@ -272,8 +291,7 @@ private TPipeConsensusTransferResp handleTransferTabletInsertNode( private TPipeConsensusTransferResp handleTransferTabletBinary( final PipeConsensusTabletBinaryReq req) throws ConsensusGroupNotExistException { - LOGGER.info( - "PipeConsensus-ConsensusGroupId-{}: starting to receive tablet binary", consensusGroupId); + LOGGER.info("PipeConsensus-PipeName-{}: starting to receive tablet binary", consensusPipeName); PipeConsensusServerImpl impl = Optional.ofNullable(pipeConsensus.getImpl(consensusGroupId)) .orElseThrow(() -> new ConsensusGroupNotExistException(consensusGroupId)); @@ -285,17 +303,20 @@ private TPipeConsensusTransferResp handleTransferTabletBinary( private TPipeConsensusTransferResp handleTransferFilePiece( final PipeConsensusTransferFilePieceReq req, final boolean isSingleFile) { - LOGGER.info( - "PipeConsensus-ConsensusGroupId-{}: starting to receive tsFile pieces", consensusGroupId); - PipeConsensusTsFileWriter diskBuffer = + LOGGER.info("PipeConsensus-PipeName-{}: starting to receive tsFile pieces", consensusPipeName); + long startBorrowTsFileWriterNanos = System.nanoTime(); + PipeConsensusTsFileWriter tsFileWriter = pipeConsensusTsFileWriterPool.borrowCorrespondingWriter(req.getCommitId()); + long startPreCheckNanos = System.nanoTime(); + pipeConsensusReceiverMetrics.recordBorrowTsFileWriterTimer( + startPreCheckNanos - startBorrowTsFileWriterNanos); try { - updateWritingFileIfNeeded(diskBuffer, req.getFileName(), isSingleFile); - final File writingFile = diskBuffer.getWritingFile(); - final RandomAccessFile writingFileWriter = diskBuffer.getWritingFileWriter(); + updateWritingFileIfNeeded(tsFileWriter, req.getFileName(), isSingleFile); + final File writingFile = tsFileWriter.getWritingFile(); + final RandomAccessFile writingFileWriter = tsFileWriter.getWritingFileWriter(); - if (isWritingFileOffsetNonCorrect(diskBuffer, req.getStartWritingOffset())) { + if (isWritingFileOffsetNonCorrect(tsFileWriter, req.getStartWritingOffset())) { if (!writingFile.getName().endsWith(TsFileConstant.TSFILE_SUFFIX)) { // If the file is a tsFile, then the content will not be changed for a specific // filename. However, for other files (mod, snapshot, etc.) the content varies for the @@ -311,20 +332,24 @@ private TPipeConsensusTransferResp handleTransferFilePiece( "Request sender to reset file reader's offset from %s to %s.", req.getStartWritingOffset(), writingFileWriter.length())); LOGGER.warn( - "PipeConsensus-ConsensusGroupId-{}: File offset reset requested by receiver, response status = {}.", - consensusGroupId, + "PipeConsensus-PipeName-{}: File offset reset requested by receiver, response status = {}.", + consensusPipeName, status); return PipeConsensusTransferFilePieceResp.toTPipeConsensusTransferResp( status, writingFileWriter.length()); } + long endPreCheckNanos = System.nanoTime(); + pipeConsensusReceiverMetrics.recordTsFilePiecePreCheckTime( + endPreCheckNanos - startPreCheckNanos); writingFileWriter.write(req.getFilePiece()); + pipeConsensusReceiverMetrics.recordTsFilePieceWriteTime(System.nanoTime() - endPreCheckNanos); return PipeConsensusTransferFilePieceResp.toTPipeConsensusTransferResp( RpcUtils.SUCCESS_STATUS, writingFileWriter.length()); } catch (Exception e) { LOGGER.warn( - "PipeConsensus-ConsensusGroupId-{}: Failed to write file piece from req {}.", - consensusGroupId, + "PipeConsensus-PipeName-{}: Failed to write file piece from req {}.", + consensusPipeName, req, e); final TSStatus status = @@ -341,10 +366,13 @@ private TPipeConsensusTransferResp handleTransferFilePiece( } private TPipeConsensusTransferResp handleTransferFileSeal(final PipeConsensusTsFileSealReq req) { - LOGGER.info( - "PipeConsensus-ConsensusGroupId-{}: starting to receive tsFile seal", consensusGroupId); + LOGGER.info("PipeConsensus-PipeName-{}: starting to receive tsFile seal", consensusPipeName); + long startBorrowTsFileWriterNanos = System.nanoTime(); PipeConsensusTsFileWriter tsFileWriter = pipeConsensusTsFileWriterPool.borrowCorrespondingWriter(req.getCommitId()); + long startPreCheckNanos = System.nanoTime(); + pipeConsensusReceiverMetrics.recordBorrowTsFileWriterTimer( + startPreCheckNanos - startBorrowTsFileWriterNanos); File writingFile = tsFileWriter.getWritingFile(); RandomAccessFile writingFileWriter = tsFileWriter.getWritingFileWriter(); @@ -381,29 +409,33 @@ private TPipeConsensusTransferResp handleTransferFileSeal(final PipeConsensusTsF // writingFile will be deleted after load if no exception occurs tsFileWriter.setWritingFile(null); + long endPreCheckNanos = System.nanoTime(); + pipeConsensusReceiverMetrics.recordTsFileSealPreCheckTimer( + endPreCheckNanos - startPreCheckNanos); final TSStatus status = loadFileToDataRegion( fileAbsolutePath, ProgressIndexType.deserializeFrom(ByteBuffer.wrap(req.getProgressIndex()))); + pipeConsensusReceiverMetrics.recordTsFileSealLoadTimer(System.nanoTime() - endPreCheckNanos); if (status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { // if transfer success, disk buffer will be released. tsFileWriter.returnSelf(); LOGGER.info( - "PipeConsensus-ConsensusGroupId-{}: Seal file {} successfully.", - consensusGroupId, + "PipeConsensus-PipeName-{}: Seal file {} successfully.", + consensusPipeName, fileAbsolutePath); } else { LOGGER.warn( - "PipeConsensus-ConsensusGroupId-{}: Failed to seal file {}, because {}.", - consensusGroupId, + "PipeConsensus-PipeName-{}: Failed to seal file {}, because {}.", + consensusPipeName, fileAbsolutePath, status.getMessage()); } return new TPipeConsensusTransferResp(status); } catch (IOException e) { LOGGER.warn( - "PipeConsensus-ConsensusGroupId-{}: Failed to seal file {} from req {}.", - consensusGroupId, + "PipeConsensus-PipeName-{}: Failed to seal file {} from req {}.", + consensusPipeName, writingFile, req, e); @@ -413,8 +445,8 @@ private TPipeConsensusTransferResp handleTransferFileSeal(final PipeConsensusTsF String.format("Failed to seal file %s because %s", writingFile, e.getMessage()))); } catch (LoadFileException e) { LOGGER.warn( - "PipeConsensus-ConsensusGroupId-{}: Failed to load file {} from req {}.", - consensusGroupId, + "PipeConsensus-PipeName-{}: Failed to load file {} from req {}.", + consensusPipeName, writingFile, req, e); @@ -434,10 +466,13 @@ private TPipeConsensusTransferResp handleTransferFileSeal(final PipeConsensusTsF private TPipeConsensusTransferResp handleTransferFileSealWithMods( final PipeConsensusTsFileSealWithModReq req) { LOGGER.info( - "PipeConsensus-ConsensusGroupId-{}: starting to receive tsFile seal with mods", - consensusGroupId); + "PipeConsensus-PipeName-{}: starting to receive tsFile seal with mods", consensusPipeName); + long startBorrowTsFileWriterNanos = System.nanoTime(); PipeConsensusTsFileWriter tsFileWriter = pipeConsensusTsFileWriterPool.borrowCorrespondingWriter(req.getCommitId()); + long startPreCheckNanos = System.nanoTime(); + pipeConsensusReceiverMetrics.recordBorrowTsFileWriterTimer( + startPreCheckNanos - startBorrowTsFileWriterNanos); File writingFile = tsFileWriter.getWritingFile(); RandomAccessFile writingFileWriter = tsFileWriter.getWritingFileWriter(); @@ -491,29 +526,33 @@ private TPipeConsensusTransferResp handleTransferFileSealWithMods( final List fileAbsolutePaths = files.stream().map(File::getAbsolutePath).collect(Collectors.toList()); + long endPreCheckNanos = System.nanoTime(); + pipeConsensusReceiverMetrics.recordTsFileSealPreCheckTimer( + endPreCheckNanos - startPreCheckNanos); final TSStatus status = loadFileToDataRegion( fileAbsolutePaths.get(1), ProgressIndexType.deserializeFrom(ByteBuffer.wrap(req.getProgressIndex()))); + pipeConsensusReceiverMetrics.recordTsFileSealLoadTimer(System.nanoTime() - endPreCheckNanos); if (status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { // if transfer success, disk buffer will be released. tsFileWriter.returnSelf(); LOGGER.info( - "PipeConsensus-ConsensusGroupId-{}: Seal file with mods {} successfully.", - consensusGroupId, + "PipeConsensus-PipeName-{}: Seal file with mods {} successfully.", + consensusPipeName, fileAbsolutePaths); } else { LOGGER.warn( - "PipeConsensus-ConsensusGroupId-{}: Failed to seal file {}, status is {}.", - consensusGroupId, + "PipeConsensus-PipeName-{}: Failed to seal file {}, status is {}.", + consensusPipeName, fileAbsolutePaths, status); } return new TPipeConsensusTransferResp(status); } catch (Exception e) { LOGGER.warn( - "PipeConsensus-ConsensusGroupId-{}: Failed to seal file {} from req {}.", - consensusGroupId, + "PipeConsensus-PipeName-{}: Failed to seal file {} from req {}.", + consensusPipeName, files, req, e); @@ -546,8 +585,8 @@ private TPipeConsensusTransferResp checkNonFinalFileSeal( TSStatusCode.PIPE_CONSENSUS_TRANSFER_FILE_ERROR, String.format("Failed to seal file %s, the file does not exist.", fileName)); LOGGER.warn( - "PipeConsensus-ConsensusGroupId-{}: Failed to seal file {}, because the file does not exist.", - consensusGroupId, + "PipeConsensus-PipeName-{}: Failed to seal file {}, because the file does not exist.", + consensusPipeName, fileName); return new TPipeConsensusTransferResp(status); } @@ -561,9 +600,9 @@ private TPipeConsensusTransferResp checkNonFinalFileSeal( + "The original file has length %s, but receiver file has length %s.", fileName, fileLength, writingFileWriter.length())); LOGGER.warn( - "PipeConsensus-ConsensusGroupId-{}: Failed to seal file {} when check non final seal, because the length of file is not correct. " + "PipeConsensus-PipeName-{}: Failed to seal file {} when check non final seal, because the length of file is not correct. " + "The original file has length {}, but receiver file has length {}.", - consensusGroupId, + consensusPipeName, fileName, fileLength, writingFileWriter.length()); @@ -604,9 +643,9 @@ private boolean isWritingFileNonAvailable(PipeConsensusTsFileWriter diskBuffer) writingFile != null && writingFile.exists() && writingFileWriter != null; if (!isWritingFileAvailable) { LOGGER.info( - "PipeConsensus-ConsensusGroupId-{}: Writing file {} is not available. " + "PipeConsensus-PipeName-{}: Writing file {} is not available. " + "Writing file is null: {}, writing file exists: {}, writing file writer is null: {}.", - consensusGroupId, + consensusPipeName, writingFile, writingFile == null, writingFile != null && writingFile.exists(), @@ -628,8 +667,8 @@ private TPipeConsensusTransferResp checkFinalFileSeal( String.format( "Failed to seal file %s, because writing file is %s.", fileName, writingFile)); LOGGER.warn( - "PipeConsensus-ConsensusGroupId-{}: Failed to seal file {}, because writing file is {}.", - consensusGroupId, + "PipeConsensus-PipeName-{}: Failed to seal file {}, because writing file is {}.", + consensusPipeName, fileName, writingFile); return new TPipeConsensusTransferResp(status); @@ -644,9 +683,9 @@ private TPipeConsensusTransferResp checkFinalFileSeal( + "The original file has length %s, but receiver file has length %s.", fileName, fileLength, writingFileWriter.length())); LOGGER.warn( - "PipeConsensus-ConsensusGroupId-{}: Failed to seal file {} when check final seal file, because the length of file is not correct. " + "PipeConsensus-PipeName-{}: Failed to seal file {} when check final seal file, because the length of file is not correct. " + "The original file has length {}, but receiver file has length {}.", - consensusGroupId, + consensusPipeName, fileName, fileLength, writingFileWriter.length()); @@ -670,8 +709,8 @@ private boolean isWritingFileOffsetNonCorrect( final boolean offsetCorrect = writingFileWriter.length() == offset; if (!offsetCorrect) { LOGGER.warn( - "PipeConsensus-ConsensusGroupId-{}: Writing file {}'s offset is {}, but request sender's offset is {}.", - consensusGroupId, + "PipeConsensus-PipeName-{}: Writing file {}'s offset is {}, but request sender's offset is {}.", + consensusPipeName, writingFile.getPath(), writingFileWriter.length(), offset); @@ -684,13 +723,13 @@ private void closeCurrentWritingFileWriter(PipeConsensusTsFileWriter diskBuffer) try { diskBuffer.getWritingFileWriter().close(); LOGGER.info( - "PipeConsensus-ConsensusGroupId-{}: Current writing file writer {} was closed.", - consensusGroupId, + "PipeConsensus-PipeName-{}: Current writing file writer {} was closed.", + consensusPipeName, diskBuffer.getWritingFile() == null ? "null" : diskBuffer.getWritingFile().getPath()); } catch (IOException e) { LOGGER.warn( - "PipeConsensus-ConsensusGroupId-{}: Failed to close current writing file writer {}, because {}.", - consensusGroupId, + "PipeConsensus-PipeName-{}: Failed to close current writing file writer {}, because {}.", + consensusPipeName, diskBuffer.getWritingFile() == null ? "null" : diskBuffer.getWritingFile().getPath(), e.getMessage(), e); @@ -699,8 +738,8 @@ private void closeCurrentWritingFileWriter(PipeConsensusTsFileWriter diskBuffer) } else { if (LOGGER.isDebugEnabled()) { LOGGER.debug( - "PipeConsensus-ConsensusGroupId-{}: Current writing file writer is null. No need to close.", - consensusGroupId.getId()); + "PipeConsensus-PipeName-{}: Current writing file writer is null. No need to close.", + consensusPipeName.toString()); } } } @@ -710,13 +749,13 @@ private void deleteFile(File file) { try { FileUtils.delete(file); LOGGER.info( - "PipeConsensus-ConsensusGroupId-{}: Original writing file {} was deleted.", - consensusGroupId, + "PipeConsensus-PipeName-{}: Original writing file {} was deleted.", + consensusPipeName, file.getPath()); } catch (IOException e) { LOGGER.warn( - "PipeConsensus-ConsensusGroupId-{}: Failed to delete original writing file {}, because {}.", - consensusGroupId, + "PipeConsensus-PipeName-{}: Failed to delete original writing file {}, because {}.", + consensusPipeName, file.getPath(), e.getMessage(), e); @@ -724,8 +763,8 @@ private void deleteFile(File file) { } else { if (LOGGER.isDebugEnabled()) { LOGGER.debug( - "PipeConsensus-ConsensusGroupId-{}: Original file {} is not existed. No need to delete.", - consensusGroupId, + "PipeConsensus-PipeName-{}: Original file {} is not existed. No need to delete.", + consensusPipeName, file.getPath()); } } @@ -737,8 +776,8 @@ private void deleteCurrentWritingFile(PipeConsensusTsFileWriter diskBuffer) { } else { if (LOGGER.isDebugEnabled()) { LOGGER.debug( - "PipeConsensus-ConsensusGroupId-{}: Current writing file is null. No need to delete.", - consensusGroupId.getId()); + "PipeConsensus-PipeName-{}: Current writing file is null. No need to delete.", + consensusPipeName.toString()); } } } @@ -751,9 +790,9 @@ private void updateWritingFileIfNeeded( } LOGGER.info( - "PipeConsensus-ConsensusGroupId-{}: Writing file {} is not existed or name is not correct, try to create it. " + "PipeConsensus-PipeName-{}: Writing file {} is not existed or name is not correct, try to create it. " + "Current writing file is {}.", - consensusGroupId, + consensusPipeName, fileName, diskBuffer.getWritingFile() == null ? "null" : diskBuffer.getWritingFile().getPath()); @@ -770,13 +809,13 @@ private void updateWritingFileIfNeeded( if (!receiverFileDirWithIdSuffix.get().exists()) { if (receiverFileDirWithIdSuffix.get().mkdirs()) { LOGGER.info( - "PipeConsensus-ConsensusGroupId-{}: Receiver file dir {} was created.", - consensusGroupId, + "PipeConsensus-PipeName-{}: Receiver file dir {} was created.", + consensusPipeName, receiverFileDirWithIdSuffix.get().getPath()); } else { LOGGER.error( - "PipeConsensus-ConsensusGroupId-{}: Failed to create receiver file dir {}.", - consensusGroupId, + "PipeConsensus-PipeName-{}: Failed to create receiver file dir {}.", + consensusPipeName, receiverFileDirWithIdSuffix.get().getPath()); } } @@ -784,8 +823,8 @@ private void updateWritingFileIfNeeded( diskBuffer.setWritingFile(new File(receiverFileDirWithIdSuffix.get(), fileName)); diskBuffer.setWritingFileWriter(new RandomAccessFile(diskBuffer.getWritingFile(), "rw")); LOGGER.info( - "PipeConsensus-ConsensusGroupId-{}: Writing file {} was created. Ready to write file pieces.", - consensusGroupId, + "PipeConsensus-PipeName-{}: Writing file {} was created. Ready to write file pieces.", + consensusPipeName, diskBuffer.getWritingFile().getPath()); } @@ -801,13 +840,13 @@ private void initiateTsFileBufferFolder() throws DiskSpaceInsufficientException, try { FileUtils.deleteDirectory(receiverFileDirWithIdSuffix.get()); LOGGER.info( - "PipeConsensus-ConsensusGroupId-{}: Original receiver file dir {} was deleted successfully.", - consensusGroupId, + "PipeConsensus-PipeName-{}: Original receiver file dir {} was deleted successfully.", + consensusPipeName, receiverFileDirWithIdSuffix.get().getPath()); } catch (IOException e) { LOGGER.warn( - "PipeConsensus-ConsensusGroupId-{}: Failed to delete original receiver file dir {}, because {}.", - consensusGroupId, + "PipeConsensus-PipeName-{}: Failed to delete original receiver file dir {}, because {}.", + consensusPipeName, receiverFileDirWithIdSuffix.get().getPath(), e.getMessage(), e); @@ -815,16 +854,16 @@ private void initiateTsFileBufferFolder() throws DiskSpaceInsufficientException, } else { if (LOGGER.isDebugEnabled()) { LOGGER.debug( - "PipeConsensus-ConsensusGroupId-{}: Original receiver file dir {} is not existed. No need to delete.", - consensusGroupId, + "PipeConsensus-PipeName-{}: Original receiver file dir {} is not existed. No need to delete.", + consensusPipeName, receiverFileDirWithIdSuffix.get().getPath()); } } receiverFileDirWithIdSuffix.set(null); } else { LOGGER.debug( - "PipeConsensus-ConsensusGroupId-{}: Current receiver file dir is null. No need to delete.", - consensusGroupId.getId()); + "PipeConsensus-PipeName-{}: Current receiver file dir is null. No need to delete.", + consensusPipeName.toString()); } // initiate receiverFileDirWithIdSuffix @@ -832,21 +871,28 @@ private void initiateTsFileBufferFolder() throws DiskSpaceInsufficientException, final String receiverFileBaseDir = getReceiverFileBaseDir(); if (Objects.isNull(receiverFileBaseDir)) { LOGGER.warn( - "PipeConsensus-ConsensusGroupId-{}: Failed to init pipeConsensus receiver file folder manager because all disks of folders are full.", - consensusGroupId.getId()); + "PipeConsensus-PipeName-{}: Failed to get pipeConsensus receiver file base directory, because your folderManager is null. May because the disk is full.", + consensusPipeName.toString()); throw new DiskSpaceInsufficientException(receiverBaseDirsName); } // Create a new receiver file dir - final File newReceiverDir = new File(receiverFileBaseDir, consensusGroupId.toString()); - if (!newReceiverDir.exists() && !newReceiverDir.mkdirs()) { + final File newReceiverDir = new File(receiverFileBaseDir, consensusPipeName.toString()); + if (newReceiverDir.exists()) { + FileUtils.deleteDirectory(newReceiverDir); + LOGGER.info( + "PipeConsensus-PipeName-{}: Origin receiver file dir {} was deleted.", + consensusPipeName, + newReceiverDir.getPath()); + } + if (!newReceiverDir.mkdirs()) { LOGGER.warn( - "PipeConsensus-ConsensusGroupId-{}: Failed to create receiver file dir {}.", - newReceiverDir.getPath(), - consensusGroupId.getId()); + "PipeConsensus-PipeName-{}: Failed to create receiver file dir {}. May because authority or dir already exists etc.", + consensusPipeName, + newReceiverDir.getPath()); throw new IOException( String.format( - "PipeConsensus-ConsensusGroupId-%s: Failed to create receiver file dir %s.", - newReceiverDir.getPath(), consensusGroupId.getId())); + "PipeConsensus-PipeName-%s: Failed to create receiver file dir %s. May because authority or dir already exists etc.", + consensusPipeName, newReceiverDir.getPath())); } receiverFileDirWithIdSuffix.set(newReceiverDir); @@ -864,7 +910,7 @@ public PipeConsensusRequestVersion getVersion() { public synchronized void handleExit() { // Clear the diskBuffers - pipeConsensusTsFileWriterPool.handleExit(consensusGroupId); + pipeConsensusTsFileWriterPool.handleExit(consensusPipeName); // Clear the original receiver file dir if exists if (receiverFileDirWithIdSuffix.get() != null) { @@ -872,21 +918,21 @@ public synchronized void handleExit() { try { FileUtils.deleteDirectory(receiverFileDirWithIdSuffix.get()); LOGGER.info( - "PipeConsensus-ConsensusGroupId-{}: Receiver exit: Original receiver file dir {} was deleted.", - consensusGroupId, + "PipeConsensus-PipeName-{}: Receiver exit: Original receiver file dir {} was deleted.", + consensusPipeName, receiverFileDirWithIdSuffix.get().getPath()); } catch (IOException e) { LOGGER.warn( - "PipeConsensus-ConsensusGroupId-{}: Receiver exit: Delete original receiver file dir {} error.", - consensusGroupId, + "PipeConsensus-PipeName-{}: Receiver exit: Delete original receiver file dir {} error.", + consensusPipeName, receiverFileDirWithIdSuffix.get().getPath(), e); } } else { if (LOGGER.isDebugEnabled()) { LOGGER.debug( - "PipeConsensus-ConsensusGroupId-{}: Receiver exit: Original receiver file dir {} does not exist. No need to delete.", - consensusGroupId, + "PipeConsensus-PipeName-{}: Receiver exit: Original receiver file dir {} does not exist. No need to delete.", + consensusPipeName, receiverFileDirWithIdSuffix.get().getPath()); } } @@ -894,14 +940,16 @@ public synchronized void handleExit() { } else { if (LOGGER.isDebugEnabled()) { LOGGER.debug( - "PipeConsensus-ConsensusGroupId-{}: Receiver exit: Original receiver file dir is null. No need to delete.", - consensusGroupId.getId()); + "PipeConsensus-PipeName-{}: Receiver exit: Original receiver file dir is null. No need to delete.", + consensusPipeName.toString()); } } + // remove metric + MetricService.getInstance().removeMetricSet(pipeConsensusReceiverMetrics); + LOGGER.info( - "PipeConsensus-ConsensusGroupId-{}: Receiver exit: Receiver exited.", - consensusGroupId.getId()); + "PipeConsensus-PipeName-{}: Receiver exit: Receiver exited.", consensusPipeName.toString()); } private static class PipeConsensusTsFileWriterPool { @@ -941,7 +989,7 @@ public PipeConsensusTsFileWriter borrowCorrespondingWriter(TCommitId commitId) { return diskBuffer.get(); } - public void handleExit(ConsensusGroupId consensusGroupId) { + public void handleExit(ConsensusPipeName consensusPipeName) { pipeConsensusTsFileWriterPool.forEach( diskBuffer -> { // Wait until diskBuffer is not used by TsFileInsertionEvent or timeout. @@ -953,13 +1001,13 @@ public void handleExit(ConsensusGroupId consensusGroupId) { Thread.sleep(RETRY_WAIT_TIME); } catch (InterruptedException e) { LOGGER.warn( - "PipeConsensus-ConsensusGroupId-{}: receiver thread get interrupted when exiting.", - consensusGroupId.getId()); + "PipeConsensus-PipeName-{}: receiver thread get interrupted when exiting.", + consensusPipeName.toString()); // avoid infinite loop break; } } - diskBuffer.closeSelf(consensusGroupId); + diskBuffer.closeSelf(consensusPipeName); }); } } @@ -1016,19 +1064,19 @@ public void returnSelf() { this.commitIdOfCorrespondingHolderEvent = null; } - public void closeSelf(ConsensusGroupId consensusGroupId) { + public void closeSelf(ConsensusPipeName consensusPipeName) { // close file writer if (writingFileWriter != null) { try { writingFileWriter.close(); LOGGER.info( - "PipeConsensus-ConsensusGroupId-{}: TsFileWriter-{} exit: Writing file writer was closed.", - consensusGroupId.getId(), + "PipeConsensus-PipeName-{}: TsFileWriter-{} exit: Writing file writer was closed.", + consensusPipeName.toString(), index); } catch (Exception e) { LOGGER.warn( - "PipeConsensus-ConsensusGroupId-{}: TsFileWriter-{} exit: Close Writing file writer error.", - consensusGroupId, + "PipeConsensus-PipeName-{}: TsFileWriter-{} exit: Close Writing file writer error.", + consensusPipeName, index, e); } @@ -1036,8 +1084,8 @@ public void closeSelf(ConsensusGroupId consensusGroupId) { } else { if (LOGGER.isDebugEnabled()) { LOGGER.debug( - "PipeConsensus-ConsensusGroupId-{}: TsFileWriter-{} exit: Writing file writer is null. No need to close.", - consensusGroupId.getId(), + "PipeConsensus-PipeName-{}: TsFileWriter-{} exit: Writing file writer is null. No need to close.", + consensusPipeName.toString(), index); } } @@ -1047,13 +1095,13 @@ public void closeSelf(ConsensusGroupId consensusGroupId) { try { FileUtils.delete(writingFile); LOGGER.info( - "PipeConsensus-ConsensusGroupId-{}: TsFileWriter exit: Writing file {} was deleted.", - consensusGroupId, + "PipeConsensus-PipeName-{}: TsFileWriter exit: Writing file {} was deleted.", + consensusPipeName, writingFile.getPath()); } catch (Exception e) { LOGGER.warn( - "PipeConsensus-ConsensusGroupId-{}: TsFileWriter exit: Delete writing file {} error.", - consensusGroupId, + "PipeConsensus-PipeName-{}: TsFileWriter exit: Delete writing file {} error.", + consensusPipeName, writingFile.getPath(), e); } @@ -1061,8 +1109,8 @@ public void closeSelf(ConsensusGroupId consensusGroupId) { } else { if (LOGGER.isDebugEnabled()) { LOGGER.debug( - "PipeConsensus-ConsensusGroupId-{}: TsFileWriter exit: Writing file is null. No need to delete.", - consensusGroupId.getId()); + "PipeConsensus-PipeName-{}: TsFileWriter exit: Writing file is null. No need to delete.", + consensusPipeName.toString()); } } } @@ -1076,38 +1124,57 @@ private class RequestExecutor { // An ordered set that buffers transfer requests' TCommitId, whose length is not larger than // PIPE_CONSENSUS_PIPELINE_SIZE. // Here we use set is to avoid duplicate events being received in some special cases - private final TreeSet reqExecutionOrderBuffer; + private final TreeSet reqExecutionOrderBuffer; private final Lock lock; private final Condition condition; - private long onSyncedCommitIndex = -1; + private final PipeConsensusReceiverMetrics metric; + private long onSyncedCommitIndex = 0; private int connectorRebootTimes = 0; + private volatile int WALEventCount = 0; + private volatile int tsFileEventCount = 0; - public RequestExecutor() { - reqExecutionOrderBuffer = + public RequestExecutor(PipeConsensusReceiverMetrics metric) { + this.reqExecutionOrderBuffer = new TreeSet<>( - Comparator.comparingInt(TCommitId::getRebootTimes) - .thenComparingLong(TCommitId::getCommitIndex)); - lock = new ReentrantLock(); - condition = lock.newCondition(); + Comparator.comparingInt(RequestMeta::getRebootTimes) + .thenComparingLong(RequestMeta::getCommitIndex)); + this.lock = new ReentrantLock(); + this.condition = lock.newCondition(); + this.metric = metric; } - private void onSuccess(long nextSyncedCommitIndex) { + private void onSuccess(long nextSyncedCommitIndex, boolean isTransferTsFileSeal) { LOGGER.info( - "PipeConsensus-ConsensusGroupId-{}: process no.{} event successfully!", - consensusGroupId, + "PipeConsensus-PipeName-{}: process no.{} event successfully!", + consensusPipeName, nextSyncedCommitIndex); - reqExecutionOrderBuffer.pollFirst(); + RequestMeta curMeta = reqExecutionOrderBuffer.pollFirst(); onSyncedCommitIndex = nextSyncedCommitIndex; + // update metric, notice that curMeta is never null. + if (isTransferTsFileSeal) { + tsFileEventCount--; + metric.recordReceiveTsFileTimer(System.nanoTime() - curMeta.getStartApplyNanos()); + } else { + WALEventCount--; + metric.recordReceiveWALTimer(System.nanoTime() - curMeta.getStartApplyNanos()); + } } private TPipeConsensusTransferResp onRequest( - final TPipeConsensusTransferReq req, final boolean isTransferTsFilePiece) { + final TPipeConsensusTransferReq req, + final boolean isTransferTsFilePiece, + final boolean isTransferTsFileSeal) { + long startAcquireLockNanos = System.nanoTime(); lock.lock(); try { + long startDispatchNanos = System.nanoTime(); + metric.recordAcquireExecutorLockTimer(startDispatchNanos - startAcquireLockNanos); + TCommitId tCommitId = req.getCommitId(); + RequestMeta requestMeta = new RequestMeta(tCommitId); LOGGER.info( - "PipeConsensus-ConsensusGroup-{}: start to receive no.{} event", - consensusGroupId, + "PipeConsensus-PipeName-{}: start to receive no.{} event", + consensusPipeName, tCommitId.getCommitIndex()); // if a req is deprecated, we will discard it // This case may happen in this scenario: leader has transferred {1,2} and is intending to @@ -1125,8 +1192,8 @@ private TPipeConsensusTransferResp onRequest( TSStatusCode.PIPE_CONSENSUS_DEPRECATED_REQUEST, "PipeConsensus receiver received a deprecated request, which may be sent before the connector restart. Consider to discard it")); LOGGER.info( - "PipeConsensus-ConsensusGroup-{}: received a deprecated request, which may be sent before the connector restart. Consider to discard it", - consensusGroupId); + "PipeConsensus-PipeName-{}: received a deprecated request, which may be sent before the connector restart. Consider to discard it", + consensusPipeName); return new TPipeConsensusTransferResp(status); } // Judge whether connector has rebooted or not, if the rebootTimes increases compared to @@ -1134,16 +1201,28 @@ private TPipeConsensusTransferResp onRequest( if (tCommitId.getRebootTimes() > connectorRebootTimes) { resetWithNewestRebootTime(tCommitId.getRebootTimes()); } - reqExecutionOrderBuffer.add(tCommitId); + // update metric + if (isTransferTsFilePiece && !reqExecutionOrderBuffer.contains(requestMeta)) { + // only update tsFileEventCount when tsFileEvent is first enqueue. + tsFileEventCount++; + } + if (!isTransferTsFileSeal && !isTransferTsFilePiece) { + WALEventCount++; + } + reqExecutionOrderBuffer.add(requestMeta); + // TsFilePieceTransferEvent will not enter further procedure, it just holds a place in // buffer. Only after the corresponding sealing event is processed, this event can be // dequeued. if (isTransferTsFilePiece) { + long startApplyNanos = System.nanoTime(); + metric.recordDispatchWaitingTimer(startApplyNanos - startDispatchNanos); + requestMeta.setStartApplyNanos(startApplyNanos); return null; } if (reqExecutionOrderBuffer.size() >= IOTDB_CONFIG.getPipeConsensusPipelineSize() - && !reqExecutionOrderBuffer.first().equals(tCommitId)) { + && !reqExecutionOrderBuffer.first().equals(requestMeta)) { // If reqBuffer is full and current thread do not hold the reqBuffer's peek, this req // is not supposed to be processed. So current thread should notify the corresponding // threads to process the peek. @@ -1152,8 +1231,11 @@ private TPipeConsensusTransferResp onRequest( // Polling to process while (true) { - if (reqExecutionOrderBuffer.first().equals(tCommitId) + if (reqExecutionOrderBuffer.first().equals(requestMeta) && tCommitId.getCommitIndex() == onSyncedCommitIndex + 1) { + long startApplyNanos = System.nanoTime(); + metric.recordDispatchWaitingTimer(startApplyNanos - startDispatchNanos); + requestMeta.setStartApplyNanos(startApplyNanos); // If current req is supposed to be process, load this event through // DataRegionStateMachine. TPipeConsensusTransferResp resp = loadEvent(req); @@ -1164,19 +1246,22 @@ private TPipeConsensusTransferResp onRequest( // when the last seal req is applied, we can discard this event. if (resp != null && resp.getStatus().getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { - onSuccess(onSyncedCommitIndex + 1); + onSuccess(onSyncedCommitIndex + 1, isTransferTsFileSeal); } return resp; } if (reqExecutionOrderBuffer.size() >= IOTDB_CONFIG.getPipeConsensusPipelineSize() - && reqExecutionOrderBuffer.first().equals(tCommitId)) { + && reqExecutionOrderBuffer.first().equals(requestMeta)) { + long startApplyNanos = System.nanoTime(); + metric.recordDispatchWaitingTimer(startApplyNanos - startDispatchNanos); + requestMeta.setStartApplyNanos(startApplyNanos); // If the reqBuffer is full and its peek is hold by current thread, load this event. TPipeConsensusTransferResp resp = loadEvent(req); if (resp != null && resp.getStatus().getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { - onSuccess(tCommitId.getCommitIndex()); + onSuccess(tCommitId.getCommitIndex(), isTransferTsFileSeal); // signal all other reqs that may wait for this event condition.signalAll(); } @@ -1196,12 +1281,15 @@ private TPipeConsensusTransferResp onRequest( if (timeout && reqExecutionOrderBuffer.size() < IOTDB_CONFIG.getPipeConsensusPipelineSize() && reqExecutionOrderBuffer.first() != null - && reqExecutionOrderBuffer.first().equals(tCommitId)) { + && reqExecutionOrderBuffer.first().equals(requestMeta)) { + long startApplyNanos = System.nanoTime(); + metric.recordDispatchWaitingTimer(startApplyNanos - startDispatchNanos); + requestMeta.setStartApplyNanos(startApplyNanos); TPipeConsensusTransferResp resp = loadEvent(req); if (resp != null && resp.getStatus().getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { - onSuccess(tCommitId.getCommitIndex()); + onSuccess(tCommitId.getCommitIndex(), isTransferTsFileSeal); // signal all other reqs that may wait for this event condition.signalAll(); } @@ -1209,8 +1297,8 @@ private TPipeConsensusTransferResp onRequest( } } catch (InterruptedException e) { LOGGER.warn( - "PipeConsensus-ConsensusGroup-{}: current waiting is interrupted. onSyncedCommitIndex: {}. Exception: ", - consensusGroupId, + "PipeConsensus-PipeName-{}: current waiting is interrupted. onSyncedCommitIndex: {}. Exception: ", + consensusPipeName, tCommitId.getCommitIndex(), e); Thread.currentThread().interrupt(); @@ -1233,12 +1321,76 @@ private TPipeConsensusTransferResp onRequest( */ private void resetWithNewestRebootTime(int connectorRebootTimes) { LOGGER.info( - "PipeConsensus-ConsensusGroup-{}: receiver detected an newer rebootTimes, which indicates the leader has rebooted. receiver will reset all its data.", - consensusGroupId); + "PipeConsensus-PipeName-{}: receiver detected an newer rebootTimes, which indicates the leader has rebooted. receiver will reset all its data.", + consensusPipeName); this.reqExecutionOrderBuffer.clear(); this.onSyncedCommitIndex = -1; // sync the follower's connectorRebootTimes with connector's actual rebootTimes this.connectorRebootTimes = connectorRebootTimes; } } + + private static class RequestMeta { + private final TCommitId commitId; + private long startApplyNanos = 0; + + public RequestMeta(TCommitId commitId) { + this.commitId = commitId; + } + + public int getRebootTimes() { + return commitId.getRebootTimes(); + } + + public long getCommitIndex() { + return commitId.getCommitIndex(); + } + + public void setStartApplyNanos(long startApplyNanos) { + // Notice that a tsFileInsertionEvent will enter RequestExecutor multiple times, we only need + // to record the time of the first apply + if (startApplyNanos == 0) { + this.startApplyNanos = startApplyNanos; + } + } + + public long getStartApplyNanos() { + return startApplyNanos; + } + + @Override + public boolean equals(Object o) { + if (this == o) { + return true; + } + if (o == null || getClass() != o.getClass()) { + return false; + } + RequestMeta that = (RequestMeta) o; + return commitId.equals(that.commitId); + } + + @Override + public int hashCode() { + return Objects.hash(commitId); + } + } + + //////////////////////////// APIs provided for metric framework //////////////////////////// + + public int getReceiveBufferSize() { + return this.requestExecutor.reqExecutionOrderBuffer.size(); + } + + public int getWALEventCount() { + return this.requestExecutor.WALEventCount; + } + + public int getTsFileEventCount() { + return this.requestExecutor.tsFileEventCount; + } + + public String getConsensusGroupIdStr() { + return consensusGroupId.toString(); + } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/receiver/protocol/thrift/IoTDBDataNodeReceiver.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/receiver/protocol/thrift/IoTDBDataNodeReceiver.java index 55fe372ea8f35..da7065392786a 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/receiver/protocol/thrift/IoTDBDataNodeReceiver.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/receiver/protocol/thrift/IoTDBDataNodeReceiver.java @@ -34,7 +34,7 @@ import org.apache.iotdb.db.conf.IoTDBConfig; import org.apache.iotdb.db.conf.IoTDBDescriptor; import org.apache.iotdb.db.exception.DiskSpaceInsufficientException; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.connector.payload.evolvable.request.PipeTransferDataNodeHandshakeV1Req; import org.apache.iotdb.db.pipe.connector.payload.evolvable.request.PipeTransferDataNodeHandshakeV2Req; import org.apache.iotdb.db.pipe.connector.payload.evolvable.request.PipeTransferPlanNodeReq; @@ -356,7 +356,7 @@ private String getConfigReceiverId() { configReceiverId.set( IoTDBDescriptor.getInstance().getConfig().getDataNodeId() + "_" - + PipeAgent.runtime().getRebootTimes() + + PipeDataNodeAgent.runtime().getRebootTimes() + "_" + CONFIG_RECEIVER_ID_GENERATOR.incrementAndGet()); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/receiver/visitor/PipeStatementExceptionVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/receiver/visitor/PipeStatementExceptionVisitor.java index 7cbe5bed4167b..5a65b1a5e0577 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/receiver/visitor/PipeStatementExceptionVisitor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/receiver/visitor/PipeStatementExceptionVisitor.java @@ -61,7 +61,7 @@ public TSStatus visitLoadFile( return new TSStatus(TSStatusCode.PIPE_RECEIVER_USER_CONFLICT_EXCEPTION.getStatusCode()) .setMessage(context.getMessage()); } - return super.visitLoadFile(loadTsFileStatement, context); + return visitStatement(loadTsFileStatement, context); } @Override diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/receiver/visitor/PipeStatementTSStatusVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/receiver/visitor/PipeStatementTSStatusVisitor.java index be4ee14ff02f7..03a917379ceb1 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/receiver/visitor/PipeStatementTSStatusVisitor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/receiver/visitor/PipeStatementTSStatusVisitor.java @@ -31,6 +31,7 @@ import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertRowStatement; import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertRowsStatement; import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertTabletStatement; +import org.apache.iotdb.db.queryengine.plan.statement.crud.LoadTsFileStatement; import org.apache.iotdb.db.queryengine.plan.statement.internal.InternalCreateMultiTimeSeriesStatement; import org.apache.iotdb.db.queryengine.plan.statement.internal.InternalCreateTimeSeriesStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.AlterTimeSeriesStatement; @@ -56,6 +57,20 @@ public TSStatus visitNode(final StatementNode node, final TSStatus context) { return context; } + @Override + public TSStatus visitLoadFile( + final LoadTsFileStatement loadTsFileStatement, final TSStatus context) { + if (context.getCode() == TSStatusCode.SYSTEM_READ_ONLY.getStatusCode() + || context.getCode() == TSStatusCode.LOAD_FILE_ERROR.getStatusCode() + && context.getMessage() != null + && context.getMessage().contains("memory")) { + return new TSStatus( + TSStatusCode.PIPE_RECEIVER_TEMPORARY_UNAVAILABLE_EXCEPTION.getStatusCode()) + .setMessage(context.getMessage()); + } + return super.visitLoadFile(loadTsFileStatement, context); + } + @Override public TSStatus visitInsertTablet( final InsertTabletStatement insertTabletStatement, final TSStatus context) { @@ -82,17 +97,17 @@ public TSStatus visitInsertMultiTablets( private TSStatus visitInsertBase( final InsertBaseStatement insertBaseStatement, final TSStatus context) { - if (context.getCode() == TSStatusCode.OUT_OF_TTL.getStatusCode()) { + if (context.getCode() == TSStatusCode.SYSTEM_READ_ONLY.getStatusCode()) { + return new TSStatus( + TSStatusCode.PIPE_RECEIVER_TEMPORARY_UNAVAILABLE_EXCEPTION.getStatusCode()) + .setMessage(context.getMessage()); + } else if (context.getCode() == TSStatusCode.OUT_OF_TTL.getStatusCode()) { return new TSStatus(TSStatusCode.PIPE_RECEIVER_IDEMPOTENT_CONFLICT_EXCEPTION.getStatusCode()) .setMessage(context.getMessage()); - } else if (context.getCode() == TSStatusCode.METADATA_ERROR.getStatusCode()) { - if (context.getMessage().contains(DataTypeMismatchException.REGISTERED_TYPE_STRING) - && config.isEnablePartialInsert()) { - return new TSStatus( - TSStatusCode.PIPE_RECEIVER_IDEMPOTENT_CONFLICT_EXCEPTION.getStatusCode()) - .setMessage(context.getMessage()); - } - return new TSStatus(TSStatusCode.PIPE_RECEIVER_USER_CONFLICT_EXCEPTION.getStatusCode()) + } else if (context.getCode() == TSStatusCode.METADATA_ERROR.getStatusCode() + && (context.getMessage().contains(DataTypeMismatchException.REGISTERED_TYPE_STRING) + && config.isEnablePartialInsert())) { + return new TSStatus(TSStatusCode.PIPE_RECEIVER_IDEMPOTENT_CONFLICT_EXCEPTION.getStatusCode()) .setMessage(context.getMessage()); } return visitStatement(insertBaseStatement, context); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/memory/PipeMemoryManager.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/memory/PipeMemoryManager.java index 39ee92809104a..0eac840f58c39 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/memory/PipeMemoryManager.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/memory/PipeMemoryManager.java @@ -22,7 +22,7 @@ import org.apache.iotdb.commons.exception.pipe.PipeRuntimeOutOfMemoryCriticalException; import org.apache.iotdb.commons.pipe.config.PipeConfig; import org.apache.iotdb.db.conf.IoTDBDescriptor; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.tsfile.enums.TSDataType; import org.apache.tsfile.utils.Binary; @@ -66,7 +66,7 @@ public class PipeMemoryManager { private final Set allocatedBlocks = new HashSet<>(); public PipeMemoryManager() { - PipeAgent.runtime() + PipeDataNodeAgent.runtime() .registerPeriodicalJob( "PipeMemoryManager#tryExpandAll()", this::tryExpandAll, diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/tsfile/PipeTsFileResourceManager.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/tsfile/PipeTsFileResourceManager.java index 0d064cd8b067c..1cf6732786e7b 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/tsfile/PipeTsFileResourceManager.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/tsfile/PipeTsFileResourceManager.java @@ -22,7 +22,7 @@ import org.apache.iotdb.commons.conf.IoTDBConstant; import org.apache.iotdb.commons.pipe.config.PipeConfig; import org.apache.iotdb.commons.utils.FileUtils; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.agent.runtime.PipePeriodicalJobExecutor; import org.apache.iotdb.db.pipe.resource.PipeResourceManager; import org.apache.iotdb.db.storageengine.dataregion.modification.ModificationFile; @@ -52,7 +52,7 @@ public class PipeTsFileResourceManager { private final ReentrantLock lock = new ReentrantLock(); public PipeTsFileResourceManager() { - PipeAgent.runtime() + PipeDataNodeAgent.runtime() .registerPeriodicalJob( "PipeTsFileResourceManager#ttlCheck()", this::tryTtlCheck, @@ -71,7 +71,7 @@ private void tryTtlCheck() { } else { LOGGER.warn("failed to try lock when checking TTL because of timeout ({}s)", timeout); } - } catch (InterruptedException e) { + } catch (final InterruptedException e) { Thread.currentThread().interrupt(); LOGGER.warn("failed to try lock when checking TTL because of interruption", e); } @@ -102,7 +102,7 @@ private void ttlCheck() { entry.getKey(), entry.getValue().getReferenceCount())); } - } catch (IOException e) { + } catch (final IOException e) { LOGGER.warn("failed to close PipeTsFileResource when checking TTL: ", e); } } @@ -129,7 +129,8 @@ private void ttlCheck() { * @return the hardlink or copied file * @throws IOException when create hardlink or copy file failed */ - public File increaseFileReference(File file, boolean isTsFile, TsFileResource tsFileResource) + public File increaseFileReference( + final File file, final boolean isTsFile, final TsFileResource tsFileResource) throws IOException { lock.lock(); try { @@ -165,7 +166,7 @@ public File increaseFileReference(File file, boolean isTsFile, TsFileResource ts } } - private boolean increaseReferenceIfExists(String path) { + private boolean increaseReferenceIfExists(final String path) { final PipeTsFileResource resource = hardlinkOrCopiedFileToPipeTsFileResourceMap.get(path); if (resource != null) { resource.increaseAndGetReference(); @@ -174,10 +175,10 @@ private boolean increaseReferenceIfExists(String path) { return false; } - private static File getHardlinkOrCopiedFileInPipeDir(File file) throws IOException { + public static File getHardlinkOrCopiedFileInPipeDir(final File file) throws IOException { try { return new File(getPipeTsFileDirPath(file), getRelativeFilePath(file)); - } catch (Exception e) { + } catch (final Exception e) { throw new IOException( String.format( "failed to get hardlink or copied file in pipe dir " @@ -218,7 +219,7 @@ private static String getRelativeFilePath(File file) { * * @param hardlinkOrCopiedFile the copied or hardlinked file */ - public void decreaseFileReference(File hardlinkOrCopiedFile) { + public void decreaseFileReference(final File hardlinkOrCopiedFile) { lock.lock(); try { final String filePath = hardlinkOrCopiedFile.getPath(); @@ -237,7 +238,7 @@ public void decreaseFileReference(File hardlinkOrCopiedFile) { * @param hardlinkOrCopiedFile the copied or hardlinked file * @return the reference count of the file */ - public int getFileReferenceCount(File hardlinkOrCopiedFile) { + public int getFileReferenceCount(final File hardlinkOrCopiedFile) { lock.lock(); try { final String filePath = hardlinkOrCopiedFile.getPath(); @@ -254,7 +255,7 @@ public int getFileReferenceCount(File hardlinkOrCopiedFile) { * @return {@code true} if the maps are successfully put into cache or already cached. {@code * false} if they can not be cached. */ - public boolean cacheObjectsIfAbsent(File hardlinkOrCopiedTsFile) throws IOException { + public boolean cacheObjectsIfAbsent(final File hardlinkOrCopiedTsFile) throws IOException { lock.lock(); try { final PipeTsFileResource resource = @@ -265,8 +266,8 @@ public boolean cacheObjectsIfAbsent(File hardlinkOrCopiedTsFile) throws IOExcept } } - public Map> getDeviceMeasurementsMapFromCache(File hardlinkOrCopiedTsFile) - throws IOException { + public Map> getDeviceMeasurementsMapFromCache( + final File hardlinkOrCopiedTsFile) throws IOException { lock.lock(); try { final PipeTsFileResource resource = @@ -277,7 +278,7 @@ public Map> getDeviceMeasurementsMapFromCache(File hardl } } - public Map getDeviceIsAlignedMapFromCache(File hardlinkOrCopiedTsFile) + public Map getDeviceIsAlignedMapFromCache(final File hardlinkOrCopiedTsFile) throws IOException { lock.lock(); try { @@ -289,8 +290,8 @@ public Map getDeviceIsAlignedMapFromCache(File hardlinkOrCop } } - public Map getMeasurementDataTypeMapFromCache(File hardlinkOrCopiedTsFile) - throws IOException { + public Map getMeasurementDataTypeMapFromCache( + final File hardlinkOrCopiedTsFile) throws IOException { lock.lock(); try { final PipeTsFileResource resource = @@ -301,7 +302,8 @@ public Map getMeasurementDataTypeMapFromCache(File hardlinkO } } - public void pinTsFileResource(TsFileResource resource, boolean withMods) throws IOException { + public void pinTsFileResource(final TsFileResource resource, final boolean withMods) + throws IOException { lock.lock(); try { increaseFileReference(resource.getTsFile(), true, resource); @@ -313,13 +315,13 @@ public void pinTsFileResource(TsFileResource resource, boolean withMods) throws } } - public void unpinTsFileResource(TsFileResource resource) throws IOException { + public void unpinTsFileResource(final TsFileResource resource) throws IOException { lock.lock(); try { - File pinnedFile = getHardlinkOrCopiedFileInPipeDir(resource.getTsFile()); + final File pinnedFile = getHardlinkOrCopiedFileInPipeDir(resource.getTsFile()); decreaseFileReference(pinnedFile); - File modFile = new File(pinnedFile + ModificationFile.FILE_SUFFIX); + final File modFile = new File(pinnedFile + ModificationFile.FILE_SUFFIX); if (modFile.exists()) { decreaseFileReference(modFile); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/wal/PipeWALResourceManager.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/wal/PipeWALResourceManager.java index 7e0adbacd3208..06b5d68ef96af 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/wal/PipeWALResourceManager.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/resource/wal/PipeWALResourceManager.java @@ -20,7 +20,7 @@ package org.apache.iotdb.db.pipe.resource.wal; import org.apache.iotdb.commons.pipe.config.PipeConfig; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.resource.PipeResourceManager; import org.apache.iotdb.db.storageengine.dataregion.wal.utils.WALEntryHandler; @@ -54,7 +54,7 @@ protected PipeWALResourceManager() { memtableIdSegmentLocks[i] = new ReentrantLock(); } - PipeAgent.runtime() + PipeDataNodeAgent.runtime() .registerPeriodicalJob( "PipeWALResourceManager#ttlCheck()", this::ttlCheck, diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/builder/PipeDataNodeTaskBuilder.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/builder/PipeDataNodeTaskBuilder.java index e84f93e34ce33..04d5ece6e3b02 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/builder/PipeDataNodeTaskBuilder.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/builder/PipeDataNodeTaskBuilder.java @@ -54,7 +54,7 @@ public class PipeDataNodeTaskBuilder { CONNECTOR_EXECUTOR_MAP.put( PipeType.SUBSCRIPTION, PipeSubtaskExecutorManager.getInstance().getSubscriptionExecutor()); CONNECTOR_EXECUTOR_MAP.put( - PipeType.CONSENSUS, PipeSubtaskExecutorManager.getInstance().getConnectorExecutor()); + PipeType.CONSENSUS, PipeSubtaskExecutorManager.getInstance().getConsensusExecutor()); } protected final Map systemParameters = new HashMap<>(); @@ -89,7 +89,7 @@ public PipeDataNodeTask build() { blendUserAndSystemParameters(pipeStaticMeta.getConnectorParameters()), regionId, CONNECTOR_EXECUTOR_MAP.get(pipeType)); - } else { // user pipe + } else { // user pipe or consensus pipe connectorStage = new PipeTaskConnectorStage( pipeStaticMeta.getPipeName(), diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/connection/PipeEventCollector.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/connection/PipeEventCollector.java index 1df20db17f635..ddc7ee5a2d339 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/connection/PipeEventCollector.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/connection/PipeEventCollector.java @@ -24,13 +24,14 @@ import org.apache.iotdb.commons.pipe.pattern.IoTDBPipePattern; import org.apache.iotdb.commons.pipe.progress.PipeEventCommitManager; import org.apache.iotdb.commons.pipe.task.connection.UnboundedBlockingPendingQueue; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.event.common.heartbeat.PipeHeartbeatEvent; import org.apache.iotdb.db.pipe.event.common.schema.PipeSchemaRegionWritePlanEvent; import org.apache.iotdb.db.pipe.event.common.tablet.PipeInsertNodeTabletInsertionEvent; import org.apache.iotdb.db.pipe.event.common.tablet.PipeRawTabletInsertionEvent; import org.apache.iotdb.db.pipe.event.common.tsfile.PipeTsFileInsertionEvent; import org.apache.iotdb.db.pipe.extractor.schemaregion.IoTDBSchemaRegionExtractor; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeType; import org.apache.iotdb.pipe.api.collector.EventCollector; import org.apache.iotdb.pipe.api.event.Event; import org.apache.iotdb.pipe.api.event.dml.insertion.TabletInsertionEvent; @@ -71,7 +72,11 @@ public void collect(final Event event) { parseAndCollectEvent((PipeRawTabletInsertionEvent) event); } else if (event instanceof PipeTsFileInsertionEvent) { parseAndCollectEvent((PipeTsFileInsertionEvent) event); - } else if (event instanceof PipeSchemaRegionWritePlanEvent) { + } else if (event instanceof PipeSchemaRegionWritePlanEvent + && ((PipeSchemaRegionWritePlanEvent) event).getPlanNode().getType() + == PlanNodeType.DELETE_DATA) { + // This is only for delete data node in data region since plan nodes in schema regions are + // already parsed in schema region extractor parseAndCollectEvent((PipeSchemaRegionWritePlanEvent) event); } else if (!(event instanceof ProgressReportEvent)) { collectEvent(event); @@ -128,6 +133,8 @@ private void parseAndCollectEvent(final PipeTsFileInsertionEvent sourceEvent) th } private void parseAndCollectEvent(final PipeSchemaRegionWritePlanEvent deleteDataEvent) { + // Only used by events containing delete data node, no need to bind progress index here since + // delete data event does not have progress index currently IoTDBSchemaRegionExtractor.PATTERN_PARSE_VISITOR .process(deleteDataEvent.getPlanNode(), (IoTDBPipePattern) deleteDataEvent.getPipePattern()) .map( @@ -135,6 +142,7 @@ private void parseAndCollectEvent(final PipeSchemaRegionWritePlanEvent deleteDat new PipeSchemaRegionWritePlanEvent( planNode, deleteDataEvent.getPipeName(), + deleteDataEvent.getCreationTime(), deleteDataEvent.getPipeTaskMeta(), deleteDataEvent.getPipePattern(), deleteDataEvent.isGeneratedByPipe())) @@ -152,7 +160,7 @@ private void collectEvent(final Event event) { .enrichWithCommitterKeyAndCommitId((EnrichedEvent) event, creationTime, regionId); // Assign a rebootTime for pipeConsensus - ((EnrichedEvent) event).setRebootTimes(PipeAgent.runtime().getRebootTimes()); + ((EnrichedEvent) event).setRebootTimes(PipeDataNodeAgent.runtime().getRebootTimes()); } if (event instanceof PipeHeartbeatEvent) { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/stage/PipeTaskExtractorStage.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/stage/PipeTaskExtractorStage.java index 06206b03bffde..32b8ca8f77543 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/stage/PipeTaskExtractorStage.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/stage/PipeTaskExtractorStage.java @@ -25,7 +25,7 @@ import org.apache.iotdb.commons.pipe.task.EventSupplier; import org.apache.iotdb.commons.pipe.task.meta.PipeTaskMeta; import org.apache.iotdb.commons.pipe.task.stage.PipeTaskStage; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.storageengine.StorageEngine; import org.apache.iotdb.pipe.api.PipeExtractor; import org.apache.iotdb.pipe.api.customizer.parameter.PipeParameterValidator; @@ -49,8 +49,8 @@ public PipeTaskExtractorStage( PipeTaskMeta pipeTaskMeta) { pipeExtractor = StorageEngine.getInstance().getAllDataRegionIds().contains(new DataRegionId(regionId)) - ? PipeAgent.plugin().dataRegion().reflectExtractor(extractorParameters) - : PipeAgent.plugin().schemaRegion().reflectExtractor(extractorParameters); + ? PipeDataNodeAgent.plugin().dataRegion().reflectExtractor(extractorParameters) + : PipeDataNodeAgent.plugin().schemaRegion().reflectExtractor(extractorParameters); // Validate and customize should be called before createSubtask. this allows extractor exposing // exceptions in advance. diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/stage/PipeTaskProcessorStage.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/stage/PipeTaskProcessorStage.java index c7ceaf1f97845..37d3e14ddc542 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/stage/PipeTaskProcessorStage.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/stage/PipeTaskProcessorStage.java @@ -28,7 +28,7 @@ import org.apache.iotdb.commons.pipe.task.connection.UnboundedBlockingPendingQueue; import org.apache.iotdb.commons.pipe.task.meta.PipeTaskMeta; import org.apache.iotdb.commons.pipe.task.stage.PipeTaskStage; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.execution.PipeProcessorSubtaskExecutor; import org.apache.iotdb.db.pipe.task.connection.PipeEventCollector; import org.apache.iotdb.db.pipe.task.subtask.processor.PipeProcessorSubtask; @@ -74,7 +74,7 @@ public PipeTaskProcessorStage( pipeName, creationTime, regionId, pipeTaskMeta)); final PipeProcessor pipeProcessor = StorageEngine.getInstance().getAllDataRegionIds().contains(new DataRegionId(regionId)) - ? PipeAgent.plugin() + ? PipeDataNodeAgent.plugin() .dataRegion() .getConfiguredProcessor( pipeProcessorParameters.getStringOrDefault( @@ -82,7 +82,7 @@ public PipeTaskProcessorStage( BuiltinPipePlugin.DO_NOTHING_PROCESSOR.getPipePluginName()), pipeProcessorParameters, runtimeConfiguration) - : PipeAgent.plugin() + : PipeDataNodeAgent.plugin() .schemaRegion() .getConfiguredProcessor( pipeProcessorParameters.getStringOrDefault( diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/subtask/connector/PipeConnectorSubtask.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/subtask/connector/PipeConnectorSubtask.java index 40ac29eaa8198..cae631021118b 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/subtask/connector/PipeConnectorSubtask.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/subtask/connector/PipeConnectorSubtask.java @@ -24,7 +24,7 @@ import org.apache.iotdb.commons.pipe.event.EnrichedEvent; import org.apache.iotdb.commons.pipe.task.connection.UnboundedBlockingPendingQueue; import org.apache.iotdb.commons.pipe.task.subtask.PipeAbstractConnectorSubtask; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.connector.protocol.thrift.async.IoTDBDataRegionAsyncConnector; import org.apache.iotdb.db.pipe.event.UserDefinedEnrichedEvent; import org.apache.iotdb.db.pipe.event.common.heartbeat.PipeHeartbeatEvent; @@ -32,6 +32,7 @@ import org.apache.iotdb.db.pipe.metric.PipeDataRegionConnectorMetrics; import org.apache.iotdb.db.pipe.metric.PipeSchemaRegionConnectorMetrics; import org.apache.iotdb.db.pipe.task.connection.PipeEventCollector; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeType; import org.apache.iotdb.db.utils.ErrorHandlingUtils; import org.apache.iotdb.pipe.api.PipeConnector; import org.apache.iotdb.pipe.api.event.Event; @@ -43,6 +44,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Objects; import java.util.concurrent.atomic.AtomicInteger; public class PipeConnectorSubtask extends PipeAbstractConnectorSubtask { @@ -115,7 +117,12 @@ protected boolean executeOnce() { PipeDataRegionConnectorMetrics.getInstance().markTsFileEvent(taskID); } else if (event instanceof PipeSchemaRegionWritePlanEvent) { outputPipeConnector.transfer(event); - PipeSchemaRegionConnectorMetrics.getInstance().markSchemaEvent(taskID); + if (((PipeSchemaRegionWritePlanEvent) event).getPlanNode().getType() + != PlanNodeType.DELETE_DATA) { + // Only plan nodes in schema region will be marked, delete data node is currently not + // taken into account + PipeSchemaRegionConnectorMetrics.getInstance().markSchemaEvent(taskID); + } } else if (event instanceof PipeHeartbeatEvent) { transferHeartbeatEvent((PipeHeartbeatEvent) event); } else { @@ -227,15 +234,18 @@ public int getConnectorIndex() { } public int getTsFileInsertionEventCount() { - return inputPendingQueue.getTsFileInsertionEventCount(); + return inputPendingQueue.getTsFileInsertionEventCount() + + (lastEvent instanceof TsFileInsertionEvent ? 1 : 0); } public int getTabletInsertionEventCount() { - return inputPendingQueue.getTabletInsertionEventCount(); + return inputPendingQueue.getTabletInsertionEventCount() + + (lastEvent instanceof TabletInsertionEvent ? 1 : 0); } public int getPipeHeartbeatEventCount() { - return inputPendingQueue.getPipeHeartbeatEventCount(); + return inputPendingQueue.getPipeHeartbeatEventCount() + + (lastEvent instanceof PipeHeartbeatEvent ? 1 : 0); } public int getAsyncConnectorRetryEventQueueSize() { @@ -256,7 +266,7 @@ public int getEventCount(final String pipeName) { count.incrementAndGet(); } }); - } catch (Exception e) { + } catch (final Exception e) { if (LOGGER.isDebugEnabled()) { LOGGER.debug( "Exception occurred when counting event of pipe {}, root cause: {}", @@ -265,10 +275,14 @@ public int getEventCount(final String pipeName) { e); } } + // Avoid potential NPE in "getPipeName" + final EnrichedEvent event = + lastEvent instanceof EnrichedEvent ? (EnrichedEvent) lastEvent : null; return count.get() + (outputPipeConnector instanceof IoTDBDataRegionAsyncConnector ? ((IoTDBDataRegionAsyncConnector) outputPipeConnector).getRetryEventCount(pipeName) - : 0); + : 0) + + (Objects.nonNull(event) && pipeName.equals(event.getPipeName()) ? 1 : 0); } //////////////////////////// Error report //////////////////////////// @@ -280,6 +294,6 @@ protected String getRootCause(final Throwable throwable) { @Override protected void report(final EnrichedEvent event, final PipeRuntimeException exception) { - PipeAgent.runtime().report(event, exception); + PipeDataNodeAgent.runtime().report(event, exception); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/subtask/connector/PipeConnectorSubtaskManager.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/subtask/connector/PipeConnectorSubtaskManager.java index d85f04b68eafc..f8809b6b689a1 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/subtask/connector/PipeConnectorSubtaskManager.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/subtask/connector/PipeConnectorSubtaskManager.java @@ -27,7 +27,7 @@ import org.apache.iotdb.commons.pipe.plugin.builtin.BuiltinPipePlugin; import org.apache.iotdb.commons.pipe.progress.PipeEventCommitManager; import org.apache.iotdb.commons.pipe.task.connection.UnboundedBlockingPendingQueue; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.execution.PipeConnectorSubtaskExecutor; import org.apache.iotdb.db.pipe.metric.PipeDataNodeRemainingEventAndTimeMetrics; import org.apache.iotdb.db.pipe.metric.PipeDataRegionEventCounter; @@ -119,8 +119,10 @@ public synchronized String register( for (int connectorIndex = 0; connectorIndex < connectorNum; connectorIndex++) { final PipeConnector pipeConnector = isDataRegionConnector - ? PipeAgent.plugin().dataRegion().reflectConnector(pipeConnectorParameters) - : PipeAgent.plugin().schemaRegion().reflectConnector(pipeConnectorParameters); + ? PipeDataNodeAgent.plugin().dataRegion().reflectConnector(pipeConnectorParameters) + : PipeDataNodeAgent.plugin() + .schemaRegion() + .reflectConnector(pipeConnectorParameters); // 1. Construct, validate and customize PipeConnector, and then handshake (create // connection) with the target try { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/subtask/processor/PipeProcessorSubtask.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/subtask/processor/PipeProcessorSubtask.java index 2b48becaed2ad..8ead33deb79d4 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/subtask/processor/PipeProcessorSubtask.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/subtask/processor/PipeProcessorSubtask.java @@ -27,10 +27,12 @@ import org.apache.iotdb.commons.pipe.progress.PipeEventCommitManager; import org.apache.iotdb.commons.pipe.task.EventSupplier; import org.apache.iotdb.commons.pipe.task.subtask.PipeReportableSubtask; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.event.UserDefinedEnrichedEvent; import org.apache.iotdb.db.pipe.event.common.heartbeat.PipeHeartbeatEvent; +import org.apache.iotdb.db.pipe.metric.PipeDataNodeRemainingEventAndTimeMetrics; import org.apache.iotdb.db.pipe.metric.PipeProcessorMetrics; +import org.apache.iotdb.db.pipe.processor.pipeconsensus.PipeConsensusProcessor; import org.apache.iotdb.db.pipe.task.connection.PipeEventCollector; import org.apache.iotdb.db.storageengine.StorageEngine; import org.apache.iotdb.db.utils.ErrorHandlingUtils; @@ -86,6 +88,7 @@ public PipeProcessorSubtask( // Only register dataRegions if (StorageEngine.getInstance().getAllDataRegionIds().contains(new DataRegionId(regionId))) { PipeProcessorMetrics.getInstance().register(this); + PipeDataNodeRemainingEventAndTimeMetrics.getInstance().register(this); } } @@ -148,8 +151,12 @@ protected boolean executeOnce() throws Exception { outputEventCollector); } } + final boolean shouldReport = - !isClosed.get() && outputEventCollector.hasNoCollectInvocationAfterReset(); + !isClosed.get() + && outputEventCollector.hasNoCollectInvocationAfterReset() + // Events generated from consensusPipe's transferred data should never be reported. + && !(pipeProcessor instanceof PipeConsensusProcessor); if (shouldReport && event instanceof EnrichedEvent) { PipeEventCommitManager.getInstance() .enrichWithCommitterKeyAndCommitId((EnrichedEvent) event, creationTime, regionId); @@ -244,6 +251,15 @@ public int getRegionId() { return regionId; } + public int getEventCount(final boolean ignoreHeartbeat) { + // Avoid potential NPE in "getPipeName" + final EnrichedEvent event = + lastEvent instanceof EnrichedEvent ? (EnrichedEvent) lastEvent : null; + return Objects.nonNull(event) && !(ignoreHeartbeat && event instanceof PipeHeartbeatEvent) + ? 1 + : 0; + } + //////////////////////////// Error report //////////////////////////// @Override @@ -253,6 +269,6 @@ protected String getRootCause(final Throwable throwable) { @Override protected void report(final EnrichedEvent event, final PipeRuntimeException exception) { - PipeAgent.runtime().report(event, exception); + PipeDataNodeAgent.runtime().report(event, exception); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/subtask/processor/PipeProcessorSubtaskWorker.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/subtask/processor/PipeProcessorSubtaskWorker.java index 64f01b24105e5..684fa5ebb0c9a 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/subtask/processor/PipeProcessorSubtaskWorker.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/pipe/task/subtask/processor/PipeProcessorSubtaskWorker.java @@ -24,8 +24,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Collections; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; import java.util.stream.Collectors; public class PipeProcessorSubtaskWorker extends WrappedRunnable { @@ -40,8 +41,8 @@ public class PipeProcessorSubtaskWorker extends WrappedRunnable { private int workingRoundInAdjustmentInterval = 0; private long sleepingTimeInMilliSecond = 50; - private final ConcurrentMap subtasks = - new ConcurrentHashMap<>(); + private final Set subtasks = + Collections.newSetFromMap(new ConcurrentHashMap<>()); @Override @SuppressWarnings("squid:S2189") @@ -56,7 +57,7 @@ public void runMayThrow() { private void cleanupClosedSubtasksIfNecessary() { if (++closedSubtaskCleanupRoundCounter % CLOSED_SUBTASK_CLEANUP_ROUND_INTERVAL == 0) { - subtasks.keySet().stream() + subtasks.stream() .filter(PipeProcessorSubtask::isClosed) .collect(Collectors.toList()) .forEach(subtasks::remove); @@ -68,7 +69,7 @@ private boolean runSubtasks() { boolean canSleepBeforeNextRound = true; - for (final PipeProcessorSubtask subtask : subtasks.keySet()) { + for (final PipeProcessorSubtask subtask : subtasks) { if (subtask.isClosed() || !subtask.isSubmittingSelf() || subtask.isStoppedByException()) { continue; } @@ -79,7 +80,7 @@ private boolean runSubtasks() { canSleepBeforeNextRound = false; } subtask.onSuccess(hasAtLeastOneEventProcessed); - } catch (Exception e) { + } catch (final Exception e) { if (subtask.isClosed()) { LOGGER.warn("subtask {} is closed, ignore exception", subtask, e); } else { @@ -91,11 +92,11 @@ private boolean runSubtasks() { return canSleepBeforeNextRound; } - private void sleepIfNecessary(boolean canSleepBeforeNextRound) { + private void sleepIfNecessary(final boolean canSleepBeforeNextRound) { if (canSleepBeforeNextRound) { try { Thread.sleep(sleepingTimeInMilliSecond); - } catch (InterruptedException e) { + } catch (final InterruptedException e) { LOGGER.warn("subtask worker is interrupted", e); Thread.currentThread().interrupt(); } @@ -122,7 +123,7 @@ private void adjustSleepingTimeIfNecessary() { } } - public void schedule(PipeProcessorSubtask pipeProcessorSubtask) { - subtasks.put(pipeProcessorSubtask, pipeProcessorSubtask); + public void schedule(final PipeProcessorSubtask pipeProcessorSubtask) { + subtasks.add(pipeProcessorSubtask); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/ConfigNodeClient.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/ConfigNodeClient.java index b8bb9a26f21e6..0b5ec89dacfbd 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/ConfigNodeClient.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/ConfigNodeClient.java @@ -23,12 +23,15 @@ import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; import org.apache.iotdb.common.rpc.thrift.TEndPoint; import org.apache.iotdb.common.rpc.thrift.TFlushReq; +import org.apache.iotdb.common.rpc.thrift.TNodeLocations; import org.apache.iotdb.common.rpc.thrift.TSStatus; import org.apache.iotdb.common.rpc.thrift.TSetConfigurationReq; import org.apache.iotdb.common.rpc.thrift.TSetSpaceQuotaReq; import org.apache.iotdb.common.rpc.thrift.TSetTTLReq; import org.apache.iotdb.common.rpc.thrift.TSetThrottleQuotaReq; import org.apache.iotdb.common.rpc.thrift.TShowConfigurationResp; +import org.apache.iotdb.common.rpc.thrift.TShowTTLReq; +import org.apache.iotdb.common.rpc.thrift.TTestConnectionResp; import org.apache.iotdb.commons.client.ClientManager; import org.apache.iotdb.commons.client.ThriftClient; import org.apache.iotdb.commons.client.factory.ThriftClientFactory; @@ -242,7 +245,7 @@ private void tryToConnect() throws TException { try { connect(configLeader); return; - } catch (TException e) { + } catch (TException ignore) { logger.warn("The current node may have been down {},try next node", configLeader); configLeader = null; } @@ -250,7 +253,7 @@ private void tryToConnect() throws TException { try { // Wait to start the next try Thread.sleep(RETRY_INTERVAL_MS); - } catch (InterruptedException e) { + } catch (InterruptedException ignore) { Thread.currentThread().interrupt(); logger.warn("Unexpected interruption when waiting to try to connect to ConfigNode"); } @@ -267,7 +270,7 @@ private void tryToConnect() throws TException { try { connect(tryEndpoint); return; - } catch (TException e) { + } catch (TException ignore) { logger.warn("The current node may have been down {},try next node", tryEndpoint); } } @@ -483,9 +486,9 @@ public TDatabaseSchemaResp getMatchedDatabaseSchemas(TGetDatabaseReq req) throws } @Override - public TShowTTLResp showAllTTL() throws TException { + public TShowTTLResp showTTL(TShowTTLReq req) throws TException { return executeRemoteCallWithRetry( - () -> client.showAllTTL(), resp -> !updateConfigNodeLeader(resp.status)); + () -> client.showTTL(req), resp -> !updateConfigNodeLeader(resp.status)); } public TSStatus callSpecialProcedure(TTestOperation operation) throws TException { @@ -728,6 +731,27 @@ public TShowDatabaseResp showDatabase(TGetDatabaseReq req) throws TException { () -> client.showDatabase(req), resp -> !updateConfigNodeLeader(resp.status)); } + @Override + public TTestConnectionResp submitTestConnectionTask(TNodeLocations nodeLocations) + throws TException { + return executeRemoteCallWithRetry( + () -> client.submitTestConnectionTask(nodeLocations), + resp -> !updateConfigNodeLeader(resp.getStatus())); + } + + @Override + public TTestConnectionResp submitTestConnectionTaskToLeader() throws TException { + return executeRemoteCallWithRetry( + () -> client.submitTestConnectionTaskToLeader(), + resp -> !updateConfigNodeLeader(resp.getStatus())); + } + + @Override + public TSStatus testConnectionEmptyRPC() throws TException { + return executeRemoteCallWithRetry( + () -> client.testConnectionEmptyRPC(), resp -> !updateConfigNodeLeader(resp)); + } + @Override public TRegionRouteMapResp getLatestRegionRouteMap() throws TException { return executeRemoteCallWithRetry( diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/ConfigNodeInfo.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/ConfigNodeInfo.java index d9fe03d80bc1e..256b8a0be178f 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/ConfigNodeInfo.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/ConfigNodeInfo.java @@ -22,21 +22,14 @@ import org.apache.iotdb.common.rpc.thrift.TEndPoint; import org.apache.iotdb.commons.consensus.ConfigRegionId; import org.apache.iotdb.commons.exception.BadNodeUrlException; -import org.apache.iotdb.commons.file.SystemFileFactory; -import org.apache.iotdb.commons.utils.FileUtils; +import org.apache.iotdb.commons.file.SystemPropertiesHandler; import org.apache.iotdb.commons.utils.NodeUrlUtils; -import org.apache.iotdb.db.conf.IoTDBDescriptor; +import org.apache.iotdb.db.conf.DataNodeSystemPropertiesHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileOutputStream; import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -45,13 +38,10 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; public class ConfigNodeInfo { - private static final Logger logger = LoggerFactory.getLogger(ConfigNodeInfo.class); private static final String CONFIG_NODE_LIST = "config_node_list"; - private static final String PROPERTIES_FILE_NAME = "system.properties"; - private final ReentrantReadWriteLock configNodeInfoReadWriteLock; /** latest config nodes. */ @@ -59,26 +49,11 @@ public class ConfigNodeInfo { public static final ConfigRegionId CONFIG_REGION_ID = new ConfigRegionId(0); - private final File propertiesFile; - private final File propertiesFileTmp; + SystemPropertiesHandler systemPropertiesHandler = DataNodeSystemPropertiesHandler.getInstance(); private ConfigNodeInfo() { this.configNodeInfoReadWriteLock = new ReentrantReadWriteLock(); this.onlineConfigNodes = new HashSet<>(); - propertiesFile = - SystemFileFactory.INSTANCE.getFile( - IoTDBDescriptor.getInstance().getConfig().getSystemDir() - + File.separator - + PROPERTIES_FILE_NAME); - propertiesFileTmp = - SystemFileFactory.INSTANCE.getFile(propertiesFile.getAbsolutePath() + ".tmp"); - if (propertiesFileTmp.exists()) { - try { - updatePropertiesFile(); - } catch (IOException e) { - logger.error("Update properties file fail", e); - } - } } // TODO: This needs removal of statics ... @@ -105,7 +80,7 @@ public boolean updateConfigNodeList(List latestConfigNodes) { try { onlineConfigNodes.clear(); onlineConfigNodes.addAll(latestConfigNodes); - storeConfigNode(); + storeConfigNodeList(); long endTime = System.currentTimeMillis(); logger.info( "Update ConfigNode Successfully: {}, which takes {} ms.", @@ -125,27 +100,13 @@ public boolean updateConfigNodeList(List latestConfigNodes) { * * @throws IOException if properties deserialization or configNode list serialization failed. */ - private void storeConfigNode() throws IOException { - Properties properties = new Properties(); - try (FileInputStream inputStream = new FileInputStream(propertiesFile)) { - properties.load(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); + public void storeConfigNodeList() throws IOException { + if (!systemPropertiesHandler.fileExist()) { + logger.info("System properties file not exist, not necessary to store ConfigNode list"); + return; } - properties.setProperty( + systemPropertiesHandler.put( CONFIG_NODE_LIST, NodeUrlUtils.convertTEndPointUrls(new ArrayList<>(onlineConfigNodes))); - try (FileOutputStream fileOutputStream = new FileOutputStream(propertiesFileTmp)) { - properties.store(new OutputStreamWriter(fileOutputStream, StandardCharsets.UTF_8), ""); - } - updatePropertiesFile(); - } - - private void updatePropertiesFile() throws IOException { - if (!propertiesFile.delete()) { - String msg = - String.format( - "Update %s file fail: %s", PROPERTIES_FILE_NAME, propertiesFile.getAbsoluteFile()); - throw new IOException(msg); - } - FileUtils.moveFileSafe(propertiesFileTmp, propertiesFile); } public void loadConfigNodeList() { @@ -153,12 +114,7 @@ public void loadConfigNodeList() { // properties contain CONFIG_NODE_LIST only when start as Data node try { configNodeInfoReadWriteLock.writeLock().lock(); - Properties properties = new Properties(); - try (FileInputStream inputStream = new FileInputStream(propertiesFile)) { - properties.load(new InputStreamReader(inputStream, StandardCharsets.UTF_8)); - } catch (IOException e) { - throw new RuntimeException(e); - } + Properties properties = systemPropertiesHandler.read(); if (properties.containsKey(CONFIG_NODE_LIST)) { onlineConfigNodes.clear(); @@ -170,6 +126,8 @@ public void loadConfigNodeList() { "Load ConfigNode successfully: {}, which takes {} ms.", onlineConfigNodes, (endTime - startTime)); + } catch (IOException e) { + throw new RuntimeException(e); } catch (BadNodeUrlException e) { logger.error("Cannot parse config node list in system.properties"); } finally { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/cn/AsyncConfigNodeTSStatusRPCHandler.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/cn/AsyncConfigNodeTSStatusRPCHandler.java new file mode 100644 index 0000000000000..fd1cbd539fbf0 --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/cn/AsyncConfigNodeTSStatusRPCHandler.java @@ -0,0 +1,95 @@ +/* + * 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.iotdb.db.protocol.client.cn; + +import org.apache.iotdb.common.rpc.thrift.TConfigNodeLocation; +import org.apache.iotdb.common.rpc.thrift.TSStatus; +import org.apache.iotdb.rpc.RpcUtils; +import org.apache.iotdb.rpc.TSStatusCode; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; +import java.util.concurrent.CountDownLatch; + +/** General RPC handler for TSStatus response type. */ +public class AsyncConfigNodeTSStatusRPCHandler extends ConfigNodeAsyncRequestRPCHandler { + + private static final Logger LOGGER = + LoggerFactory.getLogger(AsyncConfigNodeTSStatusRPCHandler.class); + + public AsyncConfigNodeTSStatusRPCHandler( + DnToCnRequestType requestType, + int requestId, + TConfigNodeLocation targetConfigNode, + Map configNodeLocationMap, + Map responseMap, + CountDownLatch countDownLatch) { + super( + requestType, + requestId, + targetConfigNode, + configNodeLocationMap, + responseMap, + countDownLatch); + } + + @Override + public void onComplete(TSStatus response) { + // Put response + responseMap.put(requestId, response); + + if (response.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { + // Remove only if success + nodeLocationMap.remove(requestId); + LOGGER.info("Successfully {} on ConfigNode: {}", requestType, formattedTargetLocation); + } else { + LOGGER.error( + "Failed to {} on ConfigNode: {}, response: {}", + requestType, + formattedTargetLocation, + response); + } + + // Always CountDown + countDownLatch.countDown(); + } + + @Override + public void onError(Exception e) { + String errorMsg = + "Failed to " + + requestType + + " on ConfigNode: " + + formattedTargetLocation + + ", exception: " + + e.getMessage(); + LOGGER.error(errorMsg); + + responseMap.put( + requestId, + new TSStatus( + RpcUtils.getStatus(TSStatusCode.EXECUTE_STATEMENT_ERROR.getStatusCode(), errorMsg))); + + // Always CountDown + countDownLatch.countDown(); + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/cn/ConfigNodeAsyncRequestRPCHandler.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/cn/ConfigNodeAsyncRequestRPCHandler.java new file mode 100644 index 0000000000000..ece9a2fa5f0ed --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/cn/ConfigNodeAsyncRequestRPCHandler.java @@ -0,0 +1,79 @@ +/* + * 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.iotdb.db.protocol.client.cn; + +import org.apache.iotdb.common.rpc.thrift.TConfigNodeLocation; +import org.apache.iotdb.common.rpc.thrift.TSStatus; +import org.apache.iotdb.commons.client.request.AsyncRequestContext; +import org.apache.iotdb.commons.client.request.AsyncRequestRPCHandler; + +import java.util.Map; +import java.util.concurrent.CountDownLatch; + +public abstract class ConfigNodeAsyncRequestRPCHandler + extends AsyncRequestRPCHandler { + + protected ConfigNodeAsyncRequestRPCHandler( + DnToCnRequestType configNodeRequestType, + int requestId, + TConfigNodeLocation targetNode, + Map integerTConfigNodeLocationMap, + Map integerResponseMap, + CountDownLatch countDownLatch) { + super( + configNodeRequestType, + requestId, + targetNode, + integerTConfigNodeLocationMap, + integerResponseMap, + countDownLatch); + } + + @Override + protected String generateFormattedTargetLocation(TConfigNodeLocation configNodeLocation) { + return "{id=" + + targetNode.getConfigNodeId() + + ", internalEndPoint=" + + targetNode.getInternalEndPoint() + + "}"; + } + + public static ConfigNodeAsyncRequestRPCHandler buildHandler( + AsyncRequestContext context, + int requestId, + TConfigNodeLocation targetConfigNode) { + DnToCnRequestType requestType = context.getRequestType(); + Map nodeLocationMap = context.getNodeLocationMap(); + Map responseMap = context.getResponseMap(); + CountDownLatch countDownLatch = context.getCountDownLatch(); + switch (requestType) { + case SUBMIT_TEST_CONNECTION_TASK: + case TEST_CONNECTION: + default: + return new AsyncConfigNodeTSStatusRPCHandler( + requestType, + requestId, + targetConfigNode, + nodeLocationMap, + (Map) responseMap, + countDownLatch); + } + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/cn/DnToCnInternalServiceAsyncRequestManager.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/cn/DnToCnInternalServiceAsyncRequestManager.java new file mode 100644 index 0000000000000..3f67636724098 --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/cn/DnToCnInternalServiceAsyncRequestManager.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.iotdb.db.protocol.client.cn; + +import org.apache.iotdb.common.rpc.thrift.TConfigNodeLocation; +import org.apache.iotdb.commons.client.request.AsyncRequestContext; +import org.apache.iotdb.commons.client.request.AsyncRequestRPCHandler; +import org.apache.iotdb.commons.client.request.ConfigNodeInternalServiceAsyncRequestManager; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DnToCnInternalServiceAsyncRequestManager + extends ConfigNodeInternalServiceAsyncRequestManager { + + private static final Logger LOGGER = + LoggerFactory.getLogger(DnToCnInternalServiceAsyncRequestManager.class); + + @Override + protected void initActionMapBuilder() { + actionMapBuilder.put( + DnToCnRequestType.TEST_CONNECTION, + (req, client, handler) -> + client.testConnectionEmptyRPC((AsyncConfigNodeTSStatusRPCHandler) handler)); + } + + @Override + protected AsyncRequestRPCHandler buildHandler( + AsyncRequestContext requestContext, + int requestId, + TConfigNodeLocation targetNode) { + return ConfigNodeAsyncRequestRPCHandler.buildHandler(requestContext, requestId, targetNode); + } + + private static class ClientPoolHolder { + private static final DnToCnInternalServiceAsyncRequestManager INSTANCE = + new DnToCnInternalServiceAsyncRequestManager(); + + private ClientPoolHolder() { + // Empty constructor + } + } + + public static DnToCnInternalServiceAsyncRequestManager getInstance() { + return ClientPoolHolder.INSTANCE; + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/cn/DnToCnRequestType.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/cn/DnToCnRequestType.java new file mode 100644 index 0000000000000..5708fec5bed21 --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/cn/DnToCnRequestType.java @@ -0,0 +1,26 @@ +/* + * 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.iotdb.db.protocol.client.cn; + +/** For DataNode async call ConfigNode */ +public enum DnToCnRequestType { + SUBMIT_TEST_CONNECTION_TASK, + TEST_CONNECTION, +} diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/AsyncTSStatusRPCHandler.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/dn/AsyncTSStatusRPCHandler.java similarity index 90% rename from iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/AsyncTSStatusRPCHandler.java rename to iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/dn/AsyncTSStatusRPCHandler.java index 1f61ee141a0b2..9672d431c3840 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/AsyncTSStatusRPCHandler.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/dn/AsyncTSStatusRPCHandler.java @@ -17,11 +17,10 @@ * under the License. */ -package org.apache.iotdb.confignode.client.async.handlers.rpc; +package org.apache.iotdb.db.protocol.client.dn; import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; import org.apache.iotdb.common.rpc.thrift.TSStatus; -import org.apache.iotdb.confignode.client.DataNodeRequestType; import org.apache.iotdb.rpc.RpcUtils; import org.apache.iotdb.rpc.TSStatusCode; @@ -32,12 +31,12 @@ import java.util.concurrent.CountDownLatch; /** General RPC handler for TSStatus response type. */ -public class AsyncTSStatusRPCHandler extends AbstractAsyncRPCHandler { +public class AsyncTSStatusRPCHandler extends DataNodeAsyncRequestRPCHandler { private static final Logger LOGGER = LoggerFactory.getLogger(AsyncTSStatusRPCHandler.class); public AsyncTSStatusRPCHandler( - DataNodeRequestType requestType, + DnToDnRequestType requestType, int requestId, TDataNodeLocation targetDataNode, Map dataNodeLocationMap, @@ -53,7 +52,7 @@ public void onComplete(TSStatus response) { if (response.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { // Remove only if success - dataNodeLocationMap.remove(requestId); + nodeLocationMap.remove(requestId); LOGGER.info("Successfully {} on DataNode: {}", requestType, formattedTargetLocation); } else { LOGGER.error( diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/dn/DataNodeAsyncRequestRPCHandler.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/dn/DataNodeAsyncRequestRPCHandler.java new file mode 100644 index 0000000000000..76be9ac9d715a --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/dn/DataNodeAsyncRequestRPCHandler.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.db.protocol.client.dn; + +import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; +import org.apache.iotdb.common.rpc.thrift.TSStatus; +import org.apache.iotdb.commons.client.request.AsyncRequestContext; +import org.apache.iotdb.commons.client.request.AsyncRequestRPCHandler; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Map; +import java.util.concurrent.CountDownLatch; + +public abstract class DataNodeAsyncRequestRPCHandler + extends AsyncRequestRPCHandler { + private static final Logger LOGGER = + LoggerFactory.getLogger(DataNodeAsyncRequestRPCHandler.class); + + protected DataNodeAsyncRequestRPCHandler( + DnToDnRequestType dataNodeToDataNodeRequestType, + int requestId, + TDataNodeLocation targetNode, + Map dataNodeLocationMap, + Map integerResponseMap, + CountDownLatch countDownLatch) { + super( + dataNodeToDataNodeRequestType, + requestId, + targetNode, + dataNodeLocationMap, + integerResponseMap, + countDownLatch); + } + + @Override + protected String generateFormattedTargetLocation(TDataNodeLocation dataNodeLocation) { + return "{id=" + + targetNode.getDataNodeId() + + ", internalEndPoint=" + + targetNode.getInternalEndPoint() + + "}"; + } + + public static DataNodeAsyncRequestRPCHandler createAsyncRPCHandler( + AsyncRequestContext context, + int requestId, + TDataNodeLocation targetDataNode) { + DnToDnRequestType requestType = context.getRequestType(); + Map nodeLocationMap = context.getNodeLocationMap(); + Map responseMap = context.getResponseMap(); + CountDownLatch countDownLatch = context.getCountDownLatch(); + switch (requestType) { + case TEST_CONNECTION: + return new AsyncTSStatusRPCHandler( + requestType, + requestId, + targetDataNode, + nodeLocationMap, + (Map) responseMap, + countDownLatch); + default: + throw new UnsupportedOperationException("request type is not supported: " + requestType); + } + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/dn/DataNodeExternalServiceAsyncRequestManager.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/dn/DataNodeExternalServiceAsyncRequestManager.java new file mode 100644 index 0000000000000..dd56e1366c03b --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/dn/DataNodeExternalServiceAsyncRequestManager.java @@ -0,0 +1,83 @@ +/* + * 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.iotdb.db.protocol.client.dn; + +import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; +import org.apache.iotdb.common.rpc.thrift.TEndPoint; +import org.apache.iotdb.commons.client.ClientPoolFactory; +import org.apache.iotdb.commons.client.IClientManager; +import org.apache.iotdb.commons.client.async.AsyncDataNodeExternalServiceClient; +import org.apache.iotdb.commons.client.request.AsyncRequestContext; +import org.apache.iotdb.commons.client.request.AsyncRequestManager; +import org.apache.iotdb.commons.client.request.AsyncRequestRPCHandler; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DataNodeExternalServiceAsyncRequestManager + extends AsyncRequestManager< + DnToDnRequestType, TDataNodeLocation, AsyncDataNodeExternalServiceClient> { + + private static final Logger LOGGER = + LoggerFactory.getLogger(DataNodeExternalServiceAsyncRequestManager.class); + + @Override + protected void initClientManager() { + clientManager = + new IClientManager.Factory() + .createClientManager( + new ClientPoolFactory.AsyncDataNodeExternalServiceClientPoolFactory()); + } + + @Override + protected void initActionMapBuilder() { + actionMapBuilder.put( + DnToDnRequestType.TEST_CONNECTION, + (req, client, handler) -> client.testConnectionEmptyRPC((AsyncTSStatusRPCHandler) handler)); + } + + @Override + protected TEndPoint nodeLocationToEndPoint(TDataNodeLocation dataNodeLocation) { + return dataNodeLocation.getClientRpcEndPoint(); + } + + @Override + protected AsyncRequestRPCHandler buildHandler( + AsyncRequestContext requestContext, + int requestId, + TDataNodeLocation targetNode) { + return DataNodeAsyncRequestRPCHandler.createAsyncRPCHandler( + requestContext, requestId, targetNode); + } + + private static class ClientPoolHolder { + + private static final DataNodeExternalServiceAsyncRequestManager INSTANCE = + new DataNodeExternalServiceAsyncRequestManager(); + + private ClientPoolHolder() { + // Empty constructor + } + } + + public static DataNodeExternalServiceAsyncRequestManager getInstance() { + return DataNodeExternalServiceAsyncRequestManager.ClientPoolHolder.INSTANCE; + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/dn/DataNodeMPPServiceAsyncRequestManager.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/dn/DataNodeMPPServiceAsyncRequestManager.java new file mode 100644 index 0000000000000..ab08d83f2645b --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/dn/DataNodeMPPServiceAsyncRequestManager.java @@ -0,0 +1,84 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.db.protocol.client.dn; + +import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; +import org.apache.iotdb.common.rpc.thrift.TEndPoint; +import org.apache.iotdb.commons.client.ClientPoolFactory; +import org.apache.iotdb.commons.client.IClientManager; +import org.apache.iotdb.commons.client.async.AsyncDataNodeMPPDataExchangeServiceClient; +import org.apache.iotdb.commons.client.request.AsyncRequestContext; +import org.apache.iotdb.commons.client.request.AsyncRequestManager; +import org.apache.iotdb.commons.client.request.AsyncRequestRPCHandler; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DataNodeMPPServiceAsyncRequestManager + extends AsyncRequestManager< + DnToDnRequestType, TDataNodeLocation, AsyncDataNodeMPPDataExchangeServiceClient> { + private static final Logger LOGGER = + LoggerFactory.getLogger(DataNodeMPPServiceAsyncRequestManager.class); + + public DataNodeMPPServiceAsyncRequestManager() {} + + @Override + protected void initClientManager() { + clientManager = + new IClientManager.Factory() + .createClientManager( + new ClientPoolFactory.AsyncDataNodeMPPDataExchangeServiceClientPoolFactory()); + } + + @Override + protected void initActionMapBuilder() { + actionMapBuilder.put( + DnToDnRequestType.TEST_CONNECTION, + (req, client, handler) -> client.testConnectionEmptyRPC((AsyncTSStatusRPCHandler) handler)); + } + + @Override + protected TEndPoint nodeLocationToEndPoint(TDataNodeLocation dataNodeLocation) { + return dataNodeLocation.getMPPDataExchangeEndPoint(); + } + + @Override + protected AsyncRequestRPCHandler buildHandler( + AsyncRequestContext requestContext, + int requestId, + TDataNodeLocation targetNode) { + return DataNodeAsyncRequestRPCHandler.createAsyncRPCHandler( + requestContext, requestId, targetNode); + } + + private static class ClientPoolHolder { + + private static final DataNodeMPPServiceAsyncRequestManager INSTANCE = + new DataNodeMPPServiceAsyncRequestManager(); + + private ClientPoolHolder() { + // Empty constructor + } + } + + public static DataNodeMPPServiceAsyncRequestManager getInstance() { + return ClientPoolHolder.INSTANCE; + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/dn/DnToDnInternalServiceAsyncRequestManager.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/dn/DnToDnInternalServiceAsyncRequestManager.java new file mode 100644 index 0000000000000..88766458b649d --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/dn/DnToDnInternalServiceAsyncRequestManager.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.iotdb.db.protocol.client.dn; + +import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; +import org.apache.iotdb.commons.client.request.AsyncRequestContext; +import org.apache.iotdb.commons.client.request.AsyncRequestRPCHandler; +import org.apache.iotdb.commons.client.request.DataNodeInternalServiceRequestManager; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class DnToDnInternalServiceAsyncRequestManager + extends DataNodeInternalServiceRequestManager { + private static final Logger LOGGER = + LoggerFactory.getLogger(DnToDnInternalServiceAsyncRequestManager.class); + + @Override + protected void initActionMapBuilder() { + actionMapBuilder.put( + DnToDnRequestType.TEST_CONNECTION, + (req, client, handler) -> client.testConnectionEmptyRPC((AsyncTSStatusRPCHandler) handler)); + } + + @Override + protected AsyncRequestRPCHandler buildHandler( + AsyncRequestContext requestContext, + int requestId, + TDataNodeLocation targetNode) { + return DataNodeAsyncRequestRPCHandler.createAsyncRPCHandler( + requestContext, requestId, targetNode); + } + + private static class ClientPoolHolder { + + private static final DnToDnInternalServiceAsyncRequestManager INSTANCE = + new DnToDnInternalServiceAsyncRequestManager(); + + private ClientPoolHolder() { + // Empty constructor + } + } + + public static DnToDnInternalServiceAsyncRequestManager getInstance() { + return ClientPoolHolder.INSTANCE; + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/dn/DnToDnRequestType.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/dn/DnToDnRequestType.java new file mode 100644 index 0000000000000..35f5b8d93a9b4 --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/client/dn/DnToDnRequestType.java @@ -0,0 +1,25 @@ +/* + * 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.iotdb.db.protocol.client.dn; + +/** For DataNode async call DataNode */ +public enum DnToDnRequestType { + TEST_CONNECTION, +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java index 136ba340e44d6..fd4d23ba53560 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/ClientRPCServiceImpl.java @@ -49,7 +49,7 @@ import org.apache.iotdb.db.auth.AuthorityChecker; import org.apache.iotdb.db.conf.IoTDBConfig; import org.apache.iotdb.db.conf.IoTDBDescriptor; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.protocol.basic.BasicOpenSessionResp; import org.apache.iotdb.db.protocol.client.ConfigNodeClient; import org.apache.iotdb.db.protocol.client.ConfigNodeClientManager; @@ -362,6 +362,7 @@ private TSExecuteStatementResp executeStatementInternal( if (result.status.code != TSStatusCode.SUCCESS_STATUS.getStatusCode() && result.status.code != TSStatusCode.REDIRECTION_RECOMMEND.getStatusCode()) { + finished = true; return RpcUtils.getTSExecuteStatementResp(result.status); } @@ -389,6 +390,7 @@ private TSExecuteStatementResp executeStatementInternal( return RpcUtils.getTSExecuteStatementResp( onQueryException(e, "\"" + statement + "\". " + OperationType.EXECUTE_STATEMENT)); } catch (Error error) { + finished = true; t = error; throw error; } finally { @@ -454,6 +456,7 @@ private TSExecuteStatementResp executeRawDataQueryInternal( req.getTimeout()); if (result.status.code != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { + finished = true; throw new RuntimeException(ERROR_CODE + result.status); } @@ -478,6 +481,7 @@ private TSExecuteStatementResp executeRawDataQueryInternal( return RpcUtils.getTSExecuteStatementResp( onQueryException(e, "\"" + req + "\". " + OperationType.EXECUTE_RAW_DATA_QUERY)); } catch (Error error) { + finished = true; t = error; throw error; } finally { @@ -542,6 +546,7 @@ private TSExecuteStatementResp executeLastDataQueryInternal( req.getTimeout()); if (result.status.code != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { + finished = true; throw new RuntimeException(ERROR_CODE + result.status); } @@ -567,6 +572,7 @@ private TSExecuteStatementResp executeLastDataQueryInternal( return RpcUtils.getTSExecuteStatementResp( onQueryException(e, "\"" + req + "\". " + OperationType.EXECUTE_LAST_DATA_QUERY)); } catch (Error error) { + finished = true; t = error; throw error; } finally { @@ -629,6 +635,7 @@ private TSExecuteStatementResp executeAggregationQueryInternal( req.getTimeout()); if (result.status.code != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { + finished = true; throw new RuntimeException(ERROR_CODE + result.status); } @@ -654,6 +661,7 @@ private TSExecuteStatementResp executeAggregationQueryInternal( return RpcUtils.getTSExecuteStatementResp( onQueryException(e, "\"" + req + "\". " + OperationType.EXECUTE_LAST_DATA_QUERY)); } catch (Error error) { + finished = true; t = error; throw error; } finally { @@ -964,6 +972,7 @@ public TSExecuteStatementResp executeFastLastDataQueryForOneDeviceV2( req.getTimeout()); if (result.status.code != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { + finished = true; throw new RuntimeException("error code: " + result.status); } @@ -996,6 +1005,7 @@ public TSExecuteStatementResp executeFastLastDataQueryForOneDeviceV2( return RpcUtils.getTSExecuteStatementResp( onQueryException(e, "\"" + req + "\". " + OperationType.EXECUTE_LAST_DATA_QUERY)); } catch (Error error) { + finished = true; t = error; throw error; } finally { @@ -1116,6 +1126,7 @@ public TSFetchResultsResp fetchResultsV2(TSFetchResultsReq req) { try { IClientSession clientSession = SESSION_MANAGER.getCurrSessionAndUpdateIdleTime(); if (!SESSION_MANAGER.checkLogin(clientSession)) { + finished = true; return RpcUtils.getTSFetchResultsResp(getNotLoggedInStatus()); } TSFetchResultsResp resp = RpcUtils.getTSFetchResultsResp(TSStatusCode.SUCCESS_STATUS); @@ -1663,6 +1674,7 @@ public TSFetchResultsResp fetchResults(TSFetchResultsReq req) { try { IClientSession clientSession = SESSION_MANAGER.getCurrSessionAndUpdateIdleTime(); if (!SESSION_MANAGER.checkLogin(clientSession)) { + finished = true; return RpcUtils.getTSFetchResultsResp(getNotLoggedInStatus()); } @@ -1694,6 +1706,7 @@ public TSFetchResultsResp fetchResults(TSFetchResultsReq req) { return RpcUtils.getTSFetchResultsResp( onQueryException(e, getContentOfRequest(req, queryExecution))); } catch (Error error) { + finished = true; t = error; throw error; } finally { @@ -2698,7 +2711,7 @@ public TSStatus createTimeseriesUsingSchemaTemplate(TCreateTimeseriesUsingSchema @Override public TSStatus handshake(final TSyncIdentityInfo info) throws TException { - return PipeAgent.receiver() + return PipeDataNodeAgent.receiver() .legacy() .handshake( info, @@ -2709,18 +2722,18 @@ public TSStatus handshake(final TSyncIdentityInfo info) throws TException { @Override public TSStatus sendPipeData(final ByteBuffer buff) throws TException { - return PipeAgent.receiver().legacy().transportPipeData(buff); + return PipeDataNodeAgent.receiver().legacy().transportPipeData(buff); } @Override public TSStatus sendFile(final TSyncTransportMetaInfo metaInfo, final ByteBuffer buff) throws TException { - return PipeAgent.receiver().legacy().transportFile(metaInfo, buff); + return PipeDataNodeAgent.receiver().legacy().transportFile(metaInfo, buff); } @Override public TPipeTransferResp pipeTransfer(final TPipeTransferReq req) { - return PipeAgent.receiver().thrift().receive(req); + return PipeDataNodeAgent.receiver().thrift().receive(req); } @Override @@ -2738,6 +2751,11 @@ public TSConnectionInfoResp fetchAllConnectionsInfo() { return SESSION_MANAGER.getAllConnectionInfo(); } + @Override + public TSStatus testConnectionEmptyRPC() throws TException { + return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()); + } + @Override public TSStatus insertStringRecord(final TSInsertStringRecordReq req) { final long t1 = System.nanoTime(); @@ -2865,8 +2883,8 @@ public void handleClientExit() { TSCloseSessionReq req = new TSCloseSessionReq(); closeSession(req); } - PipeAgent.receiver().thrift().handleClientExit(); - PipeAgent.receiver().legacy().handleClientExit(); + PipeDataNodeAgent.receiver().thrift().handleClientExit(); + PipeDataNodeAgent.receiver().legacy().handleClientExit(); SubscriptionAgent.receiver().handleClientExit(); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/DataNodeInternalRPCServiceImpl.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/DataNodeInternalRPCServiceImpl.java index 3fd8a43e064cc..1fa74be7a23f1 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/DataNodeInternalRPCServiceImpl.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/DataNodeInternalRPCServiceImpl.java @@ -19,17 +19,24 @@ package org.apache.iotdb.db.protocol.thrift.impl; +import org.apache.iotdb.common.rpc.thrift.TConfigNodeLocation; import org.apache.iotdb.common.rpc.thrift.TConsensusGroupId; import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; import org.apache.iotdb.common.rpc.thrift.TEndPoint; import org.apache.iotdb.common.rpc.thrift.TFlushReq; +import org.apache.iotdb.common.rpc.thrift.TNodeLocations; import org.apache.iotdb.common.rpc.thrift.TSStatus; +import org.apache.iotdb.common.rpc.thrift.TSender; +import org.apache.iotdb.common.rpc.thrift.TServiceType; import org.apache.iotdb.common.rpc.thrift.TSetConfigurationReq; import org.apache.iotdb.common.rpc.thrift.TSetSpaceQuotaReq; import org.apache.iotdb.common.rpc.thrift.TSetTTLReq; import org.apache.iotdb.common.rpc.thrift.TSetThrottleQuotaReq; import org.apache.iotdb.common.rpc.thrift.TSettleReq; import org.apache.iotdb.common.rpc.thrift.TShowConfigurationResp; +import org.apache.iotdb.common.rpc.thrift.TTestConnectionResp; +import org.apache.iotdb.common.rpc.thrift.TTestConnectionResult; +import org.apache.iotdb.commons.client.request.AsyncRequestContext; import org.apache.iotdb.commons.cluster.NodeStatus; import org.apache.iotdb.commons.conf.CommonConfig; import org.apache.iotdb.commons.conf.CommonDescriptor; @@ -71,8 +78,14 @@ import org.apache.iotdb.db.consensus.DataRegionConsensusImpl; import org.apache.iotdb.db.consensus.SchemaRegionConsensusImpl; import org.apache.iotdb.db.exception.StorageEngineException; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.protocol.client.ConfigNodeInfo; +import org.apache.iotdb.db.protocol.client.cn.DnToCnInternalServiceAsyncRequestManager; +import org.apache.iotdb.db.protocol.client.cn.DnToCnRequestType; +import org.apache.iotdb.db.protocol.client.dn.DataNodeExternalServiceAsyncRequestManager; +import org.apache.iotdb.db.protocol.client.dn.DataNodeMPPServiceAsyncRequestManager; +import org.apache.iotdb.db.protocol.client.dn.DnToDnInternalServiceAsyncRequestManager; +import org.apache.iotdb.db.protocol.client.dn.DnToDnRequestType; import org.apache.iotdb.db.protocol.session.IClientSession; import org.apache.iotdb.db.protocol.session.InternalClientSession; import org.apache.iotdb.db.protocol.session.SessionManager; @@ -259,6 +272,7 @@ import java.time.ZoneId; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -269,9 +283,12 @@ import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.atomic.AtomicLong; import java.util.concurrent.locks.ReadWriteLock; +import java.util.function.Consumer; import java.util.function.Function; import java.util.stream.Collectors; +import java.util.stream.Stream; +import static org.apache.iotdb.commons.client.request.Utils.testConnectionsImpl; import static org.apache.iotdb.commons.conf.IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD; import static org.apache.iotdb.db.service.RegionMigrateService.REGION_MIGRATE_PROCESS; import static org.apache.iotdb.db.utils.ErrorHandlingUtils.onQueryException; @@ -450,7 +467,7 @@ public TLoadResp sendLoadCommand(TLoadCommandReq req) { progressIndex = ProgressIndexType.deserializeFrom(ByteBuffer.wrap(req.getProgressIndex())); } else { // fallback to use local generated progress index for compatibility - progressIndex = PipeAgent.runtime().getNextProgressIndexForTsFileLoad(); + progressIndex = PipeDataNodeAgent.runtime().getNextProgressIndexForTsFileLoad(); LOGGER.info( "Use local generated load progress index {} for uuid {}.", progressIndex, req.uuid); } @@ -1040,7 +1057,7 @@ public TPushPipeMetaResp pushPipeMeta(TPushPipeMetaReq req) { } try { List exceptionMessages = - PipeAgent.task().handlePipeMetaChanges(pipeMetas); + PipeDataNodeAgent.task().handlePipeMetaChanges(pipeMetas); return exceptionMessages.isEmpty() ? new TPushPipeMetaResp() @@ -1060,10 +1077,10 @@ public TPushPipeMetaResp pushSinglePipeMeta(TPushSinglePipeMetaReq req) { try { TPushPipeMetaRespExceptionMessage exceptionMessage; if (req.isSetPipeNameToDrop()) { - exceptionMessage = PipeAgent.task().handleDropPipe(req.getPipeNameToDrop()); + exceptionMessage = PipeDataNodeAgent.task().handleDropPipe(req.getPipeNameToDrop()); } else if (req.isSetPipeMeta()) { final PipeMeta pipeMeta = PipeMeta.deserialize(ByteBuffer.wrap(req.getPipeMeta())); - exceptionMessage = PipeAgent.task().handleSinglePipeMetaChanges(pipeMeta); + exceptionMessage = PipeDataNodeAgent.task().handleSinglePipeMetaChanges(pipeMeta); } else { throw new Exception("Invalid TPushSinglePipeMetaReq"); } @@ -1089,7 +1106,7 @@ public TPushPipeMetaResp pushMultiPipeMeta(TPushMultiPipeMetaReq req) { if (req.isSetPipeNamesToDrop()) { for (String pipeNameToDrop : req.getPipeNamesToDrop()) { TPushPipeMetaRespExceptionMessage message = - PipeAgent.task().handleDropPipe(pipeNameToDrop); + PipeDataNodeAgent.task().handleDropPipe(pipeNameToDrop); exceptionMessages.add(message); if (message != null) { // If there is any exception, skip the remaining pipes @@ -1101,7 +1118,7 @@ public TPushPipeMetaResp pushMultiPipeMeta(TPushMultiPipeMetaReq req) { for (ByteBuffer byteBuffer : req.getPipeMetas()) { final PipeMeta pipeMeta = PipeMeta.deserialize(byteBuffer); TPushPipeMetaRespExceptionMessage message = - PipeAgent.task().handleSinglePipeMetaChanges(pipeMeta); + PipeDataNodeAgent.task().handleSinglePipeMetaChanges(pipeMeta); exceptionMessages.add(message); if (message != null) { // If there is any exception, skip the remaining pipes @@ -1281,7 +1298,7 @@ public TPushConsumerGroupMetaResp pushSingleConsumerGroupMeta( @Override public TPipeHeartbeatResp pipeHeartbeat(TPipeHeartbeatReq req) throws TException { final TPipeHeartbeatResp resp = new TPipeHeartbeatResp(); - PipeAgent.task().collectPipeMetaList(req, resp); + PipeDataNodeAgent.task().collectPipeMetaList(req, resp); return resp; } @@ -1472,6 +1489,90 @@ public TSStatus updateTable(TUpdateTableReq req) throws TException { return RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS); } + public TTestConnectionResp submitTestConnectionTask(TNodeLocations nodeLocations) + throws TException { + return new TTestConnectionResp( + new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()), + Stream.of( + testAllConfigNodeConnection(nodeLocations.getConfigNodeLocations()), + testAllDataNodeInternalServiceConnection(nodeLocations.getDataNodeLocations()), + testAllDataNodeMPPServiceConnection(nodeLocations.getDataNodeLocations()), + testAllDataNodeExternalServiceConnection(nodeLocations.getDataNodeLocations())) + .flatMap(Collection::stream) + .collect(Collectors.toList())); + } + + private static List testConnections( + List nodeLocations, + Function getId, + Function getEndPoint, + TServiceType serviceType, + RequestType requestType, + Consumer> sendRequest) { + TSender sender = + new TSender() + .setDataNodeLocation( + IoTDBDescriptor.getInstance().getConfig().generateLocalDataNodeLocation()); + return testConnectionsImpl( + nodeLocations, sender, getId, getEndPoint, serviceType, requestType, sendRequest); + } + + private List testAllConfigNodeConnection( + List configNodeLocations) { + return testConnections( + configNodeLocations, + TConfigNodeLocation::getConfigNodeId, + TConfigNodeLocation::getInternalEndPoint, + TServiceType.ConfigNodeInternalService, + DnToCnRequestType.TEST_CONNECTION, + (AsyncRequestContext handler) -> + DnToCnInternalServiceAsyncRequestManager.getInstance() + .sendAsyncRequestWithRetry(handler)); + } + + private List testAllDataNodeInternalServiceConnection( + List dataNodeLocations) { + return testConnections( + dataNodeLocations, + TDataNodeLocation::getDataNodeId, + TDataNodeLocation::getInternalEndPoint, + TServiceType.DataNodeInternalService, + DnToDnRequestType.TEST_CONNECTION, + (AsyncRequestContext handler) -> + DnToDnInternalServiceAsyncRequestManager.getInstance() + .sendAsyncRequestWithRetry(handler)); + } + + private List testAllDataNodeMPPServiceConnection( + List dataNodeLocations) { + return testConnections( + dataNodeLocations, + TDataNodeLocation::getDataNodeId, + TDataNodeLocation::getMPPDataExchangeEndPoint, + TServiceType.DataNodeMPPService, + DnToDnRequestType.TEST_CONNECTION, + (AsyncRequestContext handler) -> + DataNodeMPPServiceAsyncRequestManager.getInstance().sendAsyncRequestWithRetry(handler)); + } + + private List testAllDataNodeExternalServiceConnection( + List dataNodeLocations) { + return testConnections( + dataNodeLocations, + TDataNodeLocation::getDataNodeId, + TDataNodeLocation::getClientRpcEndPoint, + TServiceType.DataNodeExternalService, + DnToDnRequestType.TEST_CONNECTION, + (AsyncRequestContext handler) -> + DataNodeExternalServiceAsyncRequestManager.getInstance() + .sendAsyncRequestWithRetry(handler)); + } + + @Override + public TSStatus testConnectionEmptyRPC() throws TException { + return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()); + } + private PathPatternTree filterPathPatternTree(PathPatternTree patternTree, String storageGroup) { PathPatternTree filteredPatternTree = new PathPatternTree(); try { @@ -1550,7 +1651,7 @@ public TDataNodeHeartbeatResp getDataNodeHeartBeat(TDataNodeHeartbeatReq req) th // Update pipe meta if necessary if (req.isNeedPipeMetaList()) { - PipeAgent.task().collectPipeMetaList(resp); + PipeDataNodeAgent.task().collectPipeMetaList(resp); } if (req.isSetConfigNodeEndPoints()) { @@ -1812,7 +1913,7 @@ public TSStatus setSystemStatus(String status) throws TException { try { commonConfig.setNodeStatus(NodeStatus.parse(status)); if (commonConfig.getNodeStatus().equals(NodeStatus.Removing)) { - PipeAgent.runtime().stop(); + PipeDataNodeAgent.runtime().stop(); } } catch (Exception e) { return RpcUtils.getStatus(TSStatusCode.EXECUTE_STATEMENT_ERROR, e.getMessage()); @@ -2209,7 +2310,7 @@ private TEndPoint getConsensusEndPoint( public TSStatus createPipePlugin(TCreatePipePluginInstanceReq req) { try { PipePluginMeta pipePluginMeta = PipePluginMeta.deserialize(req.pipePluginMeta); - PipeAgent.plugin().register(pipePluginMeta, req.jarFile); + PipeDataNodeAgent.plugin().register(pipePluginMeta, req.jarFile); return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()); } catch (Exception e) { return new TSStatus(TSStatusCode.CREATE_PIPE_PLUGIN_ON_DATANODE_ERROR.getStatusCode()) @@ -2220,7 +2321,7 @@ public TSStatus createPipePlugin(TCreatePipePluginInstanceReq req) { @Override public TSStatus dropPipePlugin(TDropPipePluginInstanceReq req) { try { - PipeAgent.plugin().deregister(req.getPipePluginName(), req.isNeedToDeleteJar()); + PipeDataNodeAgent.plugin().deregister(req.getPipePluginName(), req.isNeedToDeleteJar()); return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()); } catch (Exception e) { return new TSStatus(TSStatusCode.DROP_PIPE_PLUGIN_ON_DATANODE_ERROR.getStatusCode()) diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/DataNodeRegionManager.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/DataNodeRegionManager.java index 22f624eb7df4b..18ddd6db478a4 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/DataNodeRegionManager.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/protocol/thrift/impl/DataNodeRegionManager.java @@ -36,7 +36,7 @@ import org.apache.iotdb.db.consensus.DataRegionConsensusImpl; import org.apache.iotdb.db.consensus.SchemaRegionConsensusImpl; import org.apache.iotdb.db.exception.DataRegionException; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.schemaengine.SchemaEngine; import org.apache.iotdb.db.storageengine.StorageEngine; import org.apache.iotdb.rpc.RpcUtils; @@ -203,7 +203,7 @@ public TSStatus deleteDataRegion(DataRegionId dataRegionId) { public TSStatus deleteSchemaRegion(SchemaRegionId schemaRegionId) { try { schemaEngine.deleteSchemaRegion(schemaRegionId); - PipeAgent.runtime().schemaListener(schemaRegionId).close(); + PipeDataNodeAgent.runtime().schemaListener(schemaRegionId).close(); schemaRegionLockMap.remove(schemaRegionId); return RpcUtils.getStatus(TSStatusCode.SUCCESS_STATUS, "Execute successfully"); } catch (MetadataException e) { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/DeviceContext.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/DeviceContext.java new file mode 100644 index 0000000000000..3c6663c680b11 --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/DeviceContext.java @@ -0,0 +1,81 @@ +/* + * 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.iotdb.db.queryengine.common; + +import org.apache.iotdb.db.queryengine.common.schematree.DeviceSchemaInfo; + +import org.apache.tsfile.utils.ReadWriteIOUtils; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.Objects; + +public class DeviceContext { + private boolean isAligned; + private final int templateId; + + public DeviceContext(DeviceSchemaInfo deviceSchemaInfo) { + this.isAligned = deviceSchemaInfo.isAligned(); + this.templateId = deviceSchemaInfo.getTemplateId(); + } + + public DeviceContext(boolean isAligned, int templateId) { + this.isAligned = isAligned; + this.templateId = templateId; + } + + public boolean isAligned() { + return isAligned; + } + + public int getTemplateId() { + return templateId; + } + + public void serializeAttributes(ByteBuffer byteBuffer) { + ReadWriteIOUtils.write(isAligned, byteBuffer); + ReadWriteIOUtils.write(templateId, byteBuffer); + } + + public void serializeAttributes(DataOutputStream stream) throws IOException { + ReadWriteIOUtils.write(isAligned, stream); + ReadWriteIOUtils.write(templateId, stream); + } + + public static DeviceContext deserialize(ByteBuffer buffer) { + boolean isAligned = ReadWriteIOUtils.readBool(buffer); + int templateId = ReadWriteIOUtils.readInt(buffer); + return new DeviceContext(isAligned, templateId); + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + DeviceContext that = (DeviceContext) o; + return isAligned == that.isAligned && templateId == that.templateId; + } + + @Override + public int hashCode() { + return Objects.hash(isAligned, templateId); + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/TimeseriesSchemaInfo.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/TimeseriesContext.java similarity index 76% rename from iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/TimeseriesSchemaInfo.java rename to iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/TimeseriesContext.java index 946a3cfa90482..9225b97fc70ae 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/TimeseriesSchemaInfo.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/TimeseriesContext.java @@ -32,25 +32,24 @@ import static org.apache.iotdb.db.queryengine.execution.operator.schema.source.TimeSeriesSchemaSource.mapToString; -public class TimeseriesSchemaInfo { +public class TimeseriesContext { private final String dataType; private final String encoding; private final String compression; private final String tags; private final String alias; - - // TODO: Currently we can't get attributes from fetchSchema in query - // private final String attributes; + private final String attributes; private final String deadband; private final String deadbandParameters; - public TimeseriesSchemaInfo(IMeasurementSchemaInfo schemaInfo) { + public TimeseriesContext(IMeasurementSchemaInfo schemaInfo) { this.dataType = schemaInfo.getSchema().getType().toString(); this.encoding = schemaInfo.getSchema().getEncodingType().toString(); this.compression = schemaInfo.getSchema().getCompressor().toString(); this.alias = schemaInfo.getAlias(); this.tags = mapToString(schemaInfo.getTagMap()); + this.attributes = mapToString(schemaInfo.getAttributeMap()); Pair deadbandInfo = MetaUtils.parseDeadbandInfo(schemaInfo.getSchema().getProps()); this.deadband = deadbandInfo.left; @@ -77,6 +76,10 @@ public String getTags() { return tags; } + public String getAttributes() { + return attributes; + } + public String getDeadbandParameters() { return deadbandParameters; } @@ -85,12 +88,13 @@ public String getDeadband() { return deadband; } - public TimeseriesSchemaInfo( + public TimeseriesContext( String dataType, String alias, String encoding, String compression, String tags, + String attributes, String deadband, String deadbandParameters) { this.dataType = dataType; @@ -98,6 +102,7 @@ public TimeseriesSchemaInfo( this.encoding = encoding; this.compression = compression; this.tags = tags; + this.attributes = attributes; this.deadband = deadband; this.deadbandParameters = deadbandParameters; } @@ -108,6 +113,7 @@ public void serializeAttributes(ByteBuffer byteBuffer) { ReadWriteIOUtils.write(encoding, byteBuffer); ReadWriteIOUtils.write(compression, byteBuffer); ReadWriteIOUtils.write(tags, byteBuffer); + ReadWriteIOUtils.write(attributes, byteBuffer); ReadWriteIOUtils.write(deadband, byteBuffer); ReadWriteIOUtils.write(deadbandParameters, byteBuffer); } @@ -118,20 +124,22 @@ public void serializeAttributes(DataOutputStream stream) throws IOException { ReadWriteIOUtils.write(encoding, stream); ReadWriteIOUtils.write(compression, stream); ReadWriteIOUtils.write(tags, stream); + ReadWriteIOUtils.write(attributes, stream); ReadWriteIOUtils.write(deadband, stream); ReadWriteIOUtils.write(deadbandParameters, stream); } - public static TimeseriesSchemaInfo deserialize(ByteBuffer buffer) { + public static TimeseriesContext deserialize(ByteBuffer buffer) { String dataType = ReadWriteIOUtils.readString(buffer); String alias = ReadWriteIOUtils.readString(buffer); String encoding = ReadWriteIOUtils.readString(buffer); String compression = ReadWriteIOUtils.readString(buffer); String tags = ReadWriteIOUtils.readString(buffer); + String attributes = ReadWriteIOUtils.readString(buffer); String deadband = ReadWriteIOUtils.readString(buffer); String deadbandParameters = ReadWriteIOUtils.readString(buffer); - return new TimeseriesSchemaInfo( - dataType, alias, encoding, compression, tags, deadband, deadbandParameters); + return new TimeseriesContext( + dataType, alias, encoding, compression, tags, attributes, deadband, deadbandParameters); } @Override @@ -142,18 +150,22 @@ public boolean equals(Object obj) { if (obj == null || getClass() != obj.getClass()) { return false; } - TimeseriesSchemaInfo that = (TimeseriesSchemaInfo) obj; - return Objects.equals(dataType, that.dataType) - && Objects.equals(alias, that.alias) - && encoding.equals(that.encoding) - && Objects.equals(compression, that.compression) - && Objects.equals(tags, that.tags) - && Objects.equals(deadband, that.deadband) - && Objects.equals(deadbandParameters, that.deadbandParameters); + TimeseriesContext that = (TimeseriesContext) obj; + boolean res = + Objects.equals(dataType, that.dataType) + && Objects.equals(alias, that.alias) + && encoding.equals(that.encoding) + && Objects.equals(compression, that.compression) + && Objects.equals(tags, that.tags) + && Objects.equals(attributes, that.attributes) + && Objects.equals(deadband, that.deadband) + && Objects.equals(deadbandParameters, that.deadbandParameters); + return res; } @Override public int hashCode() { - return Objects.hash(dataType, alias, encoding, compression, tags, deadband, deadbandParameters); + return Objects.hash( + dataType, alias, encoding, compression, tags, attributes, deadband, deadbandParameters); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/header/ColumnHeaderConstant.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/header/ColumnHeaderConstant.java index 898cfe2903588..0301484e4bdb0 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/header/ColumnHeaderConstant.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/header/ColumnHeaderConstant.java @@ -94,6 +94,11 @@ private ColumnHeaderConstant() { // column names for show clusterId statement public static final String CLUSTER_ID = "ClusterId"; + // column names for verify connection statement + public static final String SERVICE_PROVIDER = "ServiceProvider"; + public static final String SENDER = "Sender"; + public static final String CONNECTION = "Connection"; + // column names for show functions statement public static final String FUNCTION_NAME = "FunctionName"; public static final String FUNCTION_TYPE = "FunctionType"; @@ -375,6 +380,12 @@ private ColumnHeaderConstant() { public static final List showClusterIdColumnHeaders = ImmutableList.of(new ColumnHeader(CLUSTER_ID, TSDataType.TEXT)); + public static final List testConnectionColumnHeaders = + ImmutableList.of( + new ColumnHeader(SERVICE_PROVIDER, TSDataType.TEXT), + new ColumnHeader(SENDER, TSDataType.TEXT), + new ColumnHeader(CONNECTION, TSDataType.TEXT)); + public static final List showVariablesColumnHeaders = ImmutableList.of( new ColumnHeader(VARIABLE, TSDataType.TEXT), new ColumnHeader(VALUE, TSDataType.TEXT)); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/header/DatasetHeaderFactory.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/header/DatasetHeaderFactory.java index 16bb695ecb75f..e34cc505bad5f 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/header/DatasetHeaderFactory.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/header/DatasetHeaderFactory.java @@ -99,6 +99,10 @@ public static DatasetHeader getShowClusterIdHeader() { return new DatasetHeader(ColumnHeaderConstant.showClusterIdColumnHeaders, true); } + public static DatasetHeader getTestConnectionHeader() { + return new DatasetHeader(ColumnHeaderConstant.testConnectionColumnHeaders, true); + } + public static DatasetHeader getShowFunctionsHeader() { return new DatasetHeader(ColumnHeaderConstant.showFunctionsColumnHeaders, true); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/schematree/ClusterSchemaTree.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/schematree/ClusterSchemaTree.java index d3cfe4d57c051..bfc6cdbba5c11 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/schematree/ClusterSchemaTree.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/schematree/ClusterSchemaTree.java @@ -148,7 +148,8 @@ private IMeasurementSchemaInfo getMeasurementSchemaInfo( } else { Template template = templateMap.get(entityNode.getTemplateId()); if (template != null && template.getSchemaMap().containsKey(measurement)) { - return new MeasurementSchemaInfo(measurement, template.getSchema(measurement), null, null); + return new MeasurementSchemaInfo( + measurement, template.getSchema(measurement), null, null, null); } } return null; @@ -260,7 +261,8 @@ public void computeSourceOfLogicalView( measurementPath.getMeasurement(), measurementPath.getMeasurementSchema(), null, - measurementPath.getTagMap()), + measurementPath.getTagMap(), + null), measurementPath.isUnderAlignedEntity()); } } @@ -304,7 +306,9 @@ public void appendTemplateDevice( entityNode.setTemplateId(templateId); cur.replaceChild(deviceName, entityNode); } - templateMap.putIfAbsent(templateId, template); + if (template != null) { + templateMap.putIfAbsent(templateId, template); + } } public void appendMeasurementPaths(List measurementPathList) { @@ -318,6 +322,7 @@ public void appendSingleMeasurementPath(MeasurementPath measurementPath) { measurementPath, measurementPath.getMeasurementSchema(), measurementPath.getTagMap(), + null, measurementPath.isMeasurementAliasExists() ? measurementPath.getMeasurementAlias() : null, measurementPath.isUnderAlignedEntity()); } @@ -326,6 +331,7 @@ public void appendSingleMeasurement( PartialPath path, IMeasurementSchema schema, Map tagMap, + Map attributeMap, String alias, boolean isAligned) { String[] nodes = path.getNodes(); @@ -341,6 +347,7 @@ public void appendSingleMeasurement( cur.getAsEntityNode().addAliasChild(alias, measurementNode); } measurementNode.setTagMap(tagMap); + measurementNode.setAttributeMap(attributeMap); child = measurementNode; if (schema.isLogicalView()) { this.hasLogicalMeasurementPath = true; diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/schematree/IMeasurementSchemaInfo.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/schematree/IMeasurementSchemaInfo.java index 7200c9a5e5f21..5636363f800f4 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/schematree/IMeasurementSchemaInfo.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/schematree/IMeasurementSchemaInfo.java @@ -43,6 +43,8 @@ public interface IMeasurementSchemaInfo { Map getTagMap(); + Map getAttributeMap(); + String getAlias(); boolean isLogicalView(); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/schematree/MeasurementSchemaInfo.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/schematree/MeasurementSchemaInfo.java index a8225dbcb0ad7..9db3ebadbfded 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/schematree/MeasurementSchemaInfo.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/schematree/MeasurementSchemaInfo.java @@ -37,14 +37,20 @@ public class MeasurementSchemaInfo implements IMeasurementSchemaInfo { private final String name; private final String alias; private Map tagMap; + private Map attributeMap; private final IMeasurementSchema schema; public MeasurementSchemaInfo( - String name, IMeasurementSchema schema, String alias, Map tagMap) { + String name, + IMeasurementSchema schema, + String alias, + Map tagMap, + Map attributeMap) { this.name = name; this.schema = schema; this.alias = alias; this.tagMap = tagMap; + this.attributeMap = attributeMap; } public String getName() { @@ -68,6 +74,11 @@ public Map getTagMap() { return tagMap; } + @Override + public Map getAttributeMap() { + return attributeMap; + } + @Override public LogicalViewSchema getSchemaAsLogicalViewSchema() { if (this.isLogicalView()) { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/schematree/node/SchemaMeasurementNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/schematree/node/SchemaMeasurementNode.java index 55657a59700be..b1eaa7ff5c100 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/schematree/node/SchemaMeasurementNode.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/schematree/node/SchemaMeasurementNode.java @@ -36,8 +36,8 @@ public class SchemaMeasurementNode extends SchemaNode implements IMeasurementSch private String alias; private IMeasurementSchema schema; - private Map tagMap; + private Map attributeMap; public SchemaMeasurementNode(String name, IMeasurementSchema schema) { super(name); @@ -82,6 +82,15 @@ public Map getTagMap() { return tagMap; } + @Override + public Map getAttributeMap() { + return attributeMap; + } + + public void setAttributeMap(Map attributeMap) { + this.attributeMap = attributeMap; + } + @Override public SchemaNode getChild(String name) { return null; @@ -144,6 +153,7 @@ public void serialize(OutputStream outputStream) throws IOException { schema.serializeTo(outputStream); ReadWriteIOUtils.write(tagMap, outputStream); + ReadWriteIOUtils.write(attributeMap, outputStream); } public static SchemaMeasurementNode deserialize(InputStream inputStream) throws IOException { @@ -161,10 +171,12 @@ public static SchemaMeasurementNode deserialize(InputStream inputStream) throws } Map tagMap = ReadWriteIOUtils.readMap(inputStream); + Map attributeMap = ReadWriteIOUtils.readMap(inputStream); SchemaMeasurementNode measurementNode = new SchemaMeasurementNode(name, schema); measurementNode.setAlias(alias); measurementNode.setTagMap(tagMap); + measurementNode.setAttributeMap(attributeMap); return measurementNode; } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/schematree/visitor/SchemaTreeDeviceVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/schematree/visitor/SchemaTreeDeviceVisitor.java index 42fe1b15db19a..684035cce16f5 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/schematree/visitor/SchemaTreeDeviceVisitor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/common/schematree/visitor/SchemaTreeDeviceVisitor.java @@ -67,7 +67,8 @@ protected DeviceSchemaInfo generateResult(SchemaNode nextMatchedNode) { measurementNode.getName(), measurementNode.getSchema(), measurementNode.getAlias(), - measurementNode.getTagMap())); + measurementNode.getTagMap(), + measurementNode.getAttributeMap())); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/driver/DataDriverContext.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/driver/DataDriverContext.java index 74c50b8790b23..03bd7bb8e626f 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/driver/DataDriverContext.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/driver/DataDriverContext.java @@ -21,6 +21,7 @@ import org.apache.iotdb.commons.path.IFullPath; import org.apache.iotdb.db.exception.query.QueryProcessException; +import org.apache.iotdb.db.queryengine.common.DeviceContext; import org.apache.iotdb.db.queryengine.execution.fragment.FragmentInstanceContext; import org.apache.iotdb.db.queryengine.execution.operator.source.DataSourceOperator; import org.apache.iotdb.db.storageengine.dataregion.IDataRegionForQuery; @@ -39,7 +40,7 @@ public class DataDriverContext extends DriverContext { // it will be set to null, after being merged into Parent FIContext private List paths; private QueryDataSourceType queryDataSourceType = null; - private Map deviceIDToAligned; + private Map deviceIDToContext; // it will be set to null, after QueryDataSource being inited private List sourceOperators; @@ -47,27 +48,27 @@ public DataDriverContext(FragmentInstanceContext fragmentInstanceContext, int pi super(fragmentInstanceContext, pipelineId); this.paths = new ArrayList<>(); this.sourceOperators = new ArrayList<>(); - this.deviceIDToAligned = null; + this.deviceIDToContext = null; } public DataDriverContext(DataDriverContext parentContext, int pipelineId) { super(parentContext.getFragmentInstanceContext(), pipelineId); this.paths = new ArrayList<>(); this.sourceOperators = new ArrayList<>(); - this.deviceIDToAligned = null; + this.deviceIDToContext = null; } public void setQueryDataSourceType(QueryDataSourceType queryDataSourceType) { this.queryDataSourceType = queryDataSourceType; } - public void setDeviceIDToAligned(Map deviceIDToAligned) { - this.deviceIDToAligned = deviceIDToAligned; + public void setDeviceIDToContext(Map deviceIDToContext) { + this.deviceIDToContext = deviceIDToContext; } - public void clearDeviceIDToAligned() { + public void clearDeviceIDToContext() { // friendly for gc - deviceIDToAligned = null; + deviceIDToContext = null; } public void addPath(IFullPath path) { @@ -82,8 +83,8 @@ public List getPaths() { return paths; } - public Map getDeviceIDToAligned() { - return deviceIDToAligned; + public Map getDeviceIDToContext() { + return deviceIDToContext; } public Optional getQueryDataSourceType() { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/exchange/MPPDataExchangeManager.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/exchange/MPPDataExchangeManager.java index 2b59d72cd0700..ac0b411109089 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/exchange/MPPDataExchangeManager.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/exchange/MPPDataExchangeManager.java @@ -20,6 +20,7 @@ package org.apache.iotdb.db.queryengine.execution.exchange; import org.apache.iotdb.common.rpc.thrift.TEndPoint; +import org.apache.iotdb.common.rpc.thrift.TSStatus; import org.apache.iotdb.commons.client.IClientManager; import org.apache.iotdb.commons.client.sync.SyncDataNodeMPPDataExchangeServiceClient; import org.apache.iotdb.db.queryengine.exception.exchange.GetTsBlockFromClosedOrAbortedChannelException; @@ -49,6 +50,7 @@ import org.apache.iotdb.mpp.rpc.thrift.TGetDataBlockRequest; import org.apache.iotdb.mpp.rpc.thrift.TGetDataBlockResponse; import org.apache.iotdb.mpp.rpc.thrift.TNewDataBlockEvent; +import org.apache.iotdb.rpc.TSStatusCode; import org.apache.commons.lang3.Validate; import org.apache.thrift.TException; @@ -283,6 +285,11 @@ public void onEndOfDataBlockEvent(TEndOfDataBlockEvent e) throws TException { sourceHandle.setNoMoreTsBlocks(e.getLastSequenceId()); } } + + @Override + public TSStatus testConnectionEmptyRPC() throws TException { + return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()); + } } // endregion @@ -578,11 +585,13 @@ public MPPDataExchangeManager( ExecutorService executorService, IClientManager mppDataExchangeServiceClientManager) { - this.localMemoryManager = Validate.notNull(localMemoryManager); - this.tsBlockSerdeFactory = Validate.notNull(tsBlockSerdeFactory); - this.executorService = Validate.notNull(executorService); + this.localMemoryManager = Validate.notNull(localMemoryManager, "localMemoryManager is null."); + this.tsBlockSerdeFactory = + Validate.notNull(tsBlockSerdeFactory, "tsBlockSerdeFactory is null."); + this.executorService = Validate.notNull(executorService, "executorService is null."); this.mppDataExchangeServiceClientManager = - Validate.notNull(mppDataExchangeServiceClientManager); + Validate.notNull( + mppDataExchangeServiceClientManager, "mppDataExchangeServiceClientManager is null."); sourceHandles = new ConcurrentHashMap<>(); shuffleSinkHandles = new ConcurrentHashMap<>(); } @@ -594,10 +603,11 @@ public MPPDataExchangeServiceImpl getOrCreateMPPDataExchangeServiceImpl() { return mppDataExchangeService; } - public void deRegisterFragmentInstanceFromMemoryPool(String queryId, String fragmentInstanceId) { + public void deRegisterFragmentInstanceFromMemoryPool( + String queryId, String fragmentInstanceId, boolean forceDeregister) { localMemoryManager .getQueryPool() - .deRegisterFragmentInstanceFromQueryMemoryMap(queryId, fragmentInstanceId); + .deRegisterFragmentInstanceFromQueryMemoryMap(queryId, fragmentInstanceId, forceDeregister); } public LocalMemoryManager getLocalMemoryManager() { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/fragment/FragmentInstanceContext.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/fragment/FragmentInstanceContext.java index 861d14203add3..eab61c8a2c961 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/fragment/FragmentInstanceContext.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/fragment/FragmentInstanceContext.java @@ -22,6 +22,7 @@ import org.apache.iotdb.commons.path.IFullPath; import org.apache.iotdb.commons.utils.TestOnly; import org.apache.iotdb.db.exception.query.QueryProcessException; +import org.apache.iotdb.db.queryengine.common.DeviceContext; import org.apache.iotdb.db.queryengine.common.FragmentInstanceId; import org.apache.iotdb.db.queryengine.common.QueryId; import org.apache.iotdb.db.queryengine.common.SessionInfo; @@ -69,7 +70,7 @@ public class FragmentInstanceContext extends QueryContext { private List sourcePaths; // Used for region scan, relating methods are to be added. - private Map devicePathsToAligned; + private Map devicePathsToContext; // Shared by all scan operators in this fragment instance to avoid memory problem private IQueryDataSource sharedQueryDataSource; @@ -266,6 +267,14 @@ private void updateStatsIfDone(FragmentInstanceState newState) { // were a duplicate notification, which shouldn't happen executionEndTime.compareAndSet(END_TIME_INITIAL_VALUE, now); endNanos.compareAndSet(0, System.nanoTime()); + + // release some query resource in FragmentInstanceContext + // why not release them in releaseResourceWhenAllDriversAreClosed() together? + // because we may have no chane to run the releaseResourceWhenAllDriversAreClosed which is + // called in callback of FragmentInstanceExecution + // FragmentInstanceExecution won't be created if we meet some errors like MemoryNotEnough + releaseDataNodeQueryContext(); + sourcePaths = null; } } @@ -358,8 +367,8 @@ public void setSourcePaths(List sourcePaths) { this.sourcePaths = sourcePaths; } - public void setDevicePathsToAligned(Map devicePathsToAligned) { - this.devicePathsToAligned = devicePathsToAligned; + public void setDevicePathsToContext(Map devicePathsToContext) { + this.devicePathsToContext = devicePathsToContext; } public void initQueryDataSource(List sourcePaths) throws QueryProcessException { @@ -401,17 +410,17 @@ public void initQueryDataSource(List sourcePaths) throws QueryProcess } } - public void initRegionScanQueryDataSource(Map devicePathToAligned) + public void initRegionScanQueryDataSource(Map devicePathsToContext) throws QueryProcessException { long startTime = System.nanoTime(); - if (devicePathsToAligned == null) { + if (devicePathsToContext == null) { return; } dataRegion.readLock(); try { this.sharedQueryDataSource = dataRegion.queryForDeviceRegionScan( - devicePathToAligned, + devicePathsToContext, this, globalTimeFilter != null ? globalTimeFilter.copy() : null, timePartitions); @@ -461,8 +470,8 @@ public synchronized IQueryDataSource getSharedQueryDataSource() throws QueryProc sourcePaths = null; break; case DEVICE_REGION_SCAN: - initRegionScanQueryDataSource(devicePathsToAligned); - devicePathsToAligned = null; + initRegionScanQueryDataSource(devicePathsToContext); + devicePathsToContext = null; break; case TIME_SERIES_REGION_SCAN: initRegionScanQueryDataSource(sourcePaths); @@ -596,9 +605,7 @@ public synchronized void releaseResource() { dataRegion = null; globalTimeFilter = null; - sourcePaths = null; sharedQueryDataSource = null; - releaseDataNodeQueryContext(); // record fragment instance execution time and metadata get time to metrics long durationTime = System.currentTimeMillis() - executionStartTime.get(); @@ -659,7 +666,7 @@ public synchronized void releaseResource() { .updatePageReaderMemoryUsage(getQueryStatistics().pageReaderMaxUsedMemorySize.get()); } - private void releaseDataNodeQueryContext() { + private synchronized void releaseDataNodeQueryContext() { if (dataNodeQueryContextMap == null) { // this process is in fetch schema, nothing need to release return; diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/fragment/FragmentInstanceExecution.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/fragment/FragmentInstanceExecution.java index d4ba3abd9697c..b31d4e13eeb94 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/fragment/FragmentInstanceExecution.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/fragment/FragmentInstanceExecution.java @@ -309,7 +309,7 @@ private void initialize(IDriverScheduler scheduler, boolean isExplainAnalyze) { // release memory exchangeManager.deRegisterFragmentInstanceFromMemoryPool( - instanceId.getQueryId().getId(), instanceId.getFragmentInstanceId()); + instanceId.getQueryId().getId(), instanceId.getFragmentInstanceId(), true); if (newState.isFailed()) { scheduler.abortFragmentInstance(instanceId); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/fragment/FragmentInstanceManager.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/fragment/FragmentInstanceManager.java index bea961c7525a9..900865dc88701 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/fragment/FragmentInstanceManager.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/fragment/FragmentInstanceManager.java @@ -177,6 +177,7 @@ public FragmentInstanceInfo execDataQueryFragmentInstance( instance.isExplainAnalyze(), exchangeManager); } catch (Throwable t) { + clearFIRelatedResources(instanceId); logger.warn("error when create FragmentInstanceExecution.", t); stateMachine.failed(t); return null; @@ -205,6 +206,14 @@ public FragmentInstanceInfo execDataQueryFragmentInstance( } } + private void clearFIRelatedResources(FragmentInstanceId instanceId) { + // close and remove all the handles of the fragment instance + exchangeManager.forceDeregisterFragmentInstance(instanceId.toThrift()); + // clear MemoryPool + exchangeManager.deRegisterFragmentInstanceFromMemoryPool( + instanceId.getQueryId().getId(), instanceId.getFragmentInstanceId(), false); + } + private DataNodeQueryContext getOrCreateDataNodeQueryContext(QueryId queryId, int dataNodeFINum) { return dataNodeQueryContextMap.computeIfAbsent( queryId, queryId1 -> new DataNodeQueryContext(dataNodeFINum)); @@ -249,6 +258,7 @@ public FragmentInstanceInfo execSchemaQueryFragmentInstance( false, exchangeManager); } catch (Throwable t) { + clearFIRelatedResources(instanceId); logger.warn("Execute error caused by ", t); stateMachine.failed(t); return null; diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/load/AlignedChunkData.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/load/AlignedChunkData.java index 46bd37e630b9e..00d8a605a7548 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/load/AlignedChunkData.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/load/AlignedChunkData.java @@ -75,7 +75,9 @@ public class AlignedChunkData implements ChunkData { private List chunkList; public AlignedChunkData( - String device, ChunkHeader chunkHeader, TTimePartitionSlot timePartitionSlot) { + final String device, + final ChunkHeader chunkHeader, + final TTimePartitionSlot timePartitionSlot) { this.dataSize = 0; this.device = device; this.chunkHeaderList = new ArrayList<>(); @@ -94,7 +96,7 @@ public AlignedChunkData( private void addAttrDataSize() { // Should be init before serialize, corresponding serializeAttr dataSize += 2 * Byte.BYTES; // isModification and isAligned dataSize += Long.BYTES; // timePartitionSlot - int deviceLength = device.getBytes(TSFileConfig.STRING_CHARSET).length; + final int deviceLength = device.getBytes(TSFileConfig.STRING_CHARSET).length; dataSize += ReadWriteForEncodingUtils.varIntSize(deviceLength); dataSize += deviceLength; // device dataSize += Integer.BYTES; // chunkHeaderListSize @@ -127,9 +129,9 @@ public boolean isAligned() { } @Override - public void writeToFileWriter(TsFileIOWriter writer) throws IOException { + public void writeToFileWriter(final TsFileIOWriter writer) throws IOException { if (chunkList != null) { - for (Chunk chunk : chunkList) { + for (final Chunk chunk : chunkList) { writer.writeChunk(chunk); } } else { @@ -137,7 +139,7 @@ public void writeToFileWriter(TsFileIOWriter writer) throws IOException { } } - public void addValueChunk(ChunkHeader chunkHeader) { + public void addValueChunk(final ChunkHeader chunkHeader) { this.chunkHeaderList.add(chunkHeader); this.pageNumbers.add(0); dataSize += chunkHeader.getSerializedSize(); @@ -147,7 +149,7 @@ public void addValueChunk(ChunkHeader chunkHeader) { } @Override - public void serialize(DataOutputStream stream) throws IOException { + public void serialize(final DataOutputStream stream) throws IOException { ReadWriteIOUtils.write(isModification(), stream); ReadWriteIOUtils.write(isAligned(), stream); serializeAttr(stream); @@ -155,31 +157,32 @@ public void serialize(DataOutputStream stream) throws IOException { close(); } - private void serializeAttr(DataOutputStream stream) throws IOException { + private void serializeAttr(final DataOutputStream stream) throws IOException { ReadWriteIOUtils.write(timePartitionSlot.getStartTime(), stream); ReadWriteIOUtils.write(device, stream); ReadWriteIOUtils.write(dataSize, stream); ReadWriteIOUtils.write(needDecodeChunk, stream); ReadWriteIOUtils.write(chunkHeaderList.size(), stream); - for (ChunkHeader chunkHeader : chunkHeaderList) { + for (final ChunkHeader chunkHeader : chunkHeaderList) { chunkHeader.serializeTo(stream); // Chunk header already serialize chunk type } if (needDecodeChunk) { - for (Integer pageNumber : pageNumbers) { + for (final Integer pageNumber : pageNumbers) { ReadWriteIOUtils.write(pageNumber, stream); } } } @Override - public void writeEntireChunk(ByteBuffer chunkData, IChunkMetadata chunkMetadata) + public void writeEntireChunk(final ByteBuffer chunkData, final IChunkMetadata chunkMetadata) throws IOException { dataSize += ReadWriteIOUtils.write(chunkData, stream); dataSize += chunkMetadata.getStatistics().serialize(stream); } @Override - public void writeEntirePage(PageHeader pageHeader, ByteBuffer pageData) throws IOException { + public void writeEntirePage(final PageHeader pageHeader, final ByteBuffer pageData) + throws IOException { pageNumbers.set(pageNumbers.size() - 1, pageNumbers.get(pageNumbers.size() - 1) + 1); // serialize needDecode==false dataSize += ReadWriteIOUtils.write(false, stream); @@ -190,17 +193,17 @@ public void writeEntirePage(PageHeader pageHeader, ByteBuffer pageData) throws I } @Override - public void writeDecodePage(long[] times, Object[] values, int satisfiedLength) + public void writeDecodePage(final long[] times, final Object[] values, final int satisfiedLength) throws IOException { pageNumbers.set(pageNumbers.size() - 1, pageNumbers.get(pageNumbers.size() - 1) + 1); satisfiedLengthQueue.offer(satisfiedLength); - long startTime = timePartitionSlot.getStartTime(); - long endTime = startTime + TimePartitionUtils.getTimePartitionInterval(); + final long startTime = timePartitionSlot.getStartTime(); + final long endTime = startTime + TimePartitionUtils.getTimePartitionInterval(); // serialize needDecode==true dataSize += ReadWriteIOUtils.write(true, stream); dataSize += ReadWriteIOUtils.write(satisfiedLength, stream); - for (long time : times) { + for (final long time : times) { if (time >= endTime) { break; } @@ -210,12 +213,13 @@ public void writeDecodePage(long[] times, Object[] values, int satisfiedLength) } } - public void writeDecodeValuePage(long[] times, TsPrimitiveType[] values, TSDataType dataType) + public void writeDecodeValuePage( + final long[] times, final TsPrimitiveType[] values, final TSDataType dataType) throws IOException { pageNumbers.set(pageNumbers.size() - 1, pageNumbers.get(pageNumbers.size() - 1) + 1); - long startTime = timePartitionSlot.getStartTime(); - long endTime = startTime + TimePartitionUtils.getTimePartitionInterval(); - int satisfiedLength = satisfiedLengthQueue.poll(); + final long startTime = timePartitionSlot.getStartTime(); + final long endTime = startTime + TimePartitionUtils.getTimePartitionInterval(); + final int satisfiedLength = satisfiedLengthQueue.poll(); // serialize needDecode==true dataSize += ReadWriteIOUtils.write(true, stream); dataSize += ReadWriteIOUtils.write(satisfiedLength, stream); @@ -232,9 +236,11 @@ public void writeDecodeValuePage(long[] times, TsPrimitiveType[] values, TSDataT dataSize += ReadWriteIOUtils.write(false, stream); switch (dataType) { case INT32: + case DATE: dataSize += ReadWriteIOUtils.write(values[i].getInt(), stream); break; case INT64: + case TIMESTAMP: dataSize += ReadWriteIOUtils.write(values[i].getLong(), stream); break; case FLOAT: @@ -247,6 +253,8 @@ public void writeDecodeValuePage(long[] times, TsPrimitiveType[] values, TSDataT dataSize += ReadWriteIOUtils.write(values[i].getBoolean(), stream); break; case TEXT: + case BLOB: + case STRING: dataSize += ReadWriteIOUtils.write(values[i].getBinary(), stream); break; default: @@ -258,7 +266,7 @@ public void writeDecodeValuePage(long[] times, TsPrimitiveType[] values, TSDataT } } - private void deserializeTsFileData(InputStream stream) throws IOException, PageException { + private void deserializeTsFileData(final InputStream stream) throws IOException, PageException { if (needDecodeChunk) { buildChunkWriter(stream); } else { @@ -266,21 +274,21 @@ private void deserializeTsFileData(InputStream stream) throws IOException, PageE } } - private void deserializeEntireChunk(InputStream stream) throws IOException { + private void deserializeEntireChunk(final InputStream stream) throws IOException { chunkList = new ArrayList<>(); - for (ChunkHeader chunkHeader : chunkHeaderList) { - ByteBuffer chunkData = + for (final ChunkHeader chunkHeader : chunkHeaderList) { + final ByteBuffer chunkData = ByteBuffer.wrap(ReadWriteIOUtils.readBytesWithSelfDescriptionLength(stream)); - Statistics statistics = + final Statistics statistics = Statistics.deserialize(stream, chunkHeader.getDataType()); chunkList.add(new Chunk(chunkHeader, chunkData, null, statistics)); } } - private void buildChunkWriter(InputStream stream) throws IOException, PageException { - List measurementSchemaList = new ArrayList<>(); + private void buildChunkWriter(final InputStream stream) throws IOException, PageException { + final List measurementSchemaList = new ArrayList<>(); IMeasurementSchema timeSchema = null; - for (ChunkHeader chunkHeader : chunkHeaderList) { + for (final ChunkHeader chunkHeader : chunkHeaderList) { if (TSDataType.VECTOR.equals(chunkHeader.getDataType())) { timeSchema = new MeasurementSchema( @@ -299,7 +307,7 @@ private void buildChunkWriter(InputStream stream) throws IOException, PageExcept } chunkWriter = new AlignedChunkWriterImpl(timeSchema, measurementSchemaList); timeBatch = new ArrayList<>(); - int chunkHeaderSize = chunkHeaderList.size(); + final int chunkHeaderSize = chunkHeaderList.size(); for (int i = 0; i < chunkHeaderSize; i++) { buildChunk(stream, chunkHeaderList.get(i), pageNumbers.get(i), i - 1, i == 0); } @@ -308,52 +316,60 @@ private void buildChunkWriter(InputStream stream) throws IOException, PageExcept @SuppressWarnings({"squid:S6541", "squid:S3776"}) private void buildChunk( - InputStream stream, - ChunkHeader chunkHeader, - int pageNumber, - int valueChunkIndex, - boolean isTimeChunk) + final InputStream stream, + final ChunkHeader chunkHeader, + final int pageNumber, + final int valueChunkIndex, + final boolean isTimeChunk) throws IOException, PageException { boolean needDecode; int decodePageIndex = 0; for (int j = 0; j < pageNumber; j++) { needDecode = ReadWriteIOUtils.readBool(stream); if (needDecode) { - int length = ReadWriteIOUtils.readInt(stream); + final int length = ReadWriteIOUtils.readInt(stream); long[] timePageBatch = new long[length]; if (!isTimeChunk) { timePageBatch = timeBatch.get(decodePageIndex); } for (int i = 0; i < length; i++) { if (isTimeChunk) { - long time = ReadWriteIOUtils.readLong(stream); + final long time = ReadWriteIOUtils.readLong(stream); timePageBatch[i] = time; chunkWriter.writeTime(time); } else { - boolean isNull = ReadWriteIOUtils.readBool(stream); + final boolean isNull = ReadWriteIOUtils.readBool(stream); switch (chunkHeader.getDataType()) { case INT32: - int int32Value = isNull ? DEFAULT_INT32 : ReadWriteIOUtils.readInt(stream); + case DATE: + final int int32Value = isNull ? DEFAULT_INT32 : ReadWriteIOUtils.readInt(stream); chunkWriter.write(timePageBatch[i], int32Value, isNull, valueChunkIndex); break; case INT64: - long int64Value = isNull ? DEFAULT_INT64 : ReadWriteIOUtils.readLong(stream); + case TIMESTAMP: + final long int64Value = isNull ? DEFAULT_INT64 : ReadWriteIOUtils.readLong(stream); chunkWriter.write(timePageBatch[i], int64Value, isNull, valueChunkIndex); break; case FLOAT: - float floatValue = isNull ? DEFAULT_FLOAT : ReadWriteIOUtils.readFloat(stream); + final float floatValue = + isNull ? DEFAULT_FLOAT : ReadWriteIOUtils.readFloat(stream); chunkWriter.write(timePageBatch[i], floatValue, isNull, valueChunkIndex); break; case DOUBLE: - double doubleValue = isNull ? DEFAULT_DOUBLE : ReadWriteIOUtils.readDouble(stream); + final double doubleValue = + isNull ? DEFAULT_DOUBLE : ReadWriteIOUtils.readDouble(stream); chunkWriter.write(timePageBatch[i], doubleValue, isNull, valueChunkIndex); break; case BOOLEAN: - boolean boolValue = isNull ? DEFAULT_BOOLEAN : ReadWriteIOUtils.readBool(stream); + final boolean boolValue = + isNull ? DEFAULT_BOOLEAN : ReadWriteIOUtils.readBool(stream); chunkWriter.write(timePageBatch[i], boolValue, isNull, valueChunkIndex); break; case TEXT: - Binary binaryValue = isNull ? DEFAULT_BINARY : ReadWriteIOUtils.readBinary(stream); + case BLOB: + case STRING: + final Binary binaryValue = + isNull ? DEFAULT_BINARY : ReadWriteIOUtils.readBinary(stream); chunkWriter.write(timePageBatch[i], binaryValue, isNull, valueChunkIndex); break; default: @@ -373,7 +389,8 @@ private void buildChunk( chunkWriter.sealCurrentValuePage(valueChunkIndex); } } else { - PageHeader pageHeader = PageHeader.deserializeFrom(stream, chunkHeader.getDataType(), true); + final PageHeader pageHeader = + PageHeader.deserializeFrom(stream, chunkHeader.getDataType(), true); if (isTimeChunk) { chunkWriter.writePageHeaderAndDataIntoTimeBuff( ByteBuffer.wrap(ReadWriteIOUtils.readBytesWithSelfDescriptionLength(stream)), @@ -388,26 +405,27 @@ private void buildChunk( } } - public static AlignedChunkData deserialize(InputStream stream) throws IOException, PageException { - TTimePartitionSlot timePartitionSlot = + public static AlignedChunkData deserialize(final InputStream stream) + throws IOException, PageException { + final TTimePartitionSlot timePartitionSlot = TimePartitionUtils.getTimePartitionSlot(ReadWriteIOUtils.readLong(stream)); - String device = ReadWriteIOUtils.readString(stream); - long dataSize = ReadWriteIOUtils.readLong(stream); - boolean needDecodeChunk = ReadWriteIOUtils.readBool(stream); - int chunkHeaderListSize = ReadWriteIOUtils.readInt(stream); - List chunkHeaderList = new ArrayList<>(); + final String device = ReadWriteIOUtils.readString(stream); + final long dataSize = ReadWriteIOUtils.readLong(stream); + final boolean needDecodeChunk = ReadWriteIOUtils.readBool(stream); + final int chunkHeaderListSize = ReadWriteIOUtils.readInt(stream); + final List chunkHeaderList = new ArrayList<>(); for (int i = 0; i < chunkHeaderListSize; i++) { - byte chunkType = ReadWriteIOUtils.readByte(stream); + final byte chunkType = ReadWriteIOUtils.readByte(stream); chunkHeaderList.add(ChunkHeader.deserializeFrom(stream, chunkType)); } - List pageNumbers = new ArrayList<>(); + final List pageNumbers = new ArrayList<>(); if (needDecodeChunk) { for (int i = 0; i < chunkHeaderListSize; i++) { pageNumbers.add(ReadWriteIOUtils.readInt(stream)); } } - AlignedChunkData chunkData = + final AlignedChunkData chunkData = new AlignedChunkData(device, chunkHeaderList.get(0), timePartitionSlot); chunkData.needDecodeChunk = needDecodeChunk; chunkData.chunkHeaderList = chunkHeaderList; diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/load/LoadTsFileManager.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/load/LoadTsFileManager.java index ad97937848727..4c2039bacf01c 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/load/LoadTsFileManager.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/load/LoadTsFileManager.java @@ -29,8 +29,9 @@ import org.apache.iotdb.commons.utils.FileUtils; import org.apache.iotdb.db.conf.IoTDBConfig; import org.apache.iotdb.db.conf.IoTDBDescriptor; +import org.apache.iotdb.db.exception.DiskSpaceInsufficientException; import org.apache.iotdb.db.exception.LoadFileException; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.load.LoadTsFilePieceNode; import org.apache.iotdb.db.queryengine.plan.scheduler.load.LoadTsFileScheduler.LoadCommand; import org.apache.iotdb.db.storageengine.dataregion.DataRegion; @@ -38,6 +39,8 @@ import org.apache.iotdb.db.storageengine.dataregion.modification.ModificationFile; import org.apache.iotdb.db.storageengine.dataregion.tsfile.TsFileResource; import org.apache.iotdb.db.storageengine.dataregion.utils.TsFileResourceUtils; +import org.apache.iotdb.db.storageengine.rescon.disk.FolderManager; +import org.apache.iotdb.db.storageengine.rescon.disk.strategy.DirectoryStrategyType; import org.apache.iotdb.metrics.utils.MetricLevel; import org.apache.tsfile.common.constant.TsFileConstant; @@ -51,12 +54,16 @@ import java.nio.file.DirectoryNotEmptyException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Arrays; import java.util.HashMap; import java.util.Map; import java.util.Objects; import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.PriorityBlockingQueue; +import java.util.concurrent.atomic.AtomicReference; +import java.util.stream.Collectors; +import java.util.stream.Stream; /** * {@link LoadTsFileManager} is used for dealing with {@link LoadTsFilePieceNode} and {@link @@ -74,7 +81,9 @@ public class LoadTsFileManager { "%s TsFileWriterManager has been closed."; private static final String MESSAGE_DELETE_FAIL = "failed to delete {}."; - private final File loadDir; + private static final AtomicReference LOAD_BASE_DIRS = + new AtomicReference<>(CONFIG.getLoadTsFileDirs()); + private static final AtomicReference FOLDER_MANAGER = new AtomicReference<>(); private final Map uuid2WriterManager = new ConcurrentHashMap<>(); @@ -82,14 +91,12 @@ public class LoadTsFileManager { private final PriorityBlockingQueue cleanupTaskQueue = new PriorityBlockingQueue<>(); public LoadTsFileManager() { - this.loadDir = SystemFileFactory.INSTANCE.getFile(CONFIG.getLoadTsFileDir()); - registerCleanupTaskExecutor(); recover(); } private void registerCleanupTaskExecutor() { - PipeAgent.runtime() + PipeDataNodeAgent.runtime() .registerPeriodicalJob( "LoadTsFileManager#cleanupTasks", this::cleanupTasks, @@ -130,28 +137,43 @@ private void cleanupTasks() { } private void recover() { - if (!loadDir.exists()) { - return; - } - - final File[] files = loadDir.listFiles(); - if (files == null) { - return; - } - for (final File taskDir : files) { - String uuid = taskDir.getName(); - TsFileWriterManager writerManager = new TsFileWriterManager(taskDir); - - uuid2WriterManager.put(uuid, writerManager); - writerManager.close(); - - synchronized (uuid2CleanupTask) { - final CleanupTask cleanupTask = - new CleanupTask(uuid, CONFIG.getLoadCleanupTaskExecutionDelayTimeSeconds() * 1000); - uuid2CleanupTask.put(uuid, cleanupTask); - cleanupTaskQueue.add(cleanupTask); + if (CONFIG.getLoadTsFileDirs() != LOAD_BASE_DIRS.get()) { + synchronized (FOLDER_MANAGER) { + if (CONFIG.getLoadTsFileDirs() != LOAD_BASE_DIRS.get()) { + LOAD_BASE_DIRS.set(CONFIG.getLoadTsFileDirs()); + } } } + + final File[] baseDirs = Arrays.stream(LOAD_BASE_DIRS.get()).map(File::new).toArray(File[]::new); + final File[] files = + Arrays.stream(baseDirs) + .filter(File::exists) + .flatMap( + dir -> { + final File[] listedFiles = dir.listFiles(); + return listedFiles != null ? Arrays.stream(listedFiles) : Stream.empty(); + }) + .toArray(File[]::new); + + Arrays.stream(files) + .parallel() + .forEach( + taskDir -> { + final String uuid = taskDir.getName(); + final TsFileWriterManager writerManager = new TsFileWriterManager(taskDir); + + uuid2WriterManager.put(uuid, writerManager); + writerManager.close(); + + synchronized (uuid2CleanupTask) { + final CleanupTask cleanupTask = + new CleanupTask( + uuid, CONFIG.getLoadCleanupTaskExecutionDelayTimeSeconds() * 1000); + uuid2CleanupTask.put(uuid, cleanupTask); + cleanupTaskQueue.add(cleanupTask); + } + }); } public void writeToDataRegion(DataRegion dataRegion, LoadTsFilePieceNode pieceNode, String uuid) @@ -168,10 +190,26 @@ public void writeToDataRegion(DataRegion dataRegion, LoadTsFilePieceNode pieceNo final Optional cleanupTask = Optional.of(uuid2CleanupTask.get(uuid)); cleanupTask.ifPresent(CleanupTask::markLoadTaskRunning); try { + final AtomicReference exception = new AtomicReference<>(); final TsFileWriterManager writerManager = uuid2WriterManager.computeIfAbsent( uuid, - o -> new TsFileWriterManager(SystemFileFactory.INSTANCE.getFile(loadDir, uuid))); + o -> { + try { + return new TsFileWriterManager(new File(getNextFolder(), uuid)); + } catch (DiskSpaceInsufficientException e) { + exception.set(e); + return null; + } + }); + if (exception.get() != null || writerManager == null) { + throw new IOException( + "Failed to create TsFileWriterManager for uuid " + + uuid + + " because of insufficient disk space.", + exception.get()); + } + for (TsFileData tsFileData : pieceNode.getAllTsFileData()) { if (!tsFileData.isModification()) { ChunkData chunkData = (ChunkData) tsFileData; @@ -186,6 +224,33 @@ public void writeToDataRegion(DataRegion dataRegion, LoadTsFilePieceNode pieceNo } } + private String getNextFolder() throws DiskSpaceInsufficientException { + if (CONFIG.getLoadTsFileDirs() != LOAD_BASE_DIRS.get()) { + synchronized (FOLDER_MANAGER) { + if (CONFIG.getLoadTsFileDirs() != LOAD_BASE_DIRS.get()) { + LOAD_BASE_DIRS.set(CONFIG.getLoadTsFileDirs()); + FOLDER_MANAGER.set( + new FolderManager( + Arrays.asList(LOAD_BASE_DIRS.get()), DirectoryStrategyType.SEQUENCE_STRATEGY)); + return FOLDER_MANAGER.get().getNextFolder(); + } + } + } + + if (FOLDER_MANAGER.get() == null) { + synchronized (FOLDER_MANAGER) { + if (FOLDER_MANAGER.get() == null) { + FOLDER_MANAGER.set( + new FolderManager( + Arrays.asList(LOAD_BASE_DIRS.get()), DirectoryStrategyType.SEQUENCE_STRATEGY)); + return FOLDER_MANAGER.get().getNextFolder(); + } + } + } + + return FOLDER_MANAGER.get().getNextFolder(); + } + public boolean loadAll(String uuid, boolean isGeneratedByPipe, ProgressIndex progressIndex) throws IOException, LoadFileException { if (!uuid2WriterManager.containsKey(uuid)) { @@ -229,17 +294,20 @@ private void forceCloseWriterManager(String uuid) { writerManager.close(); } - final Path loadDirPath = loadDir.toPath(); - if (!Files.exists(loadDirPath)) { - return; - } - try { - Files.deleteIfExists(loadDirPath); - LOGGER.info("Load dir {} was deleted.", loadDirPath); - } catch (DirectoryNotEmptyException e) { - LOGGER.info("Load dir {} is not empty, skip deleting.", loadDirPath); - } catch (IOException e) { - LOGGER.info(MESSAGE_DELETE_FAIL, loadDirPath); + for (final Path loadDirPath : + Arrays.stream(LOAD_BASE_DIRS.get()) + .map(File::new) + .filter(File::exists) + .map(File::toPath) + .collect(Collectors.toList())) { + try { + Files.deleteIfExists(loadDirPath); + LOGGER.info("Load dir {} was deleted.", loadDirPath); + } catch (DirectoryNotEmptyException e) { + LOGGER.info("Load dir {} is not empty, skip deleting.", loadDirPath); + } catch (Exception e) { + LOGGER.info(MESSAGE_DELETE_FAIL, loadDirPath); + } } } @@ -344,6 +412,7 @@ private void loadAll(boolean isGeneratedByPipe, ProgressIndex progressIndex) DataRegion dataRegion = entry.getKey().getDataRegion(); dataRegion.loadNewTsFile(generateResource(writer, progressIndex), true, isGeneratedByPipe); + // Metrics dataRegion .getNonSystemDatabaseName() .ifPresent( @@ -363,7 +432,9 @@ private void loadAll(boolean isGeneratedByPipe, ProgressIndex progressIndex) Tag.DATABASE.toString(), databaseName, Tag.REGION.toString(), - dataRegion.getDataRegionId()); + dataRegion.getDataRegionId(), + Tag.TYPE.toString(), + Metric.LOAD_POINT_COUNT.toString()); }); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/load/LoadTsFileRateLimiter.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/load/LoadTsFileRateLimiter.java index ce7046bf5ee54..dedda70996de4 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/load/LoadTsFileRateLimiter.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/load/LoadTsFileRateLimiter.java @@ -19,12 +19,16 @@ package org.apache.iotdb.db.queryengine.execution.load; +import org.apache.iotdb.commons.pipe.config.PipeConfig; import org.apache.iotdb.db.conf.IoTDBConfig; import org.apache.iotdb.db.conf.IoTDBDescriptor; +import org.apache.iotdb.db.queryengine.metric.load.LoadTsFileCostMetricsSet; import com.google.common.util.concurrent.AtomicDouble; import com.google.common.util.concurrent.RateLimiter; +import java.util.concurrent.TimeUnit; + public class LoadTsFileRateLimiter { private static final IoTDBConfig CONFIG = IoTDBDescriptor.getInstance().getConfig(); @@ -34,31 +38,48 @@ public class LoadTsFileRateLimiter { private final RateLimiter loadWriteRateLimiter; public void acquire(long bytes) { - final double throughputBytesPerSecondLimit = CONFIG.getLoadWriteThroughputBytesPerSecond(); - - if (throughputBytesPerSecond.get() != throughputBytesPerSecondLimit) { - throughputBytesPerSecond.set(throughputBytesPerSecondLimit); - loadWriteRateLimiter.setRate( - // if throughput <= 0, disable rate limiting - throughputBytesPerSecondLimit <= 0 ? Double.MAX_VALUE : throughputBytesPerSecondLimit); - } + LoadTsFileCostMetricsSet.getInstance().recordDiskIO(bytes); - // For performance, we don't need to acquire rate limiter if throughput <= 0 - if (throughputBytesPerSecondLimit <= 0) { + if (reloadParams()) { return; } while (bytes > 0) { if (bytes > Integer.MAX_VALUE) { - loadWriteRateLimiter.acquire(Integer.MAX_VALUE); + tryAcquireWithRateCheck(Integer.MAX_VALUE); bytes -= Integer.MAX_VALUE; } else { - loadWriteRateLimiter.acquire((int) bytes); + tryAcquireWithRateCheck((int) bytes); return; } } } + private void tryAcquireWithRateCheck(final int bytes) { + while (!loadWriteRateLimiter.tryAcquire( + bytes, + PipeConfig.getInstance().getPipeEndPointRateLimiterDropCheckIntervalMs(), + TimeUnit.MILLISECONDS)) { + if (reloadParams()) { + return; + } + } + } + + private boolean reloadParams() { + final double throughputBytesPerSecondLimit = CONFIG.getLoadWriteThroughputBytesPerSecond(); + + if (throughputBytesPerSecond.get() != throughputBytesPerSecondLimit) { + throughputBytesPerSecond.set(throughputBytesPerSecondLimit); + loadWriteRateLimiter.setRate( + // if throughput <= 0, disable rate limiting + throughputBytesPerSecondLimit <= 0 ? Double.MAX_VALUE : throughputBytesPerSecondLimit); + } + + // For performance, we don't need to acquire rate limiter if throughput <= 0 + return throughputBytesPerSecondLimit <= 0; + } + //////////////////////////// Singleton //////////////////////////// private LoadTsFileRateLimiter() { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/load/NonAlignedChunkData.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/load/NonAlignedChunkData.java index 77467d55e98b1..2ae0acd2180bd 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/load/NonAlignedChunkData.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/load/NonAlignedChunkData.java @@ -60,7 +60,9 @@ public class NonAlignedChunkData implements ChunkData { private Chunk chunk; public NonAlignedChunkData( - String device, ChunkHeader chunkHeader, TTimePartitionSlot timePartitionSlot) { + final String device, + final ChunkHeader chunkHeader, + final TTimePartitionSlot timePartitionSlot) { this.dataSize = 0; this.device = device; this.chunkHeader = chunkHeader; @@ -76,7 +78,7 @@ public NonAlignedChunkData( private void addAttrDataSize() { // should be init before serialize, corresponding serializeAttr dataSize += 2 * Byte.BYTES; // isModification and isAligned dataSize += Long.BYTES; // timePartitionSlot - int deviceLength = device.getBytes(TSFileConfig.STRING_CHARSET).length; + final int deviceLength = device.getBytes(TSFileConfig.STRING_CHARSET).length; dataSize += ReadWriteForEncodingUtils.varIntSize(deviceLength); dataSize += deviceLength; // device dataSize += chunkHeader.getSerializedSize(); // timeChunkHeader @@ -108,7 +110,7 @@ public boolean isAligned() { } @Override - public void writeToFileWriter(TsFileIOWriter writer) throws IOException { + public void writeToFileWriter(final TsFileIOWriter writer) throws IOException { if (chunk != null) { writer.writeChunk(chunk); } else { @@ -117,7 +119,7 @@ public void writeToFileWriter(TsFileIOWriter writer) throws IOException { } @Override - public void serialize(DataOutputStream stream) throws IOException { + public void serialize(final DataOutputStream stream) throws IOException { ReadWriteIOUtils.write(isModification(), stream); ReadWriteIOUtils.write(isAligned(), stream); serializeAttr(stream); @@ -125,7 +127,7 @@ public void serialize(DataOutputStream stream) throws IOException { close(); } - private void serializeAttr(DataOutputStream stream) throws IOException { + private void serializeAttr(final DataOutputStream stream) throws IOException { ReadWriteIOUtils.write(timePartitionSlot.getStartTime(), stream); ReadWriteIOUtils.write(device, stream); ReadWriteIOUtils.write(dataSize, stream); @@ -137,14 +139,15 @@ private void serializeAttr(DataOutputStream stream) throws IOException { } @Override - public void writeEntireChunk(ByteBuffer chunkData, IChunkMetadata chunkMetadata) + public void writeEntireChunk(final ByteBuffer chunkData, final IChunkMetadata chunkMetadata) throws IOException { dataSize += ReadWriteIOUtils.write(chunkData, stream); dataSize += chunkMetadata.getStatistics().serialize(stream); } @Override - public void writeEntirePage(PageHeader pageHeader, ByteBuffer pageData) throws IOException { + public void writeEntirePage(final PageHeader pageHeader, final ByteBuffer pageData) + throws IOException { pageNumber += 1; dataSize += ReadWriteIOUtils.write(false, stream); dataSize += pageHeader.serializeTo(stream); @@ -152,11 +155,11 @@ public void writeEntirePage(PageHeader pageHeader, ByteBuffer pageData) throws I } @Override - public void writeDecodePage(long[] times, Object[] values, int satisfiedLength) + public void writeDecodePage(final long[] times, final Object[] values, final int satisfiedLength) throws IOException { pageNumber += 1; - long startTime = timePartitionSlot.getStartTime(); - long endTime = startTime + TimePartitionUtils.getTimePartitionInterval(); + final long startTime = timePartitionSlot.getStartTime(); + final long endTime = startTime + TimePartitionUtils.getTimePartitionInterval(); dataSize += ReadWriteIOUtils.write(true, stream); dataSize += ReadWriteIOUtils.write(satisfiedLength, stream); @@ -168,9 +171,11 @@ public void writeDecodePage(long[] times, Object[] values, int satisfiedLength) dataSize += ReadWriteIOUtils.write(times[i], stream); switch (chunkHeader.getDataType()) { case INT32: + case DATE: dataSize += ReadWriteIOUtils.write((int) values[i], stream); break; case INT64: + case TIMESTAMP: dataSize += ReadWriteIOUtils.write((long) values[i], stream); break; case FLOAT: @@ -183,6 +188,8 @@ public void writeDecodePage(long[] times, Object[] values, int satisfiedLength) dataSize += ReadWriteIOUtils.write((boolean) values[i], stream); break; case TEXT: + case BLOB: + case STRING: dataSize += ReadWriteIOUtils.write((Binary) values[i], stream); break; default: @@ -193,7 +200,7 @@ public void writeDecodePage(long[] times, Object[] values, int satisfiedLength) } } - private void deserializeTsFileData(InputStream stream) throws IOException, PageException { + private void deserializeTsFileData(final InputStream stream) throws IOException, PageException { if (needDecodeChunk) { buildChunkWriter(stream); } else { @@ -201,15 +208,15 @@ private void deserializeTsFileData(InputStream stream) throws IOException, PageE } } - private void deserializeEntireChunk(InputStream stream) throws IOException { - ByteBuffer chunkData = + private void deserializeEntireChunk(final InputStream stream) throws IOException { + final ByteBuffer chunkData = ByteBuffer.wrap(ReadWriteIOUtils.readBytesWithSelfDescriptionLength(stream)); - Statistics statistics = + final Statistics statistics = Statistics.deserialize(stream, chunkHeader.getDataType()); chunk = new Chunk(chunkHeader, chunkData, null, statistics); } - private void buildChunkWriter(InputStream stream) throws IOException, PageException { + private void buildChunkWriter(final InputStream stream) throws IOException, PageException { chunkWriter = new ChunkWriterImpl( new MeasurementSchema( @@ -221,14 +228,16 @@ private void buildChunkWriter(InputStream stream) throws IOException, PageExcept for (int j = 0; j < pageNumber; j++) { needDecode = ReadWriteIOUtils.readBool(stream); if (needDecode) { - int length = ReadWriteIOUtils.readInt(stream); + final int length = ReadWriteIOUtils.readInt(stream); for (int i = 0; i < length; i++) { - long time = ReadWriteIOUtils.readLong(stream); + final long time = ReadWriteIOUtils.readLong(stream); switch (chunkHeader.getDataType()) { case INT32: + case DATE: chunkWriter.write(time, ReadWriteIOUtils.readInt(stream)); break; case INT64: + case TIMESTAMP: chunkWriter.write(time, ReadWriteIOUtils.readLong(stream)); break; case FLOAT: @@ -241,6 +250,8 @@ private void buildChunkWriter(InputStream stream) throws IOException, PageExcept chunkWriter.write(time, ReadWriteIOUtils.readBool(stream)); break; case TEXT: + case BLOB: + case STRING: chunkWriter.write(time, ReadWriteIOUtils.readBinary(stream)); break; default: @@ -251,7 +262,8 @@ private void buildChunkWriter(InputStream stream) throws IOException, PageExcept chunkWriter.sealCurrentPage(); } else { - PageHeader pageHeader = PageHeader.deserializeFrom(stream, chunkHeader.getDataType(), true); + final PageHeader pageHeader = + PageHeader.deserializeFrom(stream, chunkHeader.getDataType(), true); chunkWriter.writePageHeaderAndDataIntoBuff( ByteBuffer.wrap(ReadWriteIOUtils.readBytesWithSelfDescriptionLength(stream)), pageHeader); @@ -259,21 +271,22 @@ private void buildChunkWriter(InputStream stream) throws IOException, PageExcept } } - public static NonAlignedChunkData deserialize(InputStream stream) + public static NonAlignedChunkData deserialize(final InputStream stream) throws IOException, PageException { - TTimePartitionSlot timePartitionSlot = + final TTimePartitionSlot timePartitionSlot = TimePartitionUtils.getTimePartitionSlot(ReadWriteIOUtils.readLong(stream)); - String device = ReadWriteIOUtils.readString(stream); - long dataSize = ReadWriteIOUtils.readLong(stream); - boolean needDecodeChunk = ReadWriteIOUtils.readBool(stream); - byte chunkType = ReadWriteIOUtils.readByte(stream); - ChunkHeader chunkHeader = ChunkHeader.deserializeFrom(stream, chunkType); + final String device = ReadWriteIOUtils.readString(stream); + final long dataSize = ReadWriteIOUtils.readLong(stream); + final boolean needDecodeChunk = ReadWriteIOUtils.readBool(stream); + final byte chunkType = ReadWriteIOUtils.readByte(stream); + final ChunkHeader chunkHeader = ChunkHeader.deserializeFrom(stream, chunkType); int pageNumber = 0; if (needDecodeChunk) { pageNumber = ReadWriteIOUtils.readInt(stream); } - NonAlignedChunkData chunkData = new NonAlignedChunkData(device, chunkHeader, timePartitionSlot); + final NonAlignedChunkData chunkData = + new NonAlignedChunkData(device, chunkHeader, timePartitionSlot); chunkData.needDecodeChunk = needDecodeChunk; chunkData.pageNumber = pageNumber; chunkData.deserializeTsFileData(stream); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/memory/MemoryPool.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/memory/MemoryPool.java index 188833e329ebc..a9ab6ed5d8120 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/memory/MemoryPool.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/memory/MemoryPool.java @@ -181,7 +181,7 @@ public void registerPlanNodeIdToQueryMemoryMap( * @throws MemoryLeakException throw {@link MemoryLeakException} */ public void deRegisterFragmentInstanceFromQueryMemoryMap( - String queryId, String fragmentInstanceId) { + String queryId, String fragmentInstanceId, boolean forceDeregister) { Map> queryRelatedMemory = queryMemoryReservations.get(queryId); if (queryRelatedMemory != null) { Map fragmentRelatedMemory = queryRelatedMemory.get(fragmentInstanceId); @@ -192,6 +192,13 @@ public void deRegisterFragmentInstanceFromQueryMemoryMap( hasPotentialMemoryLeak = fragmentRelatedMemory.values().stream().anyMatch(value -> value != 0L); } + if (!forceDeregister && hasPotentialMemoryLeak) { + // If hasPotentialMemoryLeak is true, it means that LocalSourceChannel/LocalSourceHandles + // have not been closed. + // We should wait for them to be closed. Make sure this method is called again with + // forceDeregister == true, after all LocalSourceChannel/LocalSourceHandles are closed. + return; + } synchronized (queryMemoryReservations) { queryRelatedMemory.remove(fragmentInstanceId); if (queryRelatedMemory.isEmpty()) { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/SchemaFetchScanOperator.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/SchemaFetchScanOperator.java index c6236d018a981..f4b40c69b79e4 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/SchemaFetchScanOperator.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/SchemaFetchScanOperator.java @@ -22,6 +22,7 @@ import org.apache.iotdb.commons.exception.MetadataException; import org.apache.iotdb.commons.exception.runtime.SchemaExecutionException; import org.apache.iotdb.commons.path.PathPatternTree; +import org.apache.iotdb.commons.schema.SchemaConstant; import org.apache.iotdb.db.queryengine.common.schematree.ClusterSchemaTree; import org.apache.iotdb.db.queryengine.execution.MemoryEstimationHelper; import org.apache.iotdb.db.queryengine.execution.operator.OperatorContext; @@ -40,6 +41,7 @@ import java.io.ByteArrayOutputStream; import java.io.IOException; +import java.util.Collections; import java.util.Map; import java.util.NoSuchElementException; import java.util.Optional; @@ -52,8 +54,13 @@ public class SchemaFetchScanOperator implements SourceOperator { private final ISchemaRegion schemaRegion; private final boolean withTags; + private final boolean withAttributes; private final boolean withTemplate; + private final boolean withAliasForce; + + private final boolean fetchDevice; private boolean isFinished = false; + private final PathPatternTree authorityScope; private static final int DEFAULT_MAX_TSBLOCK_SIZE_IN_BYTES = TSFileDescriptor.getInstance().getConfig().getMaxTsBlockSizeInBytes(); @@ -61,21 +68,78 @@ public class SchemaFetchScanOperator implements SourceOperator { private static final long INSTANCE_SIZE = RamUsageEstimator.shallowSizeOfInstance(SchemaFetchScanOperator.class); - public SchemaFetchScanOperator( + public static SchemaFetchScanOperator ofSeries( PlanNodeId planNodeId, OperatorContext context, PathPatternTree patternTree, Map templateMap, ISchemaRegion schemaRegion, boolean withTags, - boolean withTemplate) { + boolean withAttributes, + boolean withTemplate, + boolean withAliasForce) { + return new SchemaFetchScanOperator( + planNodeId, + context, + patternTree, + templateMap, + schemaRegion, + withTags, + withAttributes, + withTemplate, + withAliasForce); + } + + public static SchemaFetchScanOperator ofDevice( + PlanNodeId planNodeId, + OperatorContext context, + PathPatternTree patternTree, + PathPatternTree authorityScope, + ISchemaRegion schemaRegion) { + return new SchemaFetchScanOperator( + planNodeId, context, patternTree, authorityScope, schemaRegion); + } + + private SchemaFetchScanOperator( + PlanNodeId planNodeId, + OperatorContext context, + PathPatternTree patternTree, + Map templateMap, + ISchemaRegion schemaRegion, + boolean withTags, + boolean withAttributes, + boolean withTemplate, + boolean withAliasForce) { this.sourceId = planNodeId; this.operatorContext = context; this.patternTree = patternTree; this.schemaRegion = schemaRegion; this.templateMap = templateMap; this.withTags = withTags; + this.withAttributes = withAttributes; this.withTemplate = withTemplate; + this.withAliasForce = withAliasForce; + this.fetchDevice = false; + this.authorityScope = SchemaConstant.ALL_MATCH_SCOPE; + } + + private SchemaFetchScanOperator( + PlanNodeId planNodeId, + OperatorContext context, + PathPatternTree patternTree, + PathPatternTree authorityScope, + ISchemaRegion schemaRegion) { + this.sourceId = planNodeId; + this.operatorContext = context; + this.patternTree = patternTree; + this.schemaRegion = schemaRegion; + this.templateMap = Collections.emptyMap(); + this.withTags = false; + this.withAttributes = false; + this.withTemplate = false; + this.withAliasForce = false; + this.fetchDevice = true; + this.authorityScope = authorityScope; } @Override @@ -118,7 +182,10 @@ public PlanNodeId getSourceId() { private TsBlock fetchSchema() throws MetadataException { ClusterSchemaTree schemaTree = - schemaRegion.fetchSchema(patternTree, templateMap, withTags, withTemplate); + fetchDevice + ? schemaRegion.fetchDeviceSchema(patternTree, authorityScope) + : schemaRegion.fetchSeriesSchema( + patternTree, templateMap, withTags, withAttributes, withTemplate, withAliasForce); ByteArrayOutputStream outputStream = new ByteArrayOutputStream(); try { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/DeviceSchemaSource.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/DeviceSchemaSource.java index 37a9d63865c70..d1f6029f04c58 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/DeviceSchemaSource.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/schema/source/DeviceSchemaSource.java @@ -109,7 +109,7 @@ public void transformToTsBlockColumns( builder .getColumnBuilder(2) .writeBinary(new Binary(String.valueOf(device.isAligned()), TSFileConfig.STRING_CHARSET)); - if (templateId != -1) { + if (templateId != SchemaConstant.NON_TEMPLATE) { builder .getColumnBuilder(3) .writeBinary( @@ -125,7 +125,7 @@ public void transformToTsBlockColumns( builder .getColumnBuilder(1) .writeBinary(new Binary(String.valueOf(device.isAligned()), TSFileConfig.STRING_CHARSET)); - if (templateId != -1) { + if (templateId != SchemaConstant.NON_TEMPLATE) { builder .getColumnBuilder(2) .writeBinary( diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/AbstractSeriesScanOperator.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/AbstractSeriesScanOperator.java new file mode 100644 index 0000000000000..d8c07d75cafe3 --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/AbstractSeriesScanOperator.java @@ -0,0 +1,148 @@ +/* + * 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.iotdb.db.queryengine.execution.operator.source; + +import org.apache.tsfile.enums.TSDataType; +import org.apache.tsfile.read.common.block.TsBlock; + +import java.io.IOException; +import java.util.List; +import java.util.concurrent.TimeUnit; + +public abstract class AbstractSeriesScanOperator extends AbstractDataSourceOperator { + + private boolean finished = false; + + @Override + public TsBlock next() throws Exception { + if (retainedTsBlock != null) { + return getResultFromRetainedTsBlock(); + } + // we don't get any data in current batch time slice, just return null + if (resultTsBlockBuilder.isEmpty()) { + return null; + } + resultTsBlock = resultTsBlockBuilder.build(); + resultTsBlockBuilder.reset(); + return checkTsBlockSizeAndGetResult(); + } + + @Override + public boolean isFinished() throws Exception { + return finished; + } + + @SuppressWarnings("squid:S112") + @Override + public boolean hasNext() throws Exception { + if (retainedTsBlock != null) { + return true; + } + try { + + // start stopwatch + long maxRuntime = operatorContext.getMaxRunTime().roundTo(TimeUnit.NANOSECONDS); + long start = System.nanoTime(); + + boolean noMoreData = false; + + // here use do-while to promise doing this at least once + do { + /* + * 1. consume page data firstly + * 2. consume chunk data secondly + * 3. consume next file finally + */ + if (!readPageData() && !readChunkData() && !readFileData()) { + noMoreData = true; + break; + } + + } while (System.nanoTime() - start < maxRuntime + && !resultTsBlockBuilder.isFull() + && retainedTsBlock == null); + + finished = (resultTsBlockBuilder.isEmpty() && retainedTsBlock == null && noMoreData); + + return !finished; + } catch (IOException e) { + throw new RuntimeException("Error happened while scanning the file", e); + } + } + + private boolean readFileData() throws IOException { + while (seriesScanUtil.hasNextFile()) { + if (readChunkData()) { + return true; + } + } + return false; + } + + private boolean readChunkData() throws IOException { + while (seriesScanUtil.hasNextChunk()) { + if (readPageData()) { + return true; + } + } + return false; + } + + private boolean readPageData() throws IOException { + if (seriesScanUtil.hasNextPage()) { + TsBlock tsBlock = seriesScanUtil.nextPage(); + if (!isEmpty(tsBlock)) { + appendToBuilder(tsBlock); + } + return true; + } + return false; + } + + private boolean isEmpty(TsBlock tsBlock) { + return tsBlock == null || tsBlock.isEmpty(); + } + + private void appendToBuilder(TsBlock tsBlock) { + int size = tsBlock.getPositionCount(); + if (resultTsBlockBuilder.isEmpty() && size >= resultTsBlockBuilder.getMaxTsBlockLineNumber()) { + retainedTsBlock = tsBlock; + return; + } + buildResult(tsBlock); + } + + protected abstract void buildResult(TsBlock tsBlock); + + @Override + protected List getResultDataTypes() { + return seriesScanUtil.getTsDataTypeList(); + } + + @Override + public long calculateMaxReturnSize() { + return maxReturnSize; + } + + @Override + public long calculateRetainedSizeAfterCallingNext() { + return calculateMaxPeekMemoryWithCounter() - calculateMaxReturnSize(); + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/ActiveDeviceRegionScanOperator.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/ActiveDeviceRegionScanOperator.java index 1f7478a007054..3ceee8c526ae9 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/ActiveDeviceRegionScanOperator.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/ActiveDeviceRegionScanOperator.java @@ -19,11 +19,16 @@ package org.apache.iotdb.db.queryengine.execution.operator.source; +import org.apache.iotdb.commons.conf.IoTDBConstant; import org.apache.iotdb.commons.exception.IllegalPathException; +import org.apache.iotdb.commons.schema.SchemaConstant; +import org.apache.iotdb.db.queryengine.common.DeviceContext; import org.apache.iotdb.db.queryengine.common.header.ColumnHeader; import org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant; import org.apache.iotdb.db.queryengine.execution.operator.OperatorContext; +import org.apache.iotdb.db.queryengine.plan.analyze.cache.schema.DataNodeTTLCache; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId; +import org.apache.iotdb.db.schemaengine.template.ClusterTemplateManager; import org.apache.tsfile.block.column.ColumnBuilder; import org.apache.tsfile.common.conf.TSFileConfig; @@ -41,7 +46,7 @@ public class ActiveDeviceRegionScanOperator extends AbstractRegionScanDataSourceOperator { // The devices which need to be checked. - private final Map deviceToAlignedMap; + private final Map deviceContextMap; private static final long INSTANCE_SIZE = RamUsageEstimator.shallowSizeOfInstance(ActiveDeviceRegionScanOperator.class) @@ -50,24 +55,24 @@ public class ActiveDeviceRegionScanOperator extends AbstractRegionScanDataSource public ActiveDeviceRegionScanOperator( OperatorContext operatorContext, PlanNodeId sourceId, - Map deviceToAlignedMap, + Map deviceContextMap, Filter timeFilter, boolean outputCount) { this.outputCount = outputCount; this.sourceId = sourceId; this.operatorContext = operatorContext; - this.deviceToAlignedMap = deviceToAlignedMap; + this.deviceContextMap = deviceContextMap; this.regionScanUtil = new RegionScanForActiveDeviceUtil(timeFilter); } @Override protected boolean getNextTsFileHandle() throws IOException, IllegalPathException { - return ((RegionScanForActiveDeviceUtil) regionScanUtil).nextTsFileHandle(deviceToAlignedMap); + return ((RegionScanForActiveDeviceUtil) regionScanUtil).nextTsFileHandle(deviceContextMap); } @Override protected boolean isAllDataChecked() { - return deviceToAlignedMap.isEmpty(); + return deviceContextMap.isEmpty(); } @Override @@ -77,20 +82,38 @@ protected void updateActiveData() { if (this.outputCount) { count += activeDevices.size(); - activeDevices.forEach(deviceToAlignedMap.keySet()::remove); + activeDevices.forEach(deviceContextMap.keySet()::remove); } else { TimeColumnBuilder timeColumnBuilder = resultTsBlockBuilder.getTimeColumnBuilder(); ColumnBuilder[] columnBuilders = resultTsBlockBuilder.getValueColumnBuilders(); for (IDeviceID deviceID : activeDevices) { + DeviceContext deviceContext = deviceContextMap.get(deviceID); + int templateId = deviceContext.getTemplateId(); + // TODO: use IDeviceID interface to get ttl + long ttl = DataNodeTTLCache.getInstance().getTTL(deviceID); + + // TODO: make it more readable, like "30 days" or "10 hours" + String ttlStr = ttl == Long.MAX_VALUE ? IoTDBConstant.TTL_INFINITE : String.valueOf(ttl); + timeColumnBuilder.writeLong(-1); columnBuilders[0].writeBinary(new Binary(deviceID.toString(), TSFileConfig.STRING_CHARSET)); columnBuilders[1].writeBinary( new Binary( - String.valueOf(deviceToAlignedMap.get(deviceID)), TSFileConfig.STRING_CHARSET)); - columnBuilders[2].appendNull(); - columnBuilders[3].appendNull(); + String.valueOf(deviceContextMap.get(deviceID).isAligned()), + TSFileConfig.STRING_CHARSET)); + + if (templateId != SchemaConstant.NON_TEMPLATE) { + columnBuilders[2].writeBinary( + new Binary( + String.valueOf( + ClusterTemplateManager.getInstance().getTemplate(templateId).getName()), + TSFileConfig.STRING_CHARSET)); + } else { + columnBuilders[2].appendNull(); + } + columnBuilders[3].writeBinary(new Binary(ttlStr, TSFileConfig.STRING_CHARSET)); resultTsBlockBuilder.declarePosition(); - deviceToAlignedMap.remove(deviceID); + deviceContextMap.remove(deviceID); } } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/ActiveTimeSeriesRegionScanOperator.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/ActiveTimeSeriesRegionScanOperator.java index c1f4cc951d004..e2219bfc94d1d 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/ActiveTimeSeriesRegionScanOperator.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/ActiveTimeSeriesRegionScanOperator.java @@ -19,7 +19,7 @@ package org.apache.iotdb.db.queryengine.execution.operator.source; -import org.apache.iotdb.db.queryengine.common.TimeseriesSchemaInfo; +import org.apache.iotdb.db.queryengine.common.TimeseriesContext; import org.apache.iotdb.db.queryengine.common.header.ColumnHeader; import org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant; import org.apache.iotdb.db.queryengine.execution.operator.OperatorContext; @@ -41,7 +41,7 @@ public class ActiveTimeSeriesRegionScanOperator extends AbstractRegionScanDataSourceOperator { // Timeseries which need to be checked. - private final Map> timeSeriesToSchemasInfo; + private final Map> timeSeriesToSchemasInfo; private static final Binary VIEW_TYPE = new Binary("BASE".getBytes()); private final Binary dataBaseName; private static final long INSTANCE_SIZE = @@ -52,7 +52,7 @@ public class ActiveTimeSeriesRegionScanOperator extends AbstractRegionScanDataSo public ActiveTimeSeriesRegionScanOperator( OperatorContext operatorContext, PlanNodeId sourceId, - Map> timeSeriesToSchemasInfo, + Map> timeSeriesToSchemasInfo, Filter timeFilter, boolean isOutputCount) { this.outputCount = isOutputCount; @@ -110,9 +110,9 @@ protected void updateActiveData() { IDeviceID deviceID = entry.getKey(); String deviceStr = deviceID.toString(); List timeSeriesList = entry.getValue(); - Map timeSeriesInfo = timeSeriesToSchemasInfo.get(deviceID); + Map timeSeriesInfo = timeSeriesToSchemasInfo.get(deviceID); for (String timeSeries : timeSeriesList) { - TimeseriesSchemaInfo schemaInfo = timeSeriesInfo.get(timeSeries); + TimeseriesContext schemaInfo = timeSeriesInfo.get(timeSeries); timeColumnBuilder.writeLong(-1); columnBuilders[0].writeBinary( new Binary(contactDeviceAndMeasurement(deviceStr, timeSeries))); @@ -123,7 +123,7 @@ protected void updateActiveData() { checkAndAppend(schemaInfo.getEncoding(), columnBuilders[4]); // Encoding checkAndAppend(schemaInfo.getCompression(), columnBuilders[5]); // Compression checkAndAppend(schemaInfo.getTags(), columnBuilders[6]); // Tags - columnBuilders[7].appendNull(); // Attributes + checkAndAppend(schemaInfo.getAttributes(), columnBuilders[7]); // Attributes checkAndAppend(schemaInfo.getDeadband(), columnBuilders[8]); // Description checkAndAppend(schemaInfo.getDeadbandParameters(), columnBuilders[9]); // DeadbandParameters columnBuilders[10].writeBinary(VIEW_TYPE); // ViewType @@ -134,7 +134,7 @@ protected void updateActiveData() { } private void removeTimeseriesListFromDevice(IDeviceID deviceID, List timeSeriesList) { - Map timeSeriesInfo = timeSeriesToSchemasInfo.get(deviceID); + Map timeSeriesInfo = timeSeriesToSchemasInfo.get(deviceID); for (String timeSeries : timeSeriesList) { timeSeriesInfo.remove(timeSeries); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/AlignedSeriesScanOperator.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/AlignedSeriesScanOperator.java index b220f616b8dab..63605457aec21 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/AlignedSeriesScanOperator.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/AlignedSeriesScanOperator.java @@ -38,16 +38,13 @@ import org.apache.tsfile.read.common.block.column.TimeColumnBuilder; import org.apache.tsfile.utils.RamUsageEstimator; -import java.io.IOException; import java.util.List; -import java.util.concurrent.TimeUnit; -public class AlignedSeriesScanOperator extends AbstractDataSourceOperator { +public class AlignedSeriesScanOperator extends AbstractSeriesScanOperator { private static final long INSTANCE_SIZE = RamUsageEstimator.shallowSizeOfInstance(AlignedSeriesScanOperator.class); private final int valueColumnCount; - private boolean finished = false; private int maxTsBlockLineNum = -1; public AlignedSeriesScanOperator( @@ -78,56 +75,6 @@ public AlignedSeriesScanOperator( this.maxTsBlockLineNum = maxTsBlockLineNum; } - @Override - public TsBlock next() throws Exception { - if (retainedTsBlock != null) { - return getResultFromRetainedTsBlock(); - } - resultTsBlock = resultTsBlockBuilder.build(); - resultTsBlockBuilder.reset(); - return checkTsBlockSizeAndGetResult(); - } - - @SuppressWarnings("squid:S112") - @Override - public boolean hasNext() throws Exception { - if (retainedTsBlock != null) { - return true; - } - try { - - // start stopwatch - long maxRuntime = operatorContext.getMaxRunTime().roundTo(TimeUnit.NANOSECONDS); - long start = System.nanoTime(); - - // here use do-while to promise doing this at least once - do { - /* - * 1. consume page data firstly - * 2. consume chunk data secondly - * 3. consume next file finally - */ - if (!readPageData() && !readChunkData() && !readFileData()) { - break; - } - - } while (System.nanoTime() - start < maxRuntime - && !resultTsBlockBuilder.isFull() - && retainedTsBlock == null); - - finished = (resultTsBlockBuilder.isEmpty() && retainedTsBlock == null); - - return !finished; - } catch (IOException e) { - throw new RuntimeException("Error happened while scanning the file", e); - } - } - - @Override - public boolean isFinished() throws Exception { - return finished; - } - @Override public long calculateMaxPeekMemory() { return Math.max( @@ -138,51 +85,8 @@ public long calculateMaxPeekMemory() { } @Override - public long calculateMaxReturnSize() { - return maxReturnSize; - } - - @Override - public long calculateRetainedSizeAfterCallingNext() { - return calculateMaxPeekMemoryWithCounter() - calculateMaxReturnSize(); - } - - private boolean readFileData() throws IOException { - while (seriesScanUtil.hasNextFile()) { - if (readChunkData()) { - return true; - } - } - return false; - } - - private boolean readChunkData() throws IOException { - while (seriesScanUtil.hasNextChunk()) { - if (readPageData()) { - return true; - } - } - return false; - } - - private boolean readPageData() throws IOException { - while (seriesScanUtil.hasNextPage()) { - TsBlock tsBlock = seriesScanUtil.nextPage(); - if (!isEmpty(tsBlock)) { - appendToBuilder(tsBlock); - return true; - } - } - return false; - } - - private void appendToBuilder(TsBlock tsBlock) { + protected void buildResult(TsBlock tsBlock) { int size = tsBlock.getPositionCount(); - if (resultTsBlockBuilder.isEmpty() - && tsBlock.getPositionCount() >= resultTsBlockBuilder.getMaxTsBlockLineNumber()) { - retainedTsBlock = tsBlock; - return; - } TimeColumnBuilder timeColumnBuilder = resultTsBlockBuilder.getTimeColumnBuilder(); TimeColumn timeColumn = tsBlock.getTimeColumn(); for (int i = 0; i < size; i++) { @@ -214,16 +118,6 @@ private void appendOneColumn(int columnIndex, TsBlock tsBlock, int size) { } } - private boolean isEmpty(TsBlock tsBlock) { - return tsBlock == null || tsBlock.isEmpty(); - } - - @Override - protected List getResultDataTypes() { - // time + all value columns - return seriesScanUtil.getTsDataTypeList(); - } - @Override public void initQueryDataSource(IQueryDataSource dataSource) { seriesScanUtil.initQueryDataSource((QueryDataSource) dataSource); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/RegionScanForActiveDeviceUtil.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/RegionScanForActiveDeviceUtil.java index 8ca5e165363f9..11faa55f3941c 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/RegionScanForActiveDeviceUtil.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/RegionScanForActiveDeviceUtil.java @@ -20,6 +20,7 @@ package org.apache.iotdb.db.queryengine.execution.operator.source; import org.apache.iotdb.commons.exception.IllegalPathException; +import org.apache.iotdb.db.queryengine.common.DeviceContext; import org.apache.iotdb.db.storageengine.dataregion.read.filescan.model.AbstractChunkOffset; import org.apache.iotdb.db.storageengine.dataregion.read.filescan.model.AbstractDeviceChunkMetaData; import org.apache.iotdb.db.storageengine.dataregion.read.filescan.model.DeviceStartEndTime; @@ -60,7 +61,7 @@ public boolean isCurrentTsFileFinished() { return deviceSetForCurrentTsFile.isEmpty(); } - public boolean nextTsFileHandle(Map targetDevices) + public boolean nextTsFileHandle(Map targetDevices) throws IOException, IllegalPathException { if (!queryDataSource.hasNext()) { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/RegionScanForActiveTimeSeriesUtil.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/RegionScanForActiveTimeSeriesUtil.java index ff6711232bbac..61c7028ab211a 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/RegionScanForActiveTimeSeriesUtil.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/RegionScanForActiveTimeSeriesUtil.java @@ -20,7 +20,7 @@ package org.apache.iotdb.db.queryengine.execution.operator.source; import org.apache.iotdb.commons.exception.IllegalPathException; -import org.apache.iotdb.db.queryengine.common.TimeseriesSchemaInfo; +import org.apache.iotdb.db.queryengine.common.TimeseriesContext; import org.apache.iotdb.db.storageengine.dataregion.read.filescan.model.AbstractChunkOffset; import org.apache.iotdb.db.storageengine.dataregion.read.filescan.model.AbstractDeviceChunkMetaData; import org.apache.iotdb.db.storageengine.dataregion.read.filescan.model.DeviceStartEndTime; @@ -55,8 +55,8 @@ public RegionScanForActiveTimeSeriesUtil(Filter timeFilter) { this.activeTimeSeries = new HashMap<>(); } - public boolean nextTsFileHandle( - Map> targetTimeseries) throws IOException { + public boolean nextTsFileHandle(Map> targetTimeseries) + throws IOException { if (!queryDataSource.hasNext()) { // There is no more TsFileHandles to be scanned. return false; diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/SeriesScanOperator.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/SeriesScanOperator.java index dc5f122b1c07f..51e3ad7c580b6 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/SeriesScanOperator.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/source/SeriesScanOperator.java @@ -29,22 +29,15 @@ import org.apache.tsfile.block.column.Column; import org.apache.tsfile.block.column.ColumnBuilder; import org.apache.tsfile.common.conf.TSFileDescriptor; -import org.apache.tsfile.enums.TSDataType; import org.apache.tsfile.read.common.block.TsBlock; import org.apache.tsfile.read.common.block.column.TimeColumn; import org.apache.tsfile.read.common.block.column.TimeColumnBuilder; import org.apache.tsfile.utils.RamUsageEstimator; -import java.io.IOException; -import java.util.List; -import java.util.concurrent.TimeUnit; - -public class SeriesScanOperator extends AbstractDataSourceOperator { +public class SeriesScanOperator extends AbstractSeriesScanOperator { private static final long INSTANCE_SIZE = RamUsageEstimator.shallowSizeOfInstance(SeriesScanOperator.class); - private boolean finished = false; - public SeriesScanOperator( OperatorContext context, PlanNodeId sourceId, @@ -59,53 +52,6 @@ public SeriesScanOperator( Math.min(maxReturnSize, TSFileDescriptor.getInstance().getConfig().getPageSizeInByte()); } - @Override - public TsBlock next() throws Exception { - if (retainedTsBlock != null) { - return getResultFromRetainedTsBlock(); - } - resultTsBlock = resultTsBlockBuilder.build(); - resultTsBlockBuilder.reset(); - return checkTsBlockSizeAndGetResult(); - } - - @SuppressWarnings("squid:S112") - @Override - public boolean hasNext() throws Exception { - if (retainedTsBlock != null) { - return true; - } - try { - - // start stopwatch - long maxRuntime = operatorContext.getMaxRunTime().roundTo(TimeUnit.NANOSECONDS); - long start = System.nanoTime(); - - // here use do-while to promise doing this at least once - do { - /* - * 1. consume page data firstly - * 2. consume chunk data secondly - * 3. consume next file finally - */ - if (!readPageData() && !readChunkData() && !readFileData()) { - break; - } - } while (System.nanoTime() - start < maxRuntime && !resultTsBlockBuilder.isFull()); - - finished = resultTsBlockBuilder.isEmpty(); - - return !finished; - } catch (IOException e) { - throw new RuntimeException("Error happened while scanning the file", e); - } - } - - @Override - public boolean isFinished() throws Exception { - return finished; - } - @Override public long calculateMaxPeekMemory() { return Math.max( @@ -113,53 +59,15 @@ public long calculateMaxPeekMemory() { } @Override - public long calculateMaxReturnSize() { - return maxReturnSize; - } - - @Override - public long calculateRetainedSizeAfterCallingNext() { - return calculateMaxPeekMemoryWithCounter() - calculateMaxReturnSize(); - } - - private boolean readFileData() throws IOException { - while (seriesScanUtil.hasNextFile()) { - if (readChunkData()) { - return true; - } - } - return false; - } - - private boolean readChunkData() throws IOException { - while (seriesScanUtil.hasNextChunk()) { - if (readPageData()) { - return true; - } - } - return false; - } - - private boolean readPageData() throws IOException { - while (seriesScanUtil.hasNextPage()) { - TsBlock tsBlock = seriesScanUtil.nextPage(); - - if (!isEmpty(tsBlock)) { - appendToBuilder(tsBlock); - return true; - } - } - return false; - } - - private void appendToBuilder(TsBlock tsBlock) { + protected void buildResult(TsBlock tsBlock) { + int size = tsBlock.getPositionCount(); TimeColumnBuilder timeColumnBuilder = resultTsBlockBuilder.getTimeColumnBuilder(); TimeColumn timeColumn = tsBlock.getTimeColumn(); ColumnBuilder columnBuilder = resultTsBlockBuilder.getColumnBuilder(0); Column column = tsBlock.getColumn(0); if (column.mayHaveNull()) { - for (int i = 0, size = tsBlock.getPositionCount(); i < size; i++) { + for (int i = 0; i < size; i++) { timeColumnBuilder.writeLong(timeColumn.getLong(i)); if (column.isNull(i)) { columnBuilder.appendNull(); @@ -169,7 +77,7 @@ private void appendToBuilder(TsBlock tsBlock) { resultTsBlockBuilder.declarePosition(); } } else { - for (int i = 0, size = tsBlock.getPositionCount(); i < size; i++) { + for (int i = 0; i < size; i++) { timeColumnBuilder.writeLong(timeColumn.getLong(i)); columnBuilder.write(column, i); resultTsBlockBuilder.declarePosition(); @@ -177,15 +85,6 @@ private void appendToBuilder(TsBlock tsBlock) { } } - private boolean isEmpty(TsBlock tsBlock) { - return tsBlock == null || tsBlock.isEmpty(); - } - - @Override - protected List getResultDataTypes() { - return seriesScanUtil.getTsDataTypeList(); - } - @Override public long ramBytesUsed() { return INSTANCE_SIZE diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/load/LoadTsFileAnalyzeSchemaMemoryBlock.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/load/LoadTsFileAnalyzeSchemaMemoryBlock.java index 17aa4150bcd31..17b52745f236c 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/load/LoadTsFileAnalyzeSchemaMemoryBlock.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/load/LoadTsFileAnalyzeSchemaMemoryBlock.java @@ -22,7 +22,7 @@ import org.apache.iotdb.commons.service.metric.MetricService; import org.apache.iotdb.commons.service.metric.enums.Metric; import org.apache.iotdb.commons.service.metric.enums.Tag; -import org.apache.iotdb.db.queryengine.metric.LoadTsFileMemMetricSet; +import org.apache.iotdb.db.queryengine.metric.load.LoadTsFileMemMetricSet; import org.apache.iotdb.metrics.utils.MetricLevel; import org.slf4j.Logger; diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/load/LoadTsFileMemoryManager.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/load/LoadTsFileMemoryManager.java index eff5f790bdb3a..f034a4627b901 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/load/LoadTsFileMemoryManager.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/load/LoadTsFileMemoryManager.java @@ -64,12 +64,12 @@ private synchronized void forceAllocatedFromQuery(long sizeInBytes) throw new LoadRuntimeOutOfMemoryException( String.format( - "forceAllocate: failed to allocate memory from query engine after %d retries, " - + "total query memory %s, available memory for load %s bytes, " - + "used memory size %d bytes, requested memory size %d bytes", + "forceAllocate: failed to allocate memory from query engine after %s retries, " + + "total query memory %s bytes, current available memory for load %s bytes, " + + "current load used memory size %s bytes, load requested memory size %s bytes", MEMORY_ALLOCATE_MAX_RETRIES, - IoTDBDescriptor.getInstance().getConfig().getAllocateMemoryForOperators(), - LocalExecutionPlanner.getInstance().getFreeMemoryForOperators(), + QUERY_ENGINE_MEMORY_MANAGER.getAllocateMemoryForOperators(), + QUERY_ENGINE_MEMORY_MANAGER.getFreeMemoryForLoadTsFile(), usedMemorySizeInBytes.get(), sizeInBytes)); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/metric/load/LoadTsFileCostMetricsSet.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/metric/load/LoadTsFileCostMetricsSet.java new file mode 100644 index 0000000000000..b0ce2ca69a45d --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/metric/load/LoadTsFileCostMetricsSet.java @@ -0,0 +1,131 @@ +/* + * 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.iotdb.db.queryengine.metric.load; + +import org.apache.iotdb.commons.service.metric.enums.Metric; +import org.apache.iotdb.commons.service.metric.enums.Tag; +import org.apache.iotdb.db.conf.IoTDBDescriptor; +import org.apache.iotdb.metrics.AbstractMetricService; +import org.apache.iotdb.metrics.impl.DoNothingMetricManager; +import org.apache.iotdb.metrics.metricsets.IMetricSet; +import org.apache.iotdb.metrics.type.Rate; +import org.apache.iotdb.metrics.type.Timer; +import org.apache.iotdb.metrics.utils.MetricLevel; +import org.apache.iotdb.metrics.utils.MetricType; + +import java.util.Arrays; + +public class LoadTsFileCostMetricsSet implements IMetricSet { + + private static final LoadTsFileCostMetricsSet INSTANCE = new LoadTsFileCostMetricsSet(); + + public static final String ANALYSIS = "analysis"; + public static final String FIRST_PHASE = "first_phase"; + public static final String SECOND_PHASE = "second_phase"; + public static final String LOAD_LOCALLY = "load_locally"; + + private LoadTsFileCostMetricsSet() { + // empty constructor + } + + private Timer analyzerTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + private Timer firstPhaseTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + private Timer secondPhaseTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + private Timer loadLocallyTimer = DoNothingMetricManager.DO_NOTHING_TIMER; + + private Rate diskIORate = DoNothingMetricManager.DO_NOTHING_RATE; + + public void recordPhaseTimeCost(String stage, long costTimeInNanos) { + switch (stage) { + case ANALYSIS: + analyzerTimer.updateNanos(costTimeInNanos); + break; + case FIRST_PHASE: + firstPhaseTimer.updateNanos(costTimeInNanos); + break; + case SECOND_PHASE: + secondPhaseTimer.updateNanos(costTimeInNanos); + break; + case LOAD_LOCALLY: + loadLocallyTimer.updateNanos(costTimeInNanos); + break; + default: + throw new UnsupportedOperationException("Unsupported stage: " + stage); + } + } + + public void recordDiskIO(long bytes) { + diskIORate.mark(bytes); + } + + @Override + public void bindTo(AbstractMetricService metricService) { + analyzerTimer = + metricService.getOrCreateTimer( + Metric.LOAD_TIME_COST.toString(), MetricLevel.IMPORTANT, Tag.NAME.toString(), ANALYSIS); + firstPhaseTimer = + metricService.getOrCreateTimer( + Metric.LOAD_TIME_COST.toString(), + MetricLevel.IMPORTANT, + Tag.NAME.toString(), + FIRST_PHASE); + secondPhaseTimer = + metricService.getOrCreateTimer( + Metric.LOAD_TIME_COST.toString(), + MetricLevel.IMPORTANT, + Tag.NAME.toString(), + SECOND_PHASE); + loadLocallyTimer = + metricService.getOrCreateTimer( + Metric.LOAD_TIME_COST.toString(), + MetricLevel.IMPORTANT, + Tag.NAME.toString(), + LOAD_LOCALLY); + + diskIORate = + metricService.getOrCreateRate( + Metric.LOAD_DISK_IO.toString(), + MetricLevel.IMPORTANT, + Tag.NAME.toString(), + "DataNode " + IoTDBDescriptor.getInstance().getConfig().getDataNodeId()); + } + + @Override + public void unbindFrom(AbstractMetricService metricService) { + Arrays.asList(ANALYSIS, FIRST_PHASE, SECOND_PHASE, LOAD_LOCALLY) + .forEach( + stage -> + metricService.remove( + MetricType.TIMER, + Metric.LOAD_TIME_COST.toString(), + Tag.NAME.toString(), + stage)); + + metricService.remove( + MetricType.RATE, + Metric.LOAD_DISK_IO.toString(), + Tag.NAME.toString(), + String.valueOf(IoTDBDescriptor.getInstance().getConfig().getDataNodeId())); + } + + public static LoadTsFileCostMetricsSet getInstance() { + return LoadTsFileCostMetricsSet.INSTANCE; + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/metric/LoadTsFileMemMetricSet.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/metric/load/LoadTsFileMemMetricSet.java similarity index 98% rename from iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/metric/LoadTsFileMemMetricSet.java rename to iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/metric/load/LoadTsFileMemMetricSet.java index 7e822421302a7..c195381585490 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/metric/LoadTsFileMemMetricSet.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/metric/load/LoadTsFileMemMetricSet.java @@ -17,7 +17,7 @@ * under the License. */ -package org.apache.iotdb.db.queryengine.metric; +package org.apache.iotdb.db.queryengine.metric.load; import org.apache.iotdb.commons.service.metric.enums.Metric; import org.apache.iotdb.commons.service.metric.enums.Tag; diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/Analysis.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/Analysis.java index 7c8bf7c861c29..beb5cf6989f3b 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/Analysis.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/Analysis.java @@ -28,9 +28,10 @@ import org.apache.iotdb.commons.partition.DataPartition; import org.apache.iotdb.commons.partition.SchemaPartition; import org.apache.iotdb.commons.path.PartialPath; +import org.apache.iotdb.db.queryengine.common.DeviceContext; import org.apache.iotdb.db.queryengine.common.MPPQueryContext; import org.apache.iotdb.db.queryengine.common.NodeRef; -import org.apache.iotdb.db.queryengine.common.TimeseriesSchemaInfo; +import org.apache.iotdb.db.queryengine.common.TimeseriesContext; import org.apache.iotdb.db.queryengine.common.header.DatasetHeader; import org.apache.iotdb.db.queryengine.common.schematree.ISchemaTree; import org.apache.iotdb.db.queryengine.plan.execution.memory.StatementMemorySource; @@ -304,23 +305,23 @@ aggregation results last_value(temperature) and last_value(status), whereas buck private List measurementSchemaList; // Used for regionScan - private Map devicePathToAlignedStatus; - private Map>> deviceToTimeseriesSchemas; + private Map devicePathToContextMap; + private Map>> deviceToTimeseriesSchemas; - public void setDevicePathToAlignedStatus(Map devicePathToAlignedStatus) { - this.devicePathToAlignedStatus = devicePathToAlignedStatus; + public void setDevicePathToContextMap(Map devicePathToContextMap) { + this.devicePathToContextMap = devicePathToContextMap; } - public Map getDevicePathToAlignedStatus() { - return devicePathToAlignedStatus; + public Map getDevicePathToContextMap() { + return devicePathToContextMap; } public void setDeviceToTimeseriesSchemas( - Map>> deviceToTimeseriesSchemas) { + Map>> deviceToTimeseriesSchemas) { this.deviceToTimeseriesSchemas = deviceToTimeseriesSchemas; } - public Map>> + public Map>> getDeviceToTimeseriesSchemas() { return deviceToTimeseriesSchemas; } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java index dcf7f36021b4f..b94d0d75e0ae1 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/AnalyzeVisitor.java @@ -49,8 +49,9 @@ import org.apache.iotdb.db.protocol.client.ConfigNodeClient; import org.apache.iotdb.db.protocol.client.ConfigNodeClientManager; import org.apache.iotdb.db.protocol.client.ConfigNodeInfo; +import org.apache.iotdb.db.queryengine.common.DeviceContext; import org.apache.iotdb.db.queryengine.common.MPPQueryContext; -import org.apache.iotdb.db.queryengine.common.TimeseriesSchemaInfo; +import org.apache.iotdb.db.queryengine.common.TimeseriesContext; import org.apache.iotdb.db.queryengine.common.header.ColumnHeader; import org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant; import org.apache.iotdb.db.queryengine.common.header.DatasetHeader; @@ -60,6 +61,7 @@ import org.apache.iotdb.db.queryengine.common.schematree.ISchemaTree; import org.apache.iotdb.db.queryengine.execution.operator.window.WindowType; import org.apache.iotdb.db.queryengine.metric.QueryPlanCostMetricSet; +import org.apache.iotdb.db.queryengine.metric.load.LoadTsFileCostMetricsSet; import org.apache.iotdb.db.queryengine.plan.analyze.lock.DataNodeSchemaLockManager; import org.apache.iotdb.db.queryengine.plan.analyze.lock.SchemaLockType; import org.apache.iotdb.db.queryengine.plan.analyze.schema.ISchemaFetcher; @@ -107,10 +109,11 @@ import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertTabletStatement; import org.apache.iotdb.db.queryengine.plan.statement.crud.LoadTsFileStatement; import org.apache.iotdb.db.queryengine.plan.statement.crud.QueryStatement; +import org.apache.iotdb.db.queryengine.plan.statement.internal.DeviceSchemaFetchStatement; import org.apache.iotdb.db.queryengine.plan.statement.internal.InternalBatchActivateTemplateStatement; import org.apache.iotdb.db.queryengine.plan.statement.internal.InternalCreateMultiTimeSeriesStatement; import org.apache.iotdb.db.queryengine.plan.statement.internal.InternalCreateTimeSeriesStatement; -import org.apache.iotdb.db.queryengine.plan.statement.internal.SchemaFetchStatement; +import org.apache.iotdb.db.queryengine.plan.statement.internal.SeriesSchemaFetchStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.AlterTimeSeriesStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.CountDatabaseStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.CountDevicesStatement; @@ -156,6 +159,7 @@ import org.apache.tsfile.read.common.TimeRange; import org.apache.tsfile.read.filter.basic.Filter; import org.apache.tsfile.utils.Pair; +import org.apache.tsfile.utils.RamUsageEstimator; import org.apache.tsfile.write.schema.IMeasurementSchema; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -187,6 +191,7 @@ import static org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant.ENDTIME; import static org.apache.iotdb.db.queryengine.metric.QueryPlanCostMetricSet.PARTITION_FETCHER; import static org.apache.iotdb.db.queryengine.metric.QueryPlanCostMetricSet.SCHEMA_FETCHER; +import static org.apache.iotdb.db.queryengine.metric.load.LoadTsFileCostMetricsSet.ANALYSIS; import static org.apache.iotdb.db.queryengine.plan.analyze.ExpressionAnalyzer.bindSchemaForExpression; import static org.apache.iotdb.db.queryengine.plan.analyze.ExpressionAnalyzer.concatDeviceAndBindSchemaForExpression; import static org.apache.iotdb.db.queryengine.plan.analyze.ExpressionAnalyzer.getMeasurementExpression; @@ -2005,7 +2010,7 @@ private DataPartition fetchDataPartitionByDevices( long startTime = System.nanoTime(); try { Pair, Pair> res = - getTimePartitionSlotList(context.getGlobalTimeFilter()); + getTimePartitionSlotList(context.getGlobalTimeFilter(), context); // there is no satisfied time range if (res.left.isEmpty() && Boolean.FALSE.equals(res.right.left)) { return new DataPartition( @@ -2042,7 +2047,7 @@ private DataPartition fetchDataPartitionByDevices( */ @SuppressWarnings("squid:S3776") // Suppress high Cognitive Complexity warning public static Pair, Pair> getTimePartitionSlotList( - Filter timeFilter) { + Filter timeFilter, MPPQueryContext context) { if (timeFilter == null) { // (-oo, +oo) return new Pair<>(Collections.emptyList(), new Pair<>(true, true)); @@ -2083,6 +2088,9 @@ public static Pair, Pair> getTimePart } List result = new ArrayList<>(); + TimeRange currentTimeRange = timeRangeList.get(index); + reserveMemoryForTimePartitionSlot( + currentTimeRange.getMax(), currentTimeRange.getMin(), context); while (index < size) { long curLeft = timeRangeList.get(index).getMin(); long curRight = timeRangeList.get(index).getMax(); @@ -2098,6 +2106,11 @@ public static Pair, Pair> getTimePart endTime = endTime + TimePartitionUtils.getTimePartitionInterval(); } else { index++; + if (index < size) { + currentTimeRange = timeRangeList.get(index); + reserveMemoryForTimePartitionSlot( + currentTimeRange.getMax(), currentTimeRange.getMin(), context); + } } } result.add(timePartitionSlot); @@ -2113,6 +2126,16 @@ public static Pair, Pair> getTimePart return new Pair<>(result, new Pair<>(needLeftAll, needRightAll)); } + private static void reserveMemoryForTimePartitionSlot( + long maxTime, long minTime, MPPQueryContext context) { + if (maxTime == Long.MAX_VALUE || minTime == Long.MIN_VALUE) { + return; + } + long size = TimePartitionUtils.getEstimateTimePartitionSize(minTime, maxTime); + context.reserveMemoryForFrontEnd( + RamUsageEstimator.shallowSizeOfInstance(TTimePartitionSlot.class) * size); + } + private void analyzeInto( Analysis analysis, QueryStatement queryStatement, @@ -2856,12 +2879,24 @@ private InsertBaseStatement removeLogicalView( @Override public Analysis visitLoadFile(LoadTsFileStatement loadTsFileStatement, MPPQueryContext context) { - LoadTsfileAnalyzer loadTsfileAnalyzer = - new LoadTsfileAnalyzer(loadTsFileStatement, context, partitionFetcher, schemaFetcher); - try { + long startTime = System.nanoTime(); + try (final LoadTsfileAnalyzer loadTsfileAnalyzer = + new LoadTsfileAnalyzer(loadTsFileStatement, context, partitionFetcher, schemaFetcher)) { return loadTsfileAnalyzer.analyzeFileByFile(); + } catch (final Exception e) { + final String exceptionMessage = + String.format( + "Failed to execute load tsfile statement %s. Detail: %s", + loadTsFileStatement, + e.getMessage() == null ? e.getClass().getName() : e.getMessage()); + logger.warn(exceptionMessage, e); + final Analysis analysis = new Analysis(); + analysis.setFinishQueryAfterAnalyze(true); + analysis.setFailStatus(RpcUtils.getStatus(TSStatusCode.LOAD_FILE_ERROR, exceptionMessage)); + return analysis; } finally { - loadTsfileAnalyzer.close(); + LoadTsFileCostMetricsSet.getInstance() + .recordPhaseTimeCost(ANALYSIS, System.nanoTime() - startTime); } } @@ -2887,20 +2922,27 @@ private boolean analyzeTimeseriesRegionScan( WhereCondition timeCondition, PathPatternTree patternTree, Analysis analysis, - MPPQueryContext context) + MPPQueryContext context, + PathPatternTree authorityScope) throws IllegalPathException { analyzeGlobalTimeConditionInShowMetaData(timeCondition, analysis); context.generateGlobalTimeFilter(analysis); + patternTree.constructTree(); + ISchemaTree schemaTree = + schemaFetcher.fetchRawSchemaInMeasurementLevel(patternTree, authorityScope, context); - ISchemaTree schemaTree = schemaFetcher.fetchSchemaWithTags(patternTree, false, context); if (schemaTree.isEmpty()) { analysis.setFinishQueryAfterAnalyze(true); return false; } removeLogicViewMeasurement(schemaTree); - - Map>> deviceToTimeseriesSchemaInfo = + Map>> deviceToTimeseriesContext = new HashMap<>(); + /** + * Since we fetch raw time series schema without template(The template sequence will be treated + * as a normal node, not a device+templateId. This means that all nodes are what we need.). We + * can use ALL_MATCH_PATTERN to get result. + */ List deviceSchemaInfoList = schemaTree.getMatchedDevices(ALL_MATCH_PATTERN); Set deviceSet = new HashSet<>(); for (DeviceSchemaInfo deviceSchemaInfo : deviceSchemaInfoList) { @@ -2910,33 +2952,34 @@ private boolean analyzeTimeseriesRegionScan( if (isAligned) { List measurementList = new ArrayList<>(); List schemaList = new ArrayList<>(); - List timeseriesSchemaInfoList = new ArrayList<>(); + List timeseriesContextList = new ArrayList<>(); for (IMeasurementSchemaInfo measurementSchemaInfo : deviceSchemaInfo.getMeasurementSchemaInfoList()) { schemaList.add(measurementSchemaInfo.getSchema()); measurementList.add(measurementSchemaInfo.getName()); - timeseriesSchemaInfoList.add(new TimeseriesSchemaInfo(measurementSchemaInfo)); + timeseriesContextList.add(new TimeseriesContext(measurementSchemaInfo)); } AlignedPath alignedPath = new AlignedPath(devicePath.getNodes(), measurementList, schemaList); - deviceToTimeseriesSchemaInfo + deviceToTimeseriesContext .computeIfAbsent(devicePath, k -> new HashMap<>()) - .put(alignedPath, timeseriesSchemaInfoList); + .put(alignedPath, timeseriesContextList); } else { for (IMeasurementSchemaInfo measurementSchemaInfo : deviceSchemaInfo.getMeasurementSchemaInfoList()) { MeasurementPath measurementPath = new MeasurementPath( devicePath.concatNode(measurementSchemaInfo.getName()).getNodes()); - deviceToTimeseriesSchemaInfo + deviceToTimeseriesContext .computeIfAbsent(devicePath, k -> new HashMap<>()) .put( measurementPath, - Collections.singletonList(new TimeseriesSchemaInfo(measurementSchemaInfo))); + Collections.singletonList(new TimeseriesContext(measurementSchemaInfo))); } } } - analysis.setDeviceToTimeseriesSchemas(deviceToTimeseriesSchemaInfo); + + analysis.setDeviceToTimeseriesSchemas(deviceToTimeseriesContext); // fetch Data partition DataPartition dataPartition = fetchDataPartitionByDevices(deviceSet, schemaTree, context); analysis.setDataPartitionInfo(dataPartition); @@ -2957,7 +3000,11 @@ public Analysis visitShowTimeSeries( // If there is time condition in SHOW TIMESERIES, we need to scan the raw data boolean hasSchema = analyzeTimeseriesRegionScan( - showTimeSeriesStatement.getTimeCondition(), patternTree, analysis, context); + showTimeSeriesStatement.getTimeCondition(), + patternTree, + analysis, + context, + showTimeSeriesStatement.getAuthorityScope()); if (!hasSchema) { analysis.setRespDatasetHeader(DatasetHeaderFactory.getShowTimeSeriesHeader()); return analysis; @@ -3041,29 +3088,31 @@ private void removeLogicViewMeasurement(ISchemaTree schemaTree) { private void analyzeDeviceRegionScan( WhereCondition timeCondition, - PathPatternTree patternTree, + PartialPath pattern, + PathPatternTree authorityScope, Analysis analysis, MPPQueryContext context) { // If there is time condition in SHOW DEVICES, we need to scan the raw data analyzeGlobalTimeConditionInShowMetaData(timeCondition, analysis); context.generateGlobalTimeFilter(analysis); - - ISchemaTree schemaTree = schemaFetcher.fetchSchemaInDeviceLevel(patternTree, context); + PathPatternTree patternTree = new PathPatternTree(); + patternTree.appendPathPattern(pattern); + ISchemaTree schemaTree = + schemaFetcher.fetchRawSchemaInDeviceLevel(patternTree, authorityScope, context); if (schemaTree.isEmpty()) { analysis.setFinishQueryAfterAnalyze(true); return; } // fetch Data partition - List deviceSchemaInfoList = schemaTree.getMatchedDevices(ALL_MATCH_PATTERN); - Map devicePathsToAlignedStatus = new HashMap<>(); - for (DeviceSchemaInfo deviceSchema : deviceSchemaInfoList) { - devicePathsToAlignedStatus.put(deviceSchema.getDevicePath(), deviceSchema.isAligned()); - } - analysis.setDevicePathToAlignedStatus(devicePathsToAlignedStatus); + + Map devicePathsToInfoMap = + schemaTree.getMatchedDevices(pattern).stream() + .collect(Collectors.toMap(DeviceSchemaInfo::getDevicePath, DeviceContext::new)); + analysis.setDevicePathToContextMap(devicePathsToInfoMap); DataPartition dataPartition = fetchDataPartitionByDevices( - devicePathsToAlignedStatus.keySet().stream() + devicePathsToInfoMap.keySet().stream() .map(PartialPath::getIDeviceIDAsFullDevice) .collect(Collectors.toSet()), schemaTree, @@ -3077,14 +3126,17 @@ public Analysis visitShowDevices( Analysis analysis = new Analysis(); analysis.setStatement(showDevicesStatement); - PathPatternTree patternTree = new PathPatternTree(); - patternTree.appendPathPattern( - showDevicesStatement.getPathPattern().concatNode(IoTDBConstant.ONE_LEVEL_PATH_WILDCARD)); - if (showDevicesStatement.hasTimeCondition()) { analyzeDeviceRegionScan( - showDevicesStatement.getTimeCondition(), patternTree, analysis, context); + showDevicesStatement.getTimeCondition(), + showDevicesStatement.getPathPattern(), + showDevicesStatement.getAuthorityScope(), + analysis, + context); } else { + PathPatternTree patternTree = new PathPatternTree(); + patternTree.appendPathPattern( + showDevicesStatement.getPathPattern().concatNode(IoTDBConstant.ONE_LEVEL_PATH_WILDCARD)); SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree); analysis.setSchemaPartitionInfo(schemaPartitionInfo); } @@ -3118,13 +3170,34 @@ public Analysis visitCountStorageGroup( } @Override - public Analysis visitSchemaFetch( - SchemaFetchStatement schemaFetchStatement, MPPQueryContext context) { + public Analysis visitSeriesSchemaFetch( + SeriesSchemaFetchStatement seriesSchemaFetchStatement, MPPQueryContext context) { Analysis analysis = new Analysis(); - analysis.setStatement(schemaFetchStatement); + analysis.setStatement(seriesSchemaFetchStatement); SchemaPartition schemaPartition = - partitionFetcher.getSchemaPartition(schemaFetchStatement.getPatternTree()); + partitionFetcher.getSchemaPartition(seriesSchemaFetchStatement.getPatternTree()); + analysis.setSchemaPartitionInfo(schemaPartition); + + if (schemaPartition.isEmpty()) { + analysis.setFinishQueryAfterAnalyze(true); + } + + return analysis; + } + + @Override + public Analysis visitDeviceSchemaFetch( + DeviceSchemaFetchStatement deviceSchemaFetchStatement, MPPQueryContext context) { + Analysis analysis = new Analysis(); + analysis.setStatement(deviceSchemaFetchStatement); + + PathPatternTree patternTree = new PathPatternTree(); + for (PartialPath path : deviceSchemaFetchStatement.getPaths()) { + patternTree.appendPathPattern(path); + } + patternTree.constructTree(); + SchemaPartition schemaPartition = partitionFetcher.getSchemaPartition(patternTree); analysis.setSchemaPartitionInfo(schemaPartition); if (schemaPartition.isEmpty()) { @@ -3140,13 +3213,17 @@ public Analysis visitCountDevices( Analysis analysis = new Analysis(); analysis.setStatement(countDevicesStatement); - PathPatternTree patternTree = new PathPatternTree(); - patternTree.appendPathPattern( - countDevicesStatement.getPathPattern().concatNode(IoTDBConstant.ONE_LEVEL_PATH_WILDCARD)); if (countDevicesStatement.hasTimeCondition()) { analyzeDeviceRegionScan( - countDevicesStatement.getTimeCondition(), patternTree, analysis, context); + countDevicesStatement.getTimeCondition(), + countDevicesStatement.getPathPattern(), + countDevicesStatement.getAuthorityScope(), + analysis, + context); } else { + PathPatternTree patternTree = new PathPatternTree(); + patternTree.appendPathPattern( + countDevicesStatement.getPathPattern().concatNode(IoTDBConstant.ONE_LEVEL_PATH_WILDCARD)); SchemaPartition schemaPartitionInfo = partitionFetcher.getSchemaPartition(patternTree); analysis.setSchemaPartitionInfo(schemaPartitionInfo); } @@ -3168,7 +3245,11 @@ public Analysis visitCountTimeSeries( try { boolean hasSchema = analyzeTimeseriesRegionScan( - countTimeSeriesStatement.getTimeCondition(), patternTree, analysis, context); + countTimeSeriesStatement.getTimeCondition(), + patternTree, + analysis, + context, + countTimeSeriesStatement.getAuthorityScope()); if (!hasSchema) { analysis.setRespDatasetHeader(DatasetHeaderFactory.getCountTimeSeriesHeader()); return analysis; diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/LoadTsfileAnalyzer.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/LoadTsfileAnalyzer.java index 0d523238bca50..64f5fcefdc019 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/LoadTsfileAnalyzer.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/LoadTsfileAnalyzer.java @@ -94,7 +94,7 @@ import java.util.Set; import java.util.stream.Collectors; -public class LoadTsfileAnalyzer { +public class LoadTsfileAnalyzer implements AutoCloseable { private static final Logger LOGGER = LoggerFactory.getLogger(LoadTsfileAnalyzer.class); @@ -139,9 +139,10 @@ public class LoadTsfileAnalyzer { public Analysis analyzeFileByFile() { context.setQueryType(QueryType.WRITE); + Analysis analysis = new Analysis(); + // check if the system is read only if (CommonDescriptor.getInstance().getConfig().isReadOnly()) { - Analysis analysis = new Analysis(); analysis.setFinishQueryAfterAnalyze(true); analysis.setFailStatus( RpcUtils.getStatus(TSStatusCode.SYSTEM_READ_ONLY, LoadReadOnlyException.MESSAGE)); @@ -171,11 +172,6 @@ public Analysis analyzeFileByFile() { "Load - Analysis Stage: {}/{} tsfiles have been analyzed, progress: {}%", i + 1, tsfileNum, String.format("%.3f", (i + 1) * 100.00 / tsfileNum)); } - } catch (IllegalArgumentException e) { - LOGGER.warn( - "Parse file {} to resource error, this TsFile maybe empty.", tsFile.getPath(), e); - throw new SemanticException( - String.format("TsFile %s is empty or incomplete.", tsFile.getPath())); } catch (AuthException e) { return createFailAnalysisForAuthException(e); } catch (BufferUnderflowException e) { @@ -186,10 +182,14 @@ public Analysis analyzeFileByFile() { "The file %s is not a valid tsfile. Please check the input file.", tsFile.getPath())); } catch (Exception e) { - LOGGER.warn("Parse file {} to resource error.", tsFile.getPath(), e); - throw new SemanticException( + final String exceptionMessage = String.format( - "Parse file %s to resource error, because %s", tsFile.getPath(), e.getMessage())); + "The file %s is not a valid tsfile. Please check the input file. Detail: %s", + tsFile.getPath(), e.getMessage() == null ? e.getClass().getName() : e.getMessage()); + LOGGER.warn(exceptionMessage, e); + analysis.setFinishQueryAfterAnalyze(true); + analysis.setFailStatus(RpcUtils.getStatus(TSStatusCode.LOAD_FILE_ERROR, exceptionMessage)); + return analysis; } } @@ -197,16 +197,31 @@ public Analysis analyzeFileByFile() { schemaAutoCreatorAndVerifier.flush(); } catch (AuthException e) { return createFailAnalysisForAuthException(e); + } catch (Exception e) { + final String exceptionMessage = + String.format( + "Auto create or verify schema error when executing statement %s. Detail: %s.", + loadTsFileStatement, + e.getMessage() == null ? e.getClass().getName() : e.getMessage()); + LOGGER.warn(exceptionMessage, e); + analysis.setFinishQueryAfterAnalyze(true); + analysis.setFailStatus( + RpcUtils.getStatus( + TSStatusCode.LOAD_FILE_ERROR, + String.format( + "Auto create or verify schema error when executing statement %s.", + loadTsFileStatement))); + return analysis; } LOGGER.info("Load - Analysis Stage: all tsfiles have been analyzed."); // data partition will be queried in the scheduler - final Analysis analysis = new Analysis(); analysis.setStatement(loadTsFileStatement); return analysis; } + @Override public void close() { schemaAutoCreatorAndVerifier.close(); } @@ -360,8 +375,7 @@ public void autoCreateAndVerify( * This can only be invoked after all timeseries in the current tsfile have been processed. * Otherwise, the isAligned status may be wrong. */ - public void flushAndClearDeviceIsAlignedCacheIfNecessary() - throws SemanticException, AuthException { + public void flushAndClearDeviceIsAlignedCacheIfNecessary() throws SemanticException { // avoid OOM when loading a tsfile with too many timeseries // or loading too many tsfiles at the same time schemaCache.clearDeviceIsAlignedCacheIfNecessary(); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/TemplatedAggregationAnalyze.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/TemplatedAggregationAnalyze.java index 3f61759081284..79f8ba0a8c11a 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/TemplatedAggregationAnalyze.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/TemplatedAggregationAnalyze.java @@ -56,6 +56,7 @@ import static org.apache.iotdb.db.queryengine.plan.analyze.TemplatedAnalyze.analyzeFrom; import static org.apache.iotdb.db.queryengine.plan.optimization.LimitOffsetPushDown.canPushDownLimitOffsetInGroupByTimeForDevice; import static org.apache.iotdb.db.queryengine.plan.optimization.LimitOffsetPushDown.pushDownLimitOffsetInGroupByTimeForDevice; +import static org.apache.iotdb.db.utils.constant.SqlConstant.COUNT_TIME; /** Methods in this class are used for aggregation, templated with align by device situation. */ public class TemplatedAggregationAnalyze { @@ -120,7 +121,7 @@ static boolean canBuildAggregationPlanUseTemplate( context.generateGlobalTimeFilter(analysis); // fetch partition information - analyzeDataPartition(analysis, schemaTree, partitionFetcher, context.getGlobalTimeFilter()); + analyzeDataPartition(analysis, schemaTree, partitionFetcher, context); return true; } @@ -143,24 +144,57 @@ private static boolean analyzeSelect( Set aggregationExpressions = new LinkedHashSet<>(); for (ResultColumn resultColumn : queryStatement.getSelectComponent().getResultColumns()) { - if (paginationController.hasCurOffset()) { - paginationController.consumeOffset(); - } else if (paginationController.hasCurLimit()) { - Expression selectExpression = resultColumn.getExpression(); + Expression selectExpression = resultColumn.getExpression(); + + if (selectExpression instanceof FunctionExpression + && COUNT_TIME.equalsIgnoreCase( + ((FunctionExpression) selectExpression).getFunctionName())) { outputExpressions.add(new Pair<>(selectExpression, resultColumn.getAlias())); selectExpressions.add(selectExpression); aggregationExpressions.add(selectExpression); + + analysis.getExpressionTypes().put(NodeRef.of(selectExpression), TSDataType.INT64); + ((FunctionExpression) selectExpression) + .setExpressions(Collections.singletonList(new TimestampOperand())); + continue; + } + + List subExpressions; + if (selectExpression.getOutputSymbol().contains("*")) { + // when exist wildcard, only support agg(*) and count_time(*) if (selectExpression instanceof FunctionExpression - && "count_time" - .equalsIgnoreCase(((FunctionExpression) selectExpression).getFunctionName())) { - analysis.getExpressionTypes().put(NodeRef.of(selectExpression), TSDataType.INT64); - ((FunctionExpression) selectExpression) - .setExpressions(Collections.singletonList(new TimestampOperand())); + && selectExpression.getExpressions().size() == 1 + && "*".equalsIgnoreCase(selectExpression.getExpressions().get(0).getOutputSymbol())) { + subExpressions = new ArrayList<>(); + FunctionExpression functionExpression = (FunctionExpression) selectExpression; + for (String measurement : template.getSchemaMap().keySet()) { + FunctionExpression subFunctionExpression = + new FunctionExpression( + functionExpression.getFunctionName(), + functionExpression.getFunctionAttributes(), + Collections.singletonList( + new TimeSeriesOperand(new PartialPath(new String[] {measurement})))); + subFunctionExpression.setFunctionType(functionExpression.getFunctionType()); + subExpressions.add(subFunctionExpression); + } } else { - analyzeExpressionType(analysis, selectExpression); + return false; } } else { - break; + subExpressions = Collections.singletonList(selectExpression); + } + + for (Expression expression : subExpressions) { + if (paginationController.hasCurOffset()) { + paginationController.consumeOffset(); + } else if (paginationController.hasCurLimit()) { + outputExpressions.add(new Pair<>(expression, resultColumn.getAlias())); + selectExpressions.add(expression); + aggregationExpressions.add(expression); + analyzeExpressionType(analysis, expression); + } else { + break; + } } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/TemplatedAnalyze.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/TemplatedAnalyze.java index fe1df64361943..a64f54ae53614 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/TemplatedAnalyze.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/TemplatedAnalyze.java @@ -41,7 +41,6 @@ import org.apache.tsfile.enums.TSDataType; import org.apache.tsfile.file.metadata.IDeviceID; -import org.apache.tsfile.read.filter.basic.Filter; import org.apache.tsfile.utils.Pair; import org.apache.tsfile.write.schema.IMeasurementSchema; import org.slf4j.Logger; @@ -205,7 +204,7 @@ public static boolean canBuildPlanUseTemplate( context.generateGlobalTimeFilter(analysis); // fetch partition information - analyzeDataPartition(analysis, schemaTree, partitionFetcher, context.getGlobalTimeFilter()); + analyzeDataPartition(analysis, schemaTree, partitionFetcher, context); return true; } @@ -377,26 +376,26 @@ static void analyzeDataPartition( Analysis analysis, ISchemaTree schemaTree, IPartitionFetcher partitionFetcher, - Filter globalTimeFilter) { + MPPQueryContext context) { // TemplatedDevice has no views, so there is no need to use outputDeviceToQueriedDevicesMap Set deviceSet = analysis.getDeviceList().stream() .map(PartialPath::getIDeviceIDAsFullDevice) .collect(Collectors.toSet()); DataPartition dataPartition = - fetchDataPartitionByDevices(deviceSet, schemaTree, globalTimeFilter, partitionFetcher); + fetchDataPartitionByDevices(deviceSet, schemaTree, context, partitionFetcher); analysis.setDataPartitionInfo(dataPartition); } private static DataPartition fetchDataPartitionByDevices( Set deviceSet, ISchemaTree schemaTree, - Filter globalTimeFilter, + MPPQueryContext context, IPartitionFetcher partitionFetcher) { long startTime = System.nanoTime(); try { Pair, Pair> res = - getTimePartitionSlotList(globalTimeFilter); + getTimePartitionSlotList(context.getGlobalTimeFilter(), context); // there is no satisfied time range if (res.left.isEmpty() && Boolean.FALSE.equals(res.right.left)) { return new DataPartition( diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/DataNodeTTLCache.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/DataNodeTTLCache.java index 5dea6b9209dd2..1f69fd94917a7 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/DataNodeTTLCache.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/DataNodeTTLCache.java @@ -25,7 +25,6 @@ import org.apache.tsfile.file.metadata.IDeviceID; -import java.util.Map; import java.util.concurrent.locks.ReentrantReadWriteLock; import static org.apache.tsfile.common.constant.TsFileConstant.PATH_SEPARATER_NO_REGEX; @@ -75,15 +74,6 @@ public void unsetTTL(String[] path) { } } - public long getTTL(String path) throws IllegalPathException { - lock.readLock().lock(); - try { - return ttlCache.getClosestTTL(PathUtils.splitPathToDetachedNodes(path)); - } finally { - lock.readLock().unlock(); - } - } - public long getTTL(IDeviceID deviceID) { lock.readLock().lock(); try { @@ -103,16 +93,6 @@ public long getTTL(String[] path) { } } - /** Get all ttl map under path node. */ - public Map getTTLUnderOneNode(String path) throws IllegalPathException { - lock.readLock().lock(); - try { - return ttlCache.getAllTTLUnderOneNode(PathUtils.splitPathToDetachedNodes(path)); - } finally { - lock.readLock().unlock(); - } - } - /** Get ttl of one specific path node. If this node does not set ttl, then return -1. */ public long getNodeTTL(String path) throws IllegalPathException { lock.readLock().lock(); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/DeviceUsingTemplateSchemaCache.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/DeviceUsingTemplateSchemaCache.java index 3529c26049e0e..c5ae2bba59b20 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/DeviceUsingTemplateSchemaCache.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/DeviceUsingTemplateSchemaCache.java @@ -168,6 +168,11 @@ public Map getTagMap() { return null; } + @Override + public Map getAttributeMap() { + return null; + } + @Override public String getAlias() { return null; diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/SchemaCacheEntry.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/SchemaCacheEntry.java index d3d99c2548be8..bf6d5c31a86c0 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/SchemaCacheEntry.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/SchemaCacheEntry.java @@ -70,6 +70,11 @@ public Map getTagMap() { return tagMap; } + @Override + public Map getAttributeMap() { + return null; + } + public TSDataType getTsDataType() { return iMeasurementSchema.getType(); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/TimeSeriesSchemaCache.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/TimeSeriesSchemaCache.java index c912a7c221f7b..1909e1558e7b3 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/TimeSeriesSchemaCache.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/cache/schema/TimeSeriesSchemaCache.java @@ -111,6 +111,7 @@ public void computeValue(int index, SchemaCacheEntry value) { value.getIMeasurementSchema(), value.getTagMap(), null, + null, value.isAligned()); storageGroupSet.add(value.getStorageGroup()); } @@ -130,6 +131,7 @@ public ClusterSchemaTree get(PartialPath fullPath) { schemaCacheEntry.getIMeasurementSchema(), schemaCacheEntry.getTagMap(), null, + null, schemaCacheEntry.isAligned()); schemaTree.setDatabases(Collections.singleton(schemaCacheEntry.getStorageGroup())); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/schema/AutoCreateSchemaExecutor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/schema/AutoCreateSchemaExecutor.java index 630ca1f8cce28..3d2cae267fc23 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/schema/AutoCreateSchemaExecutor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/schema/AutoCreateSchemaExecutor.java @@ -493,6 +493,7 @@ private void internalCreateTimeSeries( measurements.get(i), tsDataTypes.get(i), encodings.get(i), compressors.get(i)), null, null, + null, isAligned); } } @@ -620,6 +621,7 @@ private void internalCreateTimeSeries( measurementGroup.getCompressors().get(i)), null, null, + null, entry.getValue().left); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/schema/ClusterSchemaFetchExecutor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/schema/ClusterSchemaFetchExecutor.java index 84b93546cdcf8..64fe751c37785 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/schema/ClusterSchemaFetchExecutor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/schema/ClusterSchemaFetchExecutor.java @@ -34,7 +34,8 @@ import org.apache.iotdb.db.queryengine.plan.analyze.QueryType; import org.apache.iotdb.db.queryengine.plan.execution.ExecutionResult; import org.apache.iotdb.db.queryengine.plan.statement.Statement; -import org.apache.iotdb.db.queryengine.plan.statement.internal.SchemaFetchStatement; +import org.apache.iotdb.db.queryengine.plan.statement.internal.DeviceSchemaFetchStatement; +import org.apache.iotdb.db.queryengine.plan.statement.internal.SeriesSchemaFetchStatement; import org.apache.iotdb.db.schemaengine.template.ITemplateManager; import org.apache.iotdb.db.schemaengine.template.Template; import org.apache.iotdb.db.utils.SetThreadName; @@ -107,7 +108,9 @@ ClusterSchemaTree fetchSchemaOfFuzzyMatch( templateMap.putAll(templateManager.checkAllRelatedTemplate(pattern)); } return executeSchemaFetchQuery( - new SchemaFetchStatement(patternTree, templateMap, withTags, withTemplate), context); + new SeriesSchemaFetchStatement( + patternTree, templateMap, withTags, false, withTemplate, false), + context); } /** @@ -125,8 +128,13 @@ ClusterSchemaTree fetchSchemaOfPreciseMatchOrPreciseDeviceUsingTemplate( MPPQueryContext context) { ClusterSchemaTree schemaTree = executeSchemaFetchQuery( - new SchemaFetchStatement( - rawPatternTree, analyzeTemplate(fullPathList), false, withTemplate), + new SeriesSchemaFetchStatement( + rawPatternTree, + analyzeTemplate(fullPathList), + false, + withTemplate, + withTemplate, + withTemplate), context); if (!schemaTree.isEmpty()) { schemaCacheUpdater.accept(schemaTree); @@ -134,6 +142,23 @@ rawPatternTree, analyzeTemplate(fullPathList), false, withTemplate), return schemaTree; } + ClusterSchemaTree fetchDeviceLevelRawSchema( + PathPatternTree patternTree, PathPatternTree authorityScope, MPPQueryContext context) { + return executeSchemaFetchQuery( + new DeviceSchemaFetchStatement(patternTree, authorityScope), context); + } + + ClusterSchemaTree fetchMeasurementLevelRawSchema( + PathPatternTree patternTree, MPPQueryContext context) { + Map templateMap = new HashMap<>(); + List pathPatternList = patternTree.getAllPathPatterns(); + for (PartialPath pattern : pathPatternList) { + templateMap.putAll(templateManager.checkAllRelatedTemplate(pattern)); + } + return executeSchemaFetchQuery( + new SeriesSchemaFetchStatement(patternTree, templateMap, true, true, false, true), context); + } + ClusterSchemaTree fetchSchemaOfOneDevice( PartialPath devicePath, String[] measurements, @@ -189,8 +214,13 @@ private ClusterSchemaTree fetchSchemaAndCacheResult( PathPatternTree patternTree, MPPQueryContext context) { ClusterSchemaTree schemaTree = executeSchemaFetchQuery( - new SchemaFetchStatement( - patternTree, analyzeTemplate(patternTree.getAllPathPatterns()), false, true), + new SeriesSchemaFetchStatement( + patternTree, + analyzeTemplate(patternTree.getAllPathPatterns()), + false, + false, + true, + false), context); if (!schemaTree.isEmpty()) { schemaCacheUpdater.accept(schemaTree); @@ -207,11 +237,11 @@ private Map analyzeTemplate(List pathPatternList } private ClusterSchemaTree executeSchemaFetchQuery( - SchemaFetchStatement schemaFetchStatement, MPPQueryContext context) { + Statement fetchStatement, MPPQueryContext context) { long queryId = SessionManager.getInstance().requestQueryId(); Throwable t = null; try { - ExecutionResult executionResult = executionStatement(queryId, schemaFetchStatement, context); + ExecutionResult executionResult = executionStatement(queryId, fetchStatement, context); if (executionResult.status.getCode() != TSStatusCode.SUCCESS_STATUS.getStatusCode()) { throw new RuntimeException( String.format( diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/schema/ClusterSchemaFetcher.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/schema/ClusterSchemaFetcher.java index 1df4a385c6834..9b40c2c9b9e72 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/schema/ClusterSchemaFetcher.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/schema/ClusterSchemaFetcher.java @@ -21,6 +21,7 @@ import org.apache.iotdb.commons.path.PartialPath; import org.apache.iotdb.commons.path.PathPatternTree; +import org.apache.iotdb.commons.path.PathPatternTreeUtils; import org.apache.iotdb.db.conf.IoTDBConfig; import org.apache.iotdb.db.conf.IoTDBDescriptor; import org.apache.iotdb.db.queryengine.common.MPPQueryContext; @@ -155,6 +156,21 @@ public ClusterSchemaTree fetchSchema( } } + @Override + public ISchemaTree fetchRawSchemaInDeviceLevel( + PathPatternTree patternTree, PathPatternTree authorityScope, MPPQueryContext context) { + authorityScope.constructTree(); + return clusterSchemaFetchExecutor.fetchDeviceLevelRawSchema( + patternTree, authorityScope, context); + } + + @Override + public ISchemaTree fetchRawSchemaInMeasurementLevel( + PathPatternTree patternTree, PathPatternTree authorityScope, MPPQueryContext context) { + return clusterSchemaFetchExecutor.fetchMeasurementLevelRawSchema( + PathPatternTreeUtils.intersectWithFullPathPrefixTree(patternTree, authorityScope), context); + } + @Override public ClusterSchemaTree fetchSchemaWithTags( PathPatternTree patternTree, boolean withTemplate, MPPQueryContext context) { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/schema/ISchemaFetcher.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/schema/ISchemaFetcher.java index a51f8af0ab139..56a7670ad9d9d 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/schema/ISchemaFetcher.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/analyze/schema/ISchemaFetcher.java @@ -39,29 +39,32 @@ public interface ISchemaFetcher { /** - * Fetch all the schema of existing timeseries matched by the given patternTree + * Fetch all the schema of existing timeseries matched by the given patternTree. The result schema + * tree may contain extra measurement nodes if withTemplate is true. It recommends to use pattern + * to filter the result schema tree. * * @param patternTree used for matching the timeseries + * @param withTemplate whether to include the template in the schema * @return the matched timeseries schema organized as tree structure logically */ ISchemaTree fetchSchema( PathPatternTree patternTree, boolean withTemplate, MPPQueryContext context); /** - * TODO need to be implemented in schema engine + * Fetch all the schema by the given patternTree in device level * - *

Fetch all the schema by the given patternTree in device level + * @return schemaTree without measurement nodes + */ + ISchemaTree fetchRawSchemaInDeviceLevel( + PathPatternTree patternTree, PathPatternTree authorityScope, MPPQueryContext context); + + /** + * Fetch all the schema by the given patternTree in device level * * @return schemaTree without measurement nodes */ - default ISchemaTree fetchSchemaInDeviceLevel( - PathPatternTree patternTree, MPPQueryContext context) { - ISchemaTree schemaTree = fetchSchema(patternTree, false, context); - if (schemaTree.hasLogicalViewMeasurement()) { - schemaTree.removeLogicalView(); - } - return schemaTree; - } + ISchemaTree fetchRawSchemaInMeasurementLevel( + PathPatternTree patternTree, PathPatternTree authorityScope, MPPQueryContext context); /** * Fetch all the schema with tags of existing timeseries matched by the given patternTree diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/QueryExecution.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/QueryExecution.java index 806fc041cdbe9..21c2cc2111e51 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/QueryExecution.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/QueryExecution.java @@ -378,7 +378,8 @@ private void cleanUpResultHandle() { .deRegisterFragmentInstanceFromMemoryPool( fragmentInstanceId.queryId, FragmentInstanceId.createFragmentInstanceIdFromTFragmentInstanceId( - fragmentInstanceId)); + fragmentInstanceId), + true); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/ConfigTaskVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/ConfigTaskVisitor.java index 0786d2fb89386..e9b36c80c9149 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/ConfigTaskVisitor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/ConfigTaskVisitor.java @@ -74,6 +74,7 @@ import org.apache.iotdb.db.queryengine.plan.execution.config.sys.SetSystemStatusTask; import org.apache.iotdb.db.queryengine.plan.execution.config.sys.StartRepairDataTask; import org.apache.iotdb.db.queryengine.plan.execution.config.sys.StopRepairDataTask; +import org.apache.iotdb.db.queryengine.plan.execution.config.sys.TestConnectionTask; import org.apache.iotdb.db.queryengine.plan.execution.config.sys.pipe.AlterPipeTask; import org.apache.iotdb.db.queryengine.plan.execution.config.sys.pipe.CreatePipeTask; import org.apache.iotdb.db.queryengine.plan.execution.config.sys.pipe.DropPipeTask; @@ -154,6 +155,7 @@ import org.apache.iotdb.db.queryengine.plan.statement.sys.SetSystemStatusStatement; import org.apache.iotdb.db.queryengine.plan.statement.sys.StartRepairDataStatement; import org.apache.iotdb.db.queryengine.plan.statement.sys.StopRepairDataStatement; +import org.apache.iotdb.db.queryengine.plan.statement.sys.TestConnectionStatement; import org.apache.iotdb.db.queryengine.plan.statement.sys.quota.SetSpaceQuotaStatement; import org.apache.iotdb.db.queryengine.plan.statement.sys.quota.SetThrottleQuotaStatement; import org.apache.iotdb.db.queryengine.plan.statement.sys.quota.ShowSpaceQuotaStatement; @@ -240,6 +242,12 @@ public IConfigTask visitShowClusterId( return new ShowClusterIdTask(); } + @Override + public IConfigTask visitTestConnection( + TestConnectionStatement testConnectionStatement, MPPQueryContext context) { + return new TestConnectionTask(testConnectionStatement.needDetails()); + } + @Override public IConfigTask visitAuthor(AuthorStatement statement, MPPQueryContext context) { return new AuthorizerTask(statement); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/ClusterConfigTaskExecutor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/ClusterConfigTaskExecutor.java index 6f6f0e55d6a07..ef900fddafe23 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/ClusterConfigTaskExecutor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/ClusterConfigTaskExecutor.java @@ -25,7 +25,9 @@ import org.apache.iotdb.common.rpc.thrift.TSetSpaceQuotaReq; import org.apache.iotdb.common.rpc.thrift.TSetTTLReq; import org.apache.iotdb.common.rpc.thrift.TSetThrottleQuotaReq; +import org.apache.iotdb.common.rpc.thrift.TShowTTLReq; import org.apache.iotdb.common.rpc.thrift.TSpaceQuota; +import org.apache.iotdb.common.rpc.thrift.TTestConnectionResp; import org.apache.iotdb.common.rpc.thrift.TThrottleQuota; import org.apache.iotdb.commons.client.IClientManager; import org.apache.iotdb.commons.client.exception.ClientManagerException; @@ -121,7 +123,7 @@ import org.apache.iotdb.db.exception.metadata.SchemaQuotaExceededException; import org.apache.iotdb.db.exception.metadata.table.TableNotExistsException; import org.apache.iotdb.db.exception.sql.SemanticException; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.protocol.client.ConfigNodeClient; import org.apache.iotdb.db.protocol.client.ConfigNodeClientManager; import org.apache.iotdb.db.protocol.client.ConfigNodeInfo; @@ -160,6 +162,7 @@ import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.template.ShowNodesInSchemaTemplateTask; import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.template.ShowPathSetTemplateTask; import org.apache.iotdb.db.queryengine.plan.execution.config.metadata.template.ShowSchemaTemplateTask; +import org.apache.iotdb.db.queryengine.plan.execution.config.sys.TestConnectionTask; import org.apache.iotdb.db.queryengine.plan.execution.config.sys.pipe.ShowPipeTask; import org.apache.iotdb.db.queryengine.plan.execution.config.sys.quota.ShowSpaceQuotaTask; import org.apache.iotdb.db.queryengine.plan.execution.config.sys.quota.ShowThrottleQuotaTask; @@ -1308,14 +1311,36 @@ public SettableFuture showClusterId() { return future; } + @Override + public SettableFuture testConnection(boolean needDetails) { + SettableFuture future = SettableFuture.create(); + try (ConfigNodeClient client = + CONFIG_NODE_CLIENT_MANAGER.borrowClient(ConfigNodeInfo.CONFIG_REGION_ID)) { + TTestConnectionResp result = client.submitTestConnectionTaskToLeader(); + int configNodeNum = 0, dataNodeNum = 0; + if (!needDetails) { + configNodeNum = client.showConfigNodes().getConfigNodesInfoListSize(); + dataNodeNum = client.showDataNodes().getDataNodesInfoListSize(); + } + TestConnectionTask.buildTSBlock(result, configNodeNum, dataNodeNum, needDetails, future); + } catch (Exception e) { + future.setException(e); + } + return future; + } + @Override public SettableFuture showTTL(ShowTTLStatement showTTLStatement) { SettableFuture future = SettableFuture.create(); Map databaseToTTL = new TreeMap<>(); try (ConfigNodeClient client = CONFIG_NODE_CLIENT_MANAGER.borrowClient(ConfigNodeInfo.CONFIG_REGION_ID)) { - TShowTTLResp resp = client.showAllTTL(); - databaseToTTL.putAll(resp.getPathTTLMap()); + // TODO: send all paths in one RPC + for (PartialPath pathPattern : showTTLStatement.getPaths()) { + TShowTTLReq req = new TShowTTLReq(Arrays.asList(pathPattern.getNodes())); + TShowTTLResp resp = client.showTTL(req); + databaseToTTL.putAll(resp.getPathTTLMap()); + } } catch (ClientManagerException | TException e) { future.setException(e); } @@ -1728,7 +1753,7 @@ public SettableFuture createPipe(CreatePipeStatement createPip // Validate pipe plugin before creation try { - PipeAgent.plugin() + PipeDataNodeAgent.plugin() .validate( createPipeStatement.getPipeName(), createPipeStatement.getExtractorAttributes(), @@ -1786,11 +1811,12 @@ public SettableFuture alterPipe(AlterPipeStatement alterPipeSt try { if (!alterPipeStatement.getProcessorAttributes().isEmpty() && alterPipeStatement.isReplaceAllProcessorAttributes()) { - PipeAgent.plugin().validateProcessor(alterPipeStatement.getProcessorAttributes()); + PipeDataNodeAgent.plugin().validateProcessor(alterPipeStatement.getProcessorAttributes()); } if (!alterPipeStatement.getConnectorAttributes().isEmpty() && alterPipeStatement.isReplaceAllConnectorAttributes()) { - PipeAgent.plugin().validateConnector(pipeName, alterPipeStatement.getConnectorAttributes()); + PipeDataNodeAgent.plugin() + .validateConnector(pipeName, alterPipeStatement.getConnectorAttributes()); } } catch (Exception e) { LOGGER.info("Failed to validate alter pipe statement, because {}", e.getMessage(), e); @@ -1988,8 +2014,10 @@ public SettableFuture createTopic(CreateTopicStatement createT CommonDescriptor.getInstance().getConfig().getTimestampPrecision()), topicAttributes); try { - PipeAgent.plugin().validateExtractor(temporaryTopicMeta.generateExtractorAttributes()); - PipeAgent.plugin().validateProcessor(temporaryTopicMeta.generateProcessorAttributes()); + PipeDataNodeAgent.plugin() + .validateExtractor(temporaryTopicMeta.generateExtractorAttributes()); + PipeDataNodeAgent.plugin() + .validateProcessor(temporaryTopicMeta.generateProcessorAttributes()); } catch (Exception e) { LOGGER.info("Failed to validate create topic statement, because {}", e.getMessage(), e); future.setException( diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/IConfigTaskExecutor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/IConfigTaskExecutor.java index 794ed9ff39399..e43111a7b92c6 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/IConfigTaskExecutor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/executor/IConfigTaskExecutor.java @@ -144,6 +144,8 @@ public interface IConfigTaskExecutor { SettableFuture showClusterId(); + SettableFuture testConnection(boolean needDetails); + SettableFuture showTTL(ShowTTLStatement showTTLStatement); SettableFuture showRegion(ShowRegionStatement showRegionStatement); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/sys/TestConnectionTask.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/sys/TestConnectionTask.java new file mode 100644 index 0000000000000..ce37a7ad44c99 --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/execution/config/sys/TestConnectionTask.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.iotdb.db.queryengine.plan.execution.config.sys; + +import org.apache.iotdb.common.rpc.thrift.TEndPoint; +import org.apache.iotdb.common.rpc.thrift.TSender; +import org.apache.iotdb.common.rpc.thrift.TServiceProvider; +import org.apache.iotdb.common.rpc.thrift.TServiceType; +import org.apache.iotdb.common.rpc.thrift.TTestConnectionResp; +import org.apache.iotdb.common.rpc.thrift.TTestConnectionResult; +import org.apache.iotdb.commons.service.ThriftService; +import org.apache.iotdb.db.queryengine.common.header.ColumnHeader; +import org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant; +import org.apache.iotdb.db.queryengine.common.header.DatasetHeaderFactory; +import org.apache.iotdb.db.queryengine.plan.execution.config.ConfigTaskResult; +import org.apache.iotdb.db.queryengine.plan.execution.config.IConfigTask; +import org.apache.iotdb.db.queryengine.plan.execution.config.executor.IConfigTaskExecutor; +import org.apache.iotdb.rpc.TSStatusCode; + +import com.google.common.util.concurrent.ListenableFuture; +import com.google.common.util.concurrent.SettableFuture; +import org.apache.tsfile.common.conf.TSFileConfig; +import org.apache.tsfile.enums.TSDataType; +import org.apache.tsfile.read.common.block.TsBlockBuilder; +import org.apache.tsfile.utils.Binary; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +public class TestConnectionTask implements IConfigTask { + + private final boolean needDetails; + + public TestConnectionTask(boolean needDetails) { + this.needDetails = needDetails; + } + + @Override + public ListenableFuture execute(IConfigTaskExecutor configTaskExecutor) + throws InterruptedException { + return configTaskExecutor.testConnection(needDetails); + } + + public static void buildTSBlock( + TTestConnectionResp resp, + int configNodeNum, + int dataNodeNum, + boolean needDetails, + SettableFuture future) { + sortTestConnectionResp(resp); + if (!needDetails) { + Map expectedNumMap = + calculateExpectedResultNum(configNodeNum, dataNodeNum); + List newResultList = new ArrayList<>(); + for (int i = 0; i < resp.getResultListSize(); ) { + TTestConnectionResult result = resp.getResultList().get(i); + final int expectNum = expectedNumMap.get(result.getServiceProvider().getServiceType()); + final boolean allSameServiceProviderAllUp = + resp.getResultList().stream() + .skip(i) + .limit(expectNum) + .allMatch( + result1 -> + result.getServiceProvider().equals(result1.serviceProvider) + && result1.isSuccess()); + if (allSameServiceProviderAllUp) { + TTestConnectionResult allUpResult = new TTestConnectionResult(result); + allUpResult.setSender(new TSender()); + newResultList.add(allUpResult); + } else { + newResultList.addAll( + resp.getResultList().stream() + .skip(i) + .limit(expectNum) + .filter(result1 -> !result1.isSuccess()) + .collect(Collectors.toList())); + } + i += expectNum; + } + resp.setResultList(newResultList); + } + List outputDataTypes = + ColumnHeaderConstant.testConnectionColumnHeaders.stream() + .map(ColumnHeader::getColumnType) + .collect(Collectors.toList()); + TsBlockBuilder builder = new TsBlockBuilder(outputDataTypes); + int serviceProviderMaxLen = calculateServiceProviderMaxLen(resp); + int connectionMaxLen = calculateConnectionMaxLen(resp); + for (TTestConnectionResult result : resp.getResultList()) { + // ServiceProvider column + builder.getTimeColumnBuilder().writeLong(0); + StringBuilder serviceStr = + new StringBuilder(serviceProviderToString(result.getServiceProvider())); + while (serviceStr.length() < serviceProviderMaxLen) { + serviceStr.append(" "); + } + builder + .getColumnBuilder(0) + .writeBinary(new Binary(serviceStr.toString(), TSFileConfig.STRING_CHARSET)); + // Sender column + String senderStr; + if (result.getSender().isSetConfigNodeLocation()) { + senderStr = + endPointToString(result.getSender().getConfigNodeLocation().getInternalEndPoint()); + senderStr += " (ConfigNode)"; + } else if (result.getSender().isSetDataNodeLocation()) { + senderStr = + endPointToString(result.getSender().getDataNodeLocation().getInternalEndPoint()); + senderStr += " (DataNode)"; + } else { + senderStr = "All"; + } + builder.getColumnBuilder(1).writeBinary(new Binary(senderStr, TSFileConfig.STRING_CHARSET)); + // Connection column + StringBuilder connectionStatus = new StringBuilder(connectionResultToString(result)); + while (connectionStatus.length() < connectionMaxLen) { + connectionStatus.append(" "); + } + builder + .getColumnBuilder(2) + .writeBinary(new Binary(connectionStatus.toString(), TSFileConfig.STRING_CHARSET)); + builder.declarePosition(); + } + + future.set( + new ConfigTaskResult( + TSStatusCode.SUCCESS_STATUS, + builder.build(), + DatasetHeaderFactory.getTestConnectionHeader())); + } + + private static Map calculateExpectedResultNum( + int configNodeNum, int dataNodeNum) { + Map result = new HashMap<>(); + result.put(TServiceType.ConfigNodeInternalService, configNodeNum + dataNodeNum); + result.put(TServiceType.DataNodeInternalService, configNodeNum + dataNodeNum); + result.put(TServiceType.DataNodeMPPService, dataNodeNum); + result.put(TServiceType.DataNodeExternalService, dataNodeNum); + return result; + } + + private static String serviceProviderToString(TServiceProvider provider) { + String serviceStr = endPointToString(provider.getEndPoint()); + serviceStr += " (" + provider.getServiceType() + ")"; + return serviceStr; + } + + private static String connectionResultToString(TTestConnectionResult result) { + if (result.isSuccess()) { + return ThriftService.STATUS_UP; + } + return ThriftService.STATUS_DOWN + " (" + result.getReason() + ")"; + } + + private static String endPointToString(TEndPoint endPoint) { + return endPoint.getIp() + ":" + endPoint.getPort(); + } + + private static void sortTestConnectionResp(TTestConnectionResp origin) { + origin + .getResultList() + .sort( + (o1, o2) -> { + { + String serviceIp1 = o1.getServiceProvider().getEndPoint().getIp(); + String serviceIp2 = o2.getServiceProvider().getEndPoint().getIp(); + if (!serviceIp1.equals(serviceIp2)) { + return serviceIp1.compareTo(serviceIp2); + } + } + { + int servicePort1 = o1.getServiceProvider().getEndPoint().getPort(); + int servicePort2 = o2.getServiceProvider().getEndPoint().getPort(); + if (servicePort1 != servicePort2) { + return Integer.compare(servicePort1, servicePort2); + } + } + return 0; + }); + } + + private static int calculateServiceProviderMaxLen(TTestConnectionResp resp) { + return resp.getResultList().stream() + .map(TTestConnectionResult::getServiceProvider) + .map(TestConnectionTask::serviceProviderToString) + .mapToInt(String::length) + .max() + .getAsInt(); + } + + private static int calculateConnectionMaxLen(TTestConnectionResp resp) { + return resp.getResultList().stream() + .map(TestConnectionTask::connectionResultToString) + .mapToInt(String::length) + .max() + .getAsInt(); + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/multi/FunctionExpression.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/multi/FunctionExpression.java index a17864ff3be63..27ff875efd090 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/multi/FunctionExpression.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/expression/multi/FunctionExpression.java @@ -193,6 +193,14 @@ public void setExpressions(List expressions) { this.expressions = expressions; } + public FunctionType getFunctionType() { + return functionType; + } + + public void setFunctionType(FunctionType functionType) { + this.functionType = functionType; + } + public String getFunctionName() { return functionName; } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java index 34fb4814fdcdb..341cb87ffb1e6 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/ASTVisitor.java @@ -202,6 +202,7 @@ import org.apache.iotdb.db.queryengine.plan.statement.sys.ShowVersionStatement; import org.apache.iotdb.db.queryengine.plan.statement.sys.StartRepairDataStatement; import org.apache.iotdb.db.queryengine.plan.statement.sys.StopRepairDataStatement; +import org.apache.iotdb.db.queryengine.plan.statement.sys.TestConnectionStatement; import org.apache.iotdb.db.queryengine.plan.statement.sys.quota.SetSpaceQuotaStatement; import org.apache.iotdb.db.queryengine.plan.statement.sys.quota.SetThrottleQuotaStatement; import org.apache.iotdb.db.queryengine.plan.statement.sys.quota.ShowSpaceQuotaStatement; @@ -2566,10 +2567,20 @@ public Statement visitUnsetTTL(IoTDBSqlParser.UnsetTTLContext ctx) { return unSetTTLStatement; } + @Override + public Statement visitShowTTL(IoTDBSqlParser.ShowTTLContext ctx) { + ShowTTLStatement showTTLStatement = new ShowTTLStatement(); + for (IoTDBSqlParser.PrefixPathContext prefixPathContext : ctx.prefixPath()) { + PartialPath partialPath = parsePrefixPath(prefixPathContext); + showTTLStatement.addPathPatterns(partialPath); + } + return showTTLStatement; + } + @Override public Statement visitShowAllTTL(IoTDBSqlParser.ShowAllTTLContext ctx) { ShowTTLStatement showTTLStatement = new ShowTTLStatement(); - showTTLStatement.setAll(true); + showTTLStatement.addPathPatterns(new PartialPath(SqlConstant.getSingleRootArray())); return showTTLStatement; } @@ -3258,8 +3269,8 @@ public Statement visitSetConfiguration(IoTDBSqlParser.SetConfigurationContext ct Integer.parseInt(ctx.INTEGER_LITERAL() == null ? "-1" : ctx.INTEGER_LITERAL().getText()); Map configItems = new HashMap<>(); for (IoTDBSqlParser.SetConfigurationEntryContext entry : ctx.setConfigurationEntry()) { - String key = entry.STRING_LITERAL(0).getText().replace("\"", ""); - String value = entry.STRING_LITERAL(1).getText().replace("\"", ""); + String key = parseStringLiteral(entry.STRING_LITERAL(0).getText()).trim(); + String value = parseStringLiteral(entry.STRING_LITERAL(1).getText()).trim(); configItems.put(key, value); } setConfigurationStatement.setNodeId(nodeId); @@ -4014,6 +4025,11 @@ public Statement visitMigrateRegion(IoTDBSqlParser.MigrateRegionContext ctx) { Integer.parseInt(ctx.toId.getText())); } + @Override + public Statement visitVerifyConnection(IoTDBSqlParser.VerifyConnectionContext ctx) { + return new TestConnectionStatement(ctx.DETAILS() != null); + } + // Quota @Override public Statement visitSetSpaceQuota(IoTDBSqlParser.SetSpaceQuotaContext ctx) { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/StatementGenerator.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/StatementGenerator.java index b0385c8e6420a..68bef30462fc3 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/StatementGenerator.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/parser/StatementGenerator.java @@ -527,7 +527,7 @@ public static CreateAlignedTimeSeriesStatement createStatement(TSCreateAlignedTi final long startTime = System.nanoTime(); // construct create aligned timeseries statement CreateAlignedTimeSeriesStatement statement = new CreateAlignedTimeSeriesStatement(); - statement.setDevicePath(new PartialPath(req.prefixPath)); + statement.setDevicePath(DEVICE_PATH_CACHE.getPartialPath(req.prefixPath)); List dataTypes = new ArrayList<>(); for (Integer dataType : req.dataTypes) { dataTypes.add(TSDataType.deserialize(dataType.byteValue())); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LocalExecutionPlanner.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LocalExecutionPlanner.java index 98bd2a962b8d2..3b74f1b4a08e4 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LocalExecutionPlanner.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LocalExecutionPlanner.java @@ -22,6 +22,7 @@ import org.apache.iotdb.db.conf.IoTDBConfig; import org.apache.iotdb.db.conf.IoTDBDescriptor; import org.apache.iotdb.db.protocol.session.IClientSession; +import org.apache.iotdb.db.queryengine.common.DeviceContext; import org.apache.iotdb.db.queryengine.exception.MemoryNotEnoughException; import org.apache.iotdb.db.queryengine.execution.driver.DataDriverContext; import org.apache.iotdb.db.queryengine.execution.fragment.DataNodeQueryContext; @@ -55,14 +56,14 @@ public class LocalExecutionPlanner { private static final Logger LOGGER = LoggerFactory.getLogger(LocalExecutionPlanner.class); private static final long ALLOCATE_MEMORY_FOR_OPERATORS; - private static final long MAX_REST_MEMORY_FOR_LOAD; + private static final long MIN_REST_MEMORY_FOR_QUERY_AFTER_LOAD; public final Metadata metadata = new TableMetadataImpl(); static { IoTDBConfig CONFIG = IoTDBDescriptor.getInstance().getConfig(); ALLOCATE_MEMORY_FOR_OPERATORS = CONFIG.getAllocateMemoryForOperators(); - MAX_REST_MEMORY_FOR_LOAD = + MIN_REST_MEMORY_FOR_QUERY_AFTER_LOAD = (long) ((ALLOCATE_MEMORY_FOR_OPERATORS) * (1.0 - CONFIG.getMaxAllocateMemoryRatioForLoad())); } @@ -74,6 +75,10 @@ public long getFreeMemoryForOperators() { return freeMemoryForOperators; } + public long getFreeMemoryForLoadTsFile() { + return freeMemoryForOperators - MIN_REST_MEMORY_FOR_QUERY_AFTER_LOAD; + } + public static LocalExecutionPlanner getInstance() { return InstanceHolder.INSTANCE; } @@ -113,7 +118,7 @@ public List plan( context.addPipelineDriverFactory(root, context.getDriverContext(), estimatedMemorySize); instanceContext.setSourcePaths(collectSourcePaths(context)); - instanceContext.setDevicePathsToAligned(collectDevicePathsToAligned(context)); + instanceContext.setDevicePathsToContext(collectDevicePathsToContext(context)); instanceContext.setQueryDataSourceType( getQueryDataSourceType((DataDriverContext) context.getDriverContext())); @@ -206,11 +211,12 @@ private QueryDataSourceType getQueryDataSourceType(DataDriverContext dataDriverC return dataDriverContext.getQueryDataSourceType().orElse(QueryDataSourceType.SERIES_SCAN); } - private Map collectDevicePathsToAligned(LocalExecutionPlanContext context) { + private Map collectDevicePathsToContext( + LocalExecutionPlanContext context) { DataDriverContext dataDriverContext = (DataDriverContext) context.getDriverContext(); - Map deviceToAlignedMap = dataDriverContext.getDeviceIDToAligned(); - dataDriverContext.clearDeviceIDToAligned(); - return deviceToAlignedMap; + Map deviceContextMap = dataDriverContext.getDeviceIDToContext(); + dataDriverContext.clearDeviceIDToContext(); + return deviceContextMap; } private List collectSourcePaths(LocalExecutionPlanContext context) { @@ -227,7 +233,7 @@ private List collectSourcePaths(LocalExecutionPlanContext context) { } public synchronized boolean forceAllocateFreeMemoryForOperators(long memoryInBytes) { - if (freeMemoryForOperators - memoryInBytes <= MAX_REST_MEMORY_FOR_LOAD) { + if (freeMemoryForOperators - memoryInBytes <= MIN_REST_MEMORY_FOR_QUERY_AFTER_LOAD) { return false; } else { freeMemoryForOperators -= memoryInBytes; @@ -236,9 +242,9 @@ public synchronized boolean forceAllocateFreeMemoryForOperators(long memoryInByt } public synchronized long tryAllocateFreeMemoryForOperators(long memoryInBytes) { - if (freeMemoryForOperators - memoryInBytes <= MAX_REST_MEMORY_FOR_LOAD) { - long result = freeMemoryForOperators - MAX_REST_MEMORY_FOR_LOAD; - freeMemoryForOperators = MAX_REST_MEMORY_FOR_LOAD; + if (freeMemoryForOperators - memoryInBytes <= MIN_REST_MEMORY_FOR_QUERY_AFTER_LOAD) { + long result = freeMemoryForOperators - MIN_REST_MEMORY_FOR_QUERY_AFTER_LOAD; + freeMemoryForOperators = MIN_REST_MEMORY_FOR_QUERY_AFTER_LOAD; return result; } else { freeMemoryForOperators -= memoryInBytes; diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LogicalPlanBuilder.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LogicalPlanBuilder.java index de448bc1c6c8f..23ea2f49f6f10 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LogicalPlanBuilder.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LogicalPlanBuilder.java @@ -28,8 +28,9 @@ import org.apache.iotdb.commons.path.PartialPath; import org.apache.iotdb.commons.path.PathPatternTree; import org.apache.iotdb.commons.schema.filter.SchemaFilter; +import org.apache.iotdb.db.queryengine.common.DeviceContext; import org.apache.iotdb.db.queryengine.common.MPPQueryContext; -import org.apache.iotdb.db.queryengine.common.TimeseriesSchemaInfo; +import org.apache.iotdb.db.queryengine.common.TimeseriesContext; import org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant; import org.apache.iotdb.db.queryengine.execution.MemoryEstimationHelper; import org.apache.iotdb.db.queryengine.execution.aggregation.AccumulatorFactory; @@ -42,6 +43,7 @@ import org.apache.iotdb.db.queryengine.plan.expression.multi.FunctionExpression; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.CountSchemaMergeNode; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.DeviceSchemaFetchScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.DevicesCountNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.DevicesSchemaScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.LevelTimeSeriesCountNode; @@ -52,9 +54,9 @@ import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.NodePathsSchemaScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.PathsUsingTemplateScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaFetchMergeNode; -import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaFetchScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaQueryMergeNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaQueryOrderByHeatNode; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SeriesSchemaFetchScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.TimeSeriesCountNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.TimeSeriesSchemaScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.ColumnInjectNode; @@ -1087,12 +1089,14 @@ public LogicalPlanBuilder planSchemaFetchMerge(List storageGroupList) { } @SuppressWarnings({"checkstyle:Indentation", "checkstyle:CommentsIndentation"}) - public LogicalPlanBuilder planSchemaFetchSource( + public LogicalPlanBuilder planSeriesSchemaFetchSource( List storageGroupList, PathPatternTree patternTree, Map templateMap, boolean withTags, - boolean withTemplate) { + boolean withAttributes, + boolean withTemplate, + boolean withAliasForce) { PartialPath storageGroupPath; for (String storageGroup : storageGroupList) { try { @@ -1105,13 +1109,43 @@ public LogicalPlanBuilder planSchemaFetchSource( overlappedPatternTree.appendFullPath(pathPattern); } this.root.addChild( - new SchemaFetchScanNode( + new SeriesSchemaFetchScanNode( context.getQueryId().genPlanNodeId(), storageGroupPath, overlappedPatternTree, templateMap, withTags, - withTemplate)); + withAttributes, + withTemplate, + withAliasForce)); + } catch (IllegalPathException e) { + // definitely won't happen + throw new RuntimeException(e); + } + } + return this; + } + + @SuppressWarnings({"checkstyle:Indentation", "checkstyle:CommentsIndentation"}) + public LogicalPlanBuilder planDeviceSchemaFetchSource( + List storageGroupList, PathPatternTree patternTree, PathPatternTree authorityScope) { + PartialPath storageGroupPath; + for (String storageGroup : storageGroupList) { + try { + storageGroupPath = new PartialPath(storageGroup); + PathPatternTree overlappedPatternTree = new PathPatternTree(); + for (PartialPath pathPattern : + patternTree.getOverlappedPathPatterns( + storageGroupPath.concatNode(MULTI_LEVEL_PATH_WILDCARD))) { + // pathPattern has been deduplicated, no need to deduplicate again + overlappedPatternTree.appendFullPath(pathPattern); + } + this.root.addChild( + new DeviceSchemaFetchScanNode( + context.getQueryId().genPlanNodeId(), + storageGroupPath, + overlappedPatternTree, + authorityScope)); } catch (IllegalPathException e) { // definitely won't happen throw new RuntimeException(e); @@ -1350,15 +1384,15 @@ public LogicalPlanBuilder planEndTimeColumnInject( } public LogicalPlanBuilder planDeviceRegionScan( - Map devicePathToAlignedStatus, boolean outputCount) { + Map devicePathToContextMap, boolean outputCount) { this.root = new DeviceRegionScanNode( - context.getQueryId().genPlanNodeId(), devicePathToAlignedStatus, outputCount, null); + context.getQueryId().genPlanNodeId(), devicePathToContextMap, outputCount, null); return this; } public LogicalPlanBuilder planTimeseriesRegionScan( - Map>> deviceToTimeseriesSchemaInfo, + Map>> deviceToTimeseriesSchemaInfo, boolean outputCount) { TimeseriesRegionScanNode timeseriesRegionScanNode = new TimeseriesRegionScanNode(context.getQueryId().genPlanNodeId(), outputCount, null); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LogicalPlanVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LogicalPlanVisitor.java index 98f544c75f550..68a3281dead6c 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LogicalPlanVisitor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/LogicalPlanVisitor.java @@ -61,10 +61,11 @@ import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertTabletStatement; import org.apache.iotdb.db.queryengine.plan.statement.crud.LoadTsFileStatement; import org.apache.iotdb.db.queryengine.plan.statement.crud.QueryStatement; +import org.apache.iotdb.db.queryengine.plan.statement.internal.DeviceSchemaFetchStatement; import org.apache.iotdb.db.queryengine.plan.statement.internal.InternalBatchActivateTemplateStatement; import org.apache.iotdb.db.queryengine.plan.statement.internal.InternalCreateMultiTimeSeriesStatement; import org.apache.iotdb.db.queryengine.plan.statement.internal.InternalCreateTimeSeriesStatement; -import org.apache.iotdb.db.queryengine.plan.statement.internal.SchemaFetchStatement; +import org.apache.iotdb.db.queryengine.plan.statement.internal.SeriesSchemaFetchStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.AlterTimeSeriesStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.CountDevicesStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.CountLevelTimeSeriesStatement; @@ -580,7 +581,7 @@ public PlanNode visitShowDevices( if (showDevicesStatement.hasTimeCondition()) { planBuilder = planBuilder - .planDeviceRegionScan(analysis.getDevicePathToAlignedStatus(), false) + .planDeviceRegionScan(analysis.getDevicePathToContextMap(), false) .planLimit(showDevicesStatement.getLimit()) .planOffset(showDevicesStatement.getOffset()); return planBuilder.getRoot(); @@ -626,7 +627,7 @@ public PlanNode visitCountDevices( LogicalPlanBuilder planBuilder = new LogicalPlanBuilder(analysis, context); if (countDevicesStatement.hasTimeCondition()) { - planBuilder = planBuilder.planDeviceRegionScan(analysis.getDevicePathToAlignedStatus(), true); + planBuilder = planBuilder.planDeviceRegionScan(analysis.getDevicePathToContextMap(), true); return planBuilder.getRoot(); } @@ -778,19 +779,36 @@ public PlanNode visitInsertRowsOfOneDevice( } @Override - public PlanNode visitSchemaFetch( - SchemaFetchStatement schemaFetchStatement, MPPQueryContext context) { + public PlanNode visitSeriesSchemaFetch( + SeriesSchemaFetchStatement seriesSchemaFetchStatement, MPPQueryContext context) { LogicalPlanBuilder planBuilder = new LogicalPlanBuilder(analysis, context); List storageGroupList = new ArrayList<>(analysis.getSchemaPartitionInfo().getSchemaPartitionMap().keySet()); return planBuilder .planSchemaFetchMerge(storageGroupList) - .planSchemaFetchSource( + .planSeriesSchemaFetchSource( storageGroupList, - schemaFetchStatement.getPatternTree(), - schemaFetchStatement.getTemplateMap(), - schemaFetchStatement.isWithTags(), - schemaFetchStatement.isWithTemplate()) + seriesSchemaFetchStatement.getPatternTree(), + seriesSchemaFetchStatement.getTemplateMap(), + seriesSchemaFetchStatement.isWithTags(), + seriesSchemaFetchStatement.isWithAttributes(), + seriesSchemaFetchStatement.isWithTemplate(), + seriesSchemaFetchStatement.isWithAliasForce()) + .getRoot(); + } + + @Override + public PlanNode visitDeviceSchemaFetch( + DeviceSchemaFetchStatement deviceSchemaFetchStatement, MPPQueryContext context) { + LogicalPlanBuilder planBuilder = new LogicalPlanBuilder(analysis, context); + List storageGroupList = + new ArrayList<>(analysis.getSchemaPartitionInfo().getSchemaPartitionMap().keySet()); + return planBuilder + .planSchemaFetchMerge(storageGroupList) + .planDeviceSchemaFetchSource( + storageGroupList, + deviceSchemaFetchStatement.getPatternTree(), + deviceSchemaFetchStatement.getAuthorityScope()) .getRoot(); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/OperatorTreeGenerator.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/OperatorTreeGenerator.java index 692125063bd1e..cd9cb23db3358 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/OperatorTreeGenerator.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/OperatorTreeGenerator.java @@ -29,9 +29,10 @@ import org.apache.iotdb.commons.path.PartialPath; import org.apache.iotdb.db.conf.IoTDBDescriptor; import org.apache.iotdb.db.exception.query.QueryProcessException; +import org.apache.iotdb.db.queryengine.common.DeviceContext; import org.apache.iotdb.db.queryengine.common.FragmentInstanceId; import org.apache.iotdb.db.queryengine.common.NodeRef; -import org.apache.iotdb.db.queryengine.common.TimeseriesSchemaInfo; +import org.apache.iotdb.db.queryengine.common.TimeseriesContext; import org.apache.iotdb.db.queryengine.execution.aggregation.Accumulator; import org.apache.iotdb.db.queryengine.execution.aggregation.AccumulatorFactory; import org.apache.iotdb.db.queryengine.execution.aggregation.Aggregator; @@ -170,6 +171,7 @@ import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanVisitor; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.CountSchemaMergeNode; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.DeviceSchemaFetchScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.DevicesCountNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.DevicesSchemaScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.LevelTimeSeriesCountNode; @@ -180,10 +182,10 @@ import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.NodePathsSchemaScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.PathsUsingTemplateScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaFetchMergeNode; -import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaFetchScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaQueryMergeNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaQueryOrderByHeatNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaQueryScanNode; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SeriesSchemaFetchScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.TimeSeriesCountNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.TimeSeriesSchemaScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.ActiveRegionScanMergeNode; @@ -348,8 +350,6 @@ public Operator visitSeriesScan(SeriesScanNode node, LocalExecutionPlanContext c SeriesScanOptions.Builder scanOptionsBuilder = getSeriesScanOptionsBuilder(context); scanOptionsBuilder.withAllSensors( context.getAllSensors(seriesPath.getDeviceId(), seriesPath.getMeasurement())); - scanOptionsBuilder.withPushDownLimit(node.getPushDownLimit()); - scanOptionsBuilder.withPushDownOffset(node.getPushDownOffset()); Expression pushDownPredicate = node.getPushDownPredicate(); boolean predicateCanPushIntoScan = canPushIntoScan(pushDownPredicate); @@ -362,6 +362,10 @@ public Operator visitSeriesScan(SeriesScanNode node, LocalExecutionPlanContext c context.getTypeProvider(), context.getZoneId())); } + if (pushDownPredicate == null || predicateCanPushIntoScan) { + scanOptionsBuilder.withPushDownLimit(node.getPushDownLimit()); + scanOptionsBuilder.withPushDownOffset(node.getPushDownOffset()); + } OperatorContext operatorContext = context @@ -385,17 +389,43 @@ public Operator visitSeriesScan(SeriesScanNode node, LocalExecutionPlanContext c if (!predicateCanPushIntoScan) { checkState(!context.isBuildPlanUseTemplate(), "Push down predicate is not supported yet"); - return constructFilterOperator( - pushDownPredicate, - seriesScanOperator, - Collections.singletonList(ExpressionFactory.timeSeries(node.getSeriesPath())) - .toArray(new Expression[0]), - Collections.singletonList(node.getSeriesPath().getSeriesType()), - makeLayout(Collections.singletonList(node)), - false, - node.getPlanNodeId(), - node.getScanOrder(), - context); + Operator rootOperator = + constructFilterOperator( + pushDownPredicate, + seriesScanOperator, + Collections.singletonList(ExpressionFactory.timeSeries(node.getSeriesPath())) + .toArray(new Expression[0]), + Collections.singletonList(node.getSeriesPath().getSeriesType()), + makeLayout(Collections.singletonList(node)), + false, + node.getPlanNodeId(), + node.getScanOrder(), + context); + if (node.getPushDownOffset() > 0) { + rootOperator = + new OffsetOperator( + context + .getDriverContext() + .addOperatorContext( + context.getNextOperatorId(), + node.getPlanNodeId(), + OffsetOperator.class.getSimpleName()), + node.getPushDownOffset(), + rootOperator); + } + if (node.getPushDownLimit() > 0) { + rootOperator = + new LimitOperator( + context + .getDriverContext() + .addOperatorContext( + context.getNextOperatorId(), + node.getPlanNodeId(), + LimitOperator.class.getSimpleName()), + node.getPushDownLimit(), + rootOperator); + } + return rootOperator; } return seriesScanOperator; } @@ -407,8 +437,6 @@ public Operator visitAlignedSeriesScan( (AlignedFullPath) IFullPath.convertToIFullPath(node.getAlignedPath()); SeriesScanOptions.Builder scanOptionsBuilder = getSeriesScanOptionsBuilder(context); - scanOptionsBuilder.withPushDownLimit(node.getPushDownLimit()); - scanOptionsBuilder.withPushDownOffset(node.getPushDownOffset()); scanOptionsBuilder.withAllSensors( new HashSet<>( context.isBuildPlanUseTemplate() @@ -426,6 +454,10 @@ public Operator visitAlignedSeriesScan( context.getTypeProvider(), context.getZoneId())); } + if (pushDownPredicate == null || predicateCanPushIntoScan) { + scanOptionsBuilder.withPushDownLimit(node.getPushDownLimit()); + scanOptionsBuilder.withPushDownOffset(node.getPushDownOffset()); + } OperatorContext operatorContext = context @@ -483,16 +515,43 @@ public Operator visitAlignedSeriesScan( dataTypes.add(alignedPath.getSubMeasurementDataType(i)); } - return constructFilterOperator( - pushDownPredicate, - seriesScanOperator, - expressions.toArray(new Expression[0]), - dataTypes, - makeLayout(Collections.singletonList(node)), - false, - node.getPlanNodeId(), - node.getScanOrder(), - context); + Operator rootOperator = + constructFilterOperator( + pushDownPredicate, + seriesScanOperator, + expressions.toArray(new Expression[0]), + dataTypes, + makeLayout(Collections.singletonList(node)), + false, + node.getPlanNodeId(), + node.getScanOrder(), + context); + + if (node.getPushDownOffset() > 0) { + rootOperator = + new OffsetOperator( + context + .getDriverContext() + .addOperatorContext( + context.getNextOperatorId(), + node.getPlanNodeId(), + OffsetOperator.class.getSimpleName()), + node.getPushDownOffset(), + rootOperator); + } + if (node.getPushDownLimit() > 0) { + rootOperator = + new LimitOperator( + context + .getDriverContext() + .addOperatorContext( + context.getNextOperatorId(), + node.getPlanNodeId(), + LimitOperator.class.getSimpleName()), + node.getPushDownLimit(), + rootOperator); + } + return rootOperator; } return seriesScanOperator; } @@ -2605,8 +2664,8 @@ public Operator visitSchemaFetchMerge( } @Override - public Operator visitSchemaFetchScan( - SchemaFetchScanNode node, LocalExecutionPlanContext context) { + public Operator visitSeriesSchemaFetchScan( + SeriesSchemaFetchScanNode node, LocalExecutionPlanContext context) { OperatorContext operatorContext = context .getDriverContext() @@ -2614,14 +2673,34 @@ public Operator visitSchemaFetchScan( context.getNextOperatorId(), node.getPlanNodeId(), SchemaFetchScanOperator.class.getSimpleName()); - return new SchemaFetchScanOperator( + return SchemaFetchScanOperator.ofSeries( node.getPlanNodeId(), operatorContext, node.getPatternTree(), node.getTemplateMap(), ((SchemaDriverContext) (context.getDriverContext())).getSchemaRegion(), node.isWithTags(), - node.isWithTemplate()); + node.isWithAttributes(), + node.isWithTemplate(), + node.isWithAliasForce()); + } + + @Override + public Operator visitDeviceSchemaFetchScan( + DeviceSchemaFetchScanNode node, LocalExecutionPlanContext context) { + OperatorContext operatorContext = + context + .getDriverContext() + .addOperatorContext( + context.getNextOperatorId(), + node.getPlanNodeId(), + SchemaFetchScanOperator.class.getSimpleName()); + return SchemaFetchScanOperator.ofDevice( + node.getPlanNodeId(), + operatorContext, + node.getPatternTree(), + node.getAuthorityScope(), + ((SchemaDriverContext) (context.getDriverContext())).getSchemaRegion()); } @Override @@ -3550,18 +3629,20 @@ public Operator visitDeviceRegionScan( node.getPlanNodeId(), ActiveDeviceRegionScanOperator.class.getSimpleName()); Filter filter = context.getGlobalTimeFilter(); - Map deviceIDToAligned = new HashMap<>(); - for (Map.Entry entry : node.getDevicePathsToAligned().entrySet()) { - deviceIDToAligned.put( + + Map deviceIDToContext = new HashMap<>(); + for (Map.Entry entry : + node.getDevicePathToContextMap().entrySet()) { + deviceIDToContext.put( IDeviceID.Factory.DEFAULT_FACTORY.create(entry.getKey().getFullPath()), entry.getValue()); } ActiveDeviceRegionScanOperator regionScanOperator = new ActiveDeviceRegionScanOperator( - operatorContext, node.getPlanNodeId(), deviceIDToAligned, filter, node.isOutputCount()); + operatorContext, node.getPlanNodeId(), deviceIDToContext, filter, node.isOutputCount()); DataDriverContext dataDriverContext = (DataDriverContext) context.getDriverContext(); dataDriverContext.addSourceOperator(regionScanOperator); - dataDriverContext.setDeviceIDToAligned(deviceIDToAligned); + dataDriverContext.setDeviceIDToContext(deviceIDToContext); dataDriverContext.setQueryDataSourceType(QueryDataSourceType.DEVICE_REGION_SCAN); return regionScanOperator; @@ -3580,10 +3661,10 @@ public Operator visitTimeSeriesRegionScan( Filter filter = context.getGlobalTimeFilter(); DataDriverContext dataDriverContext = (DataDriverContext) context.getDriverContext(); - Map> timeseriesToSchemaInfo = new HashMap<>(); - for (Map.Entry>> entryMap : + Map> timeseriesToSchemaInfo = new HashMap<>(); + for (Map.Entry>> entryMap : node.getDeviceToTimeseriesSchemaInfo().entrySet()) { - Map timeseriesSchemaInfoMap = + Map timeseriesSchemaInfoMap = getTimeseriesSchemaInfoMap(entryMap, dataDriverContext); timeseriesToSchemaInfo.put( entryMap.getValue().keySet().iterator().next().getIDeviceID(), timeseriesSchemaInfoMap); @@ -3602,12 +3683,11 @@ public Operator visitTimeSeriesRegionScan( return regionScanOperator; } - private static Map getTimeseriesSchemaInfoMap( - Map.Entry>> entryMap, + private static Map getTimeseriesSchemaInfoMap( + Map.Entry>> entryMap, DataDriverContext context) { - Map timeseriesSchemaInfoMap = new HashMap<>(); - for (Map.Entry> entry : - entryMap.getValue().entrySet()) { + Map timeseriesSchemaInfoMap = new HashMap<>(); + for (Map.Entry> entry : entryMap.getValue().entrySet()) { PartialPath path = entry.getKey(); if (path instanceof MeasurementPath) { timeseriesSchemaInfoMap.put(path.getMeasurement(), entry.getValue().get(0)); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/ExchangeNodeAdder.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/ExchangeNodeAdder.java index f261acfb65c26..e5983b6a18ce3 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/ExchangeNodeAdder.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/ExchangeNodeAdder.java @@ -28,11 +28,12 @@ import org.apache.iotdb.db.queryengine.plan.planner.plan.node.WritePlanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.AbstractSchemaMergeNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.CountSchemaMergeNode; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.DeviceSchemaFetchScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaFetchMergeNode; -import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaFetchScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaQueryMergeNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaQueryOrderByHeatNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaQueryScanNode; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SeriesSchemaFetchScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.ActiveRegionScanMergeNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.AggregationMergeSortNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.process.AggregationNode; @@ -158,7 +159,14 @@ public PlanNode visitSchemaQueryScan(SchemaQueryScanNode node, NodeGroupContext } @Override - public PlanNode visitSchemaFetchScan(SchemaFetchScanNode node, NodeGroupContext context) { + public PlanNode visitSeriesSchemaFetchScan( + SeriesSchemaFetchScanNode node, NodeGroupContext context) { + return processNoChildSourceNode(node, context); + } + + @Override + public PlanNode visitDeviceSchemaFetchScan( + DeviceSchemaFetchScanNode node, NodeGroupContext context) { return processNoChildSourceNode(node, context); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanNodeType.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanNodeType.java index 2d910f02c1756..1846f8aa0ce5e 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanNodeType.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanNodeType.java @@ -21,6 +21,7 @@ import org.apache.iotdb.db.queryengine.plan.analyze.TypeProvider; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.load.LoadTsFilePieceNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.CountSchemaMergeNode; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.DeviceSchemaFetchScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.DevicesCountNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.DevicesSchemaScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.LevelTimeSeriesCountNode; @@ -31,9 +32,9 @@ import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.NodePathsSchemaScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.PathsUsingTemplateScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaFetchMergeNode; -import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaFetchScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaQueryMergeNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaQueryOrderByHeatNode; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SeriesSchemaFetchScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.TimeSeriesCountNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.TimeSeriesSchemaScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.write.ActivateTemplateNode; @@ -141,7 +142,7 @@ public enum PlanNodeType { ALTER_TIME_SERIES((short) 21), CREATE_ALIGNED_TIME_SERIES((short) 22), TIME_SERIES_SCHEMA_SCAN((short) 23), - SCHEMA_FETCH_SCAN((short) 24), + SERIES_SCHEMA_FETCH_SCAN((short) 24), SCHEMA_QUERY_MERGE((short) 25), SCHEMA_QUERY_ORDER_BY_HEAT((short) 26), DEVICES_COUNT((short) 27), @@ -219,6 +220,7 @@ public enum PlanNodeType { DEVICE_REGION_SCAN((short) 93), TIMESERIES_REGION_SCAN((short) 94), REGION_MERGE((short) 95), + DEVICE_SCHEMA_FETCH_SCAN((short) 96), CREATE_TABLE_DEVICE((short) 902), TABLE_DEVICE_SCAN((short) 903), @@ -339,7 +341,7 @@ public static PlanNode deserialize(ByteBuffer buffer, short nodeType) { case 23: return TimeSeriesSchemaScanNode.deserialize(buffer); case 24: - return SchemaFetchScanNode.deserialize(buffer); + return SeriesSchemaFetchScanNode.deserialize(buffer); case 25: return SchemaQueryMergeNode.deserialize(buffer); case 26: @@ -477,6 +479,8 @@ public static PlanNode deserialize(ByteBuffer buffer, short nodeType) { return TimeseriesRegionScanNode.deserialize(buffer); case 95: return ActiveRegionScanMergeNode.deserialize(buffer); + case 96: + return DeviceSchemaFetchScanNode.deserialize(buffer); case 1000: return org.apache.iotdb.db.queryengine.plan.relational.planner.node.TableScanNode .deserialize(buffer); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanVisitor.java index 11d504b4cc4d0..ca6e09c55b39c 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanVisitor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/PlanVisitor.java @@ -19,6 +19,7 @@ package org.apache.iotdb.db.queryengine.plan.planner.plan.node; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.CountSchemaMergeNode; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.DeviceSchemaFetchScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.DevicesCountNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.DevicesSchemaScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.LevelTimeSeriesCountNode; @@ -27,10 +28,10 @@ import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.NodePathsCountNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.NodePathsSchemaScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaFetchMergeNode; -import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaFetchScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaQueryMergeNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaQueryOrderByHeatNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaQueryScanNode; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SeriesSchemaFetchScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.TimeSeriesCountNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.TimeSeriesSchemaScanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.write.ActivateTemplateNode; @@ -389,7 +390,11 @@ public R visitSchemaFetchMerge(SchemaFetchMergeNode node, C context) { return visitPlan(node, context); } - public R visitSchemaFetchScan(SchemaFetchScanNode node, C context) { + public R visitSeriesSchemaFetchScan(SeriesSchemaFetchScanNode node, C context) { + return visitPlan(node, context); + } + + public R visitDeviceSchemaFetchScan(DeviceSchemaFetchScanNode node, C context) { return visitPlan(node, context); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metedata/read/DeviceSchemaFetchScanNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metedata/read/DeviceSchemaFetchScanNode.java new file mode 100644 index 0000000000000..5b1935e1c4c05 --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metedata/read/DeviceSchemaFetchScanNode.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.iotdb.db.queryengine.plan.planner.plan.node.metedata.read; + +import org.apache.iotdb.commons.path.PartialPath; +import org.apache.iotdb.commons.path.PathDeserializeUtil; +import org.apache.iotdb.commons.path.PathPatternTree; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeType; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeUtil; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanVisitor; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; + +public class DeviceSchemaFetchScanNode extends SchemaFetchScanNode { + + private final PathPatternTree authorityScope; + + public DeviceSchemaFetchScanNode( + PlanNodeId id, + PartialPath storageGroup, + PathPatternTree patternTree, + PathPatternTree authorityScope) { + super(id, storageGroup, patternTree); + this.authorityScope = authorityScope; + this.authorityScope.constructTree(); + } + + public PathPatternTree getAuthorityScope() { + return authorityScope; + } + + @Override + public PlanNodeType getType() { + return PlanNodeType.DEVICE_SCHEMA_FETCH_SCAN; + } + + @Override + public PlanNode clone() { + return new DeviceSchemaFetchScanNode( + getPlanNodeId(), storageGroup, patternTree, authorityScope); + } + + @Override + public String toString() { + return String.format( + "DeviceSchemaFetchScanNode-%s:[StorageGroup: %s, DataRegion: %s]", + this.getPlanNodeId(), + storageGroup, + PlanNodeUtil.printRegionReplicaSet(getRegionReplicaSet())); + } + + @Override + protected void serializeAttributes(ByteBuffer byteBuffer) { + PlanNodeType.DEVICE_SCHEMA_FETCH_SCAN.serialize(byteBuffer); + storageGroup.serialize(byteBuffer); + patternTree.serialize(byteBuffer); + authorityScope.serialize(byteBuffer); + } + + @Override + protected void serializeAttributes(DataOutputStream stream) throws IOException { + PlanNodeType.DEVICE_SCHEMA_FETCH_SCAN.serialize(stream); + storageGroup.serialize(stream); + patternTree.serialize(stream); + authorityScope.serialize(stream); + } + + public static DeviceSchemaFetchScanNode deserialize(ByteBuffer byteBuffer) { + PartialPath storageGroup = (PartialPath) PathDeserializeUtil.deserialize(byteBuffer); + PathPatternTree patternTree = PathPatternTree.deserialize(byteBuffer); + PathPatternTree authorityScope = PathPatternTree.deserialize(byteBuffer); + PlanNodeId planNodeId = PlanNodeId.deserialize(byteBuffer); + return new DeviceSchemaFetchScanNode(planNodeId, storageGroup, patternTree, authorityScope); + } + + @Override + public R accept(PlanVisitor visitor, C context) { + return visitor.visitDeviceSchemaFetchScan(this, context); + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metedata/read/SchemaFetchScanNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metedata/read/SchemaFetchScanNode.java index e68aebef1650d..56d2d5cf65740 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metedata/read/SchemaFetchScanNode.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metedata/read/SchemaFetchScanNode.java @@ -21,51 +21,27 @@ import org.apache.iotdb.common.rpc.thrift.TRegionReplicaSet; import org.apache.iotdb.commons.path.PartialPath; -import org.apache.iotdb.commons.path.PathDeserializeUtil; import org.apache.iotdb.commons.path.PathPatternTree; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId; -import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeType; -import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeUtil; -import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanVisitor; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.source.SourceNode; -import org.apache.iotdb.db.schemaengine.template.Template; import com.google.common.collect.ImmutableList; -import org.apache.tsfile.utils.ReadWriteIOUtils; -import java.io.DataOutputStream; -import java.io.IOException; -import java.nio.ByteBuffer; import java.util.Collections; -import java.util.HashMap; import java.util.List; -import java.util.Map; - -/** This class defines the scan task of schema fetcher. */ -public class SchemaFetchScanNode extends SourceNode { - - private final PartialPath storageGroup; - private final PathPatternTree patternTree; - private final Map templateMap; - private final boolean withTags; - private final boolean withTemplate; - private TRegionReplicaSet schemaRegionReplicaSet; - - public SchemaFetchScanNode( - PlanNodeId id, - PartialPath storageGroup, - PathPatternTree patternTree, - Map templateMap, - boolean withTags, - boolean withTemplate) { + +public abstract class SchemaFetchScanNode extends SourceNode { + protected final PartialPath storageGroup; + protected final PathPatternTree patternTree; + protected TRegionReplicaSet schemaRegionReplicaSet; + + protected SchemaFetchScanNode( + PlanNodeId id, PartialPath storageGroup, PathPatternTree patternTree) { super(id); this.storageGroup = storageGroup; this.patternTree = patternTree; this.patternTree.constructTree(); - this.templateMap = templateMap; - this.withTags = withTags; - this.withTemplate = withTemplate; } public PartialPath getStorageGroup() { @@ -76,10 +52,6 @@ public PathPatternTree getPatternTree() { return patternTree; } - public Map getTemplateMap() { - return templateMap; - } - @Override public List getChildren() { return Collections.emptyList(); @@ -88,17 +60,6 @@ public List getChildren() { @Override public void addChild(PlanNode child) {} - @Override - public PlanNodeType getType() { - return PlanNodeType.SCHEMA_FETCH_SCAN; - } - - @Override - public PlanNode clone() { - return new SchemaFetchScanNode( - getPlanNodeId(), storageGroup, patternTree, templateMap, withTags, withTemplate); - } - @Override public int allowedChildCount() { return 0; @@ -109,61 +70,6 @@ public List getOutputColumnNames() { return ImmutableList.of(); } - @Override - public String toString() { - return String.format( - "SchemaFetchScanNode-%s:[StorageGroup: %s, DataRegion: %s]", - this.getPlanNodeId(), - storageGroup, - PlanNodeUtil.printRegionReplicaSet(getRegionReplicaSet())); - } - - @Override - protected void serializeAttributes(ByteBuffer byteBuffer) { - PlanNodeType.SCHEMA_FETCH_SCAN.serialize(byteBuffer); - storageGroup.serialize(byteBuffer); - patternTree.serialize(byteBuffer); - - ReadWriteIOUtils.write(templateMap.size(), byteBuffer); - for (Template template : templateMap.values()) { - template.serialize(byteBuffer); - } - ReadWriteIOUtils.write(withTags, byteBuffer); - ReadWriteIOUtils.write(withTemplate, byteBuffer); - } - - @Override - protected void serializeAttributes(DataOutputStream stream) throws IOException { - PlanNodeType.SCHEMA_FETCH_SCAN.serialize(stream); - storageGroup.serialize(stream); - patternTree.serialize(stream); - ReadWriteIOUtils.write(templateMap.size(), stream); - for (Template template : templateMap.values()) { - template.serialize(stream); - } - ReadWriteIOUtils.write(withTags, stream); - ReadWriteIOUtils.write(withTemplate, stream); - } - - public static SchemaFetchScanNode deserialize(ByteBuffer byteBuffer) { - PartialPath storageGroup = (PartialPath) PathDeserializeUtil.deserialize(byteBuffer); - PathPatternTree patternTree = PathPatternTree.deserialize(byteBuffer); - - int templateNum = ReadWriteIOUtils.readInt(byteBuffer); - Map templateMap = new HashMap<>(); - Template template; - for (int i = 0; i < templateNum; i++) { - template = new Template(); - template.deserialize(byteBuffer); - templateMap.put(template.getId(), template); - } - boolean withTags = ReadWriteIOUtils.readBool(byteBuffer); - boolean withTemplate = ReadWriteIOUtils.readBool(byteBuffer); - PlanNodeId planNodeId = PlanNodeId.deserialize(byteBuffer); - return new SchemaFetchScanNode( - planNodeId, storageGroup, patternTree, templateMap, withTags, withTemplate); - } - @Override public void open() throws Exception {} @@ -179,17 +85,4 @@ public void setRegionReplicaSet(TRegionReplicaSet schemaRegionReplicaSet) { @Override public void close() throws Exception {} - - @Override - public R accept(PlanVisitor visitor, C context) { - return visitor.visitSchemaFetchScan(this, context); - } - - public boolean isWithTags() { - return withTags; - } - - public boolean isWithTemplate() { - return withTemplate; - } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metedata/read/SeriesSchemaFetchScanNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metedata/read/SeriesSchemaFetchScanNode.java new file mode 100644 index 0000000000000..8f3bab5e9cc10 --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metedata/read/SeriesSchemaFetchScanNode.java @@ -0,0 +1,176 @@ +/* + * 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.iotdb.db.queryengine.plan.planner.plan.node.metedata.read; + +import org.apache.iotdb.commons.path.PartialPath; +import org.apache.iotdb.commons.path.PathDeserializeUtil; +import org.apache.iotdb.commons.path.PathPatternTree; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeType; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeUtil; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanVisitor; +import org.apache.iotdb.db.schemaengine.template.Template; + +import org.apache.tsfile.utils.ReadWriteIOUtils; + +import java.io.DataOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.util.HashMap; +import java.util.Map; + +/** This class defines the scan task of schema fetcher. */ +public class SeriesSchemaFetchScanNode extends SchemaFetchScanNode { + + private final Map templateMap; + private final boolean withTags; + private final boolean withAttributes; + private final boolean withTemplate; + private final boolean withAliasForce; + + public SeriesSchemaFetchScanNode( + PlanNodeId id, + PartialPath storageGroup, + PathPatternTree patternTree, + Map templateMap, + boolean withTags, + boolean withAttributes, + boolean withTemplate, + boolean withAliasForce) { + super(id, storageGroup, patternTree); + this.templateMap = templateMap; + this.withTags = withTags; + this.withAttributes = withAttributes; + this.withTemplate = withTemplate; + this.withAliasForce = withAliasForce; + } + + public Map getTemplateMap() { + return templateMap; + } + + @Override + public PlanNodeType getType() { + return PlanNodeType.SERIES_SCHEMA_FETCH_SCAN; + } + + @Override + public PlanNode clone() { + return new SeriesSchemaFetchScanNode( + getPlanNodeId(), + storageGroup, + patternTree, + templateMap, + withTags, + withAttributes, + withTemplate, + withAliasForce); + } + + @Override + public String toString() { + return String.format( + "SeriesSchemaFetchScanNode-%s:[StorageGroup: %s, DataRegion: %s]", + this.getPlanNodeId(), + storageGroup, + PlanNodeUtil.printRegionReplicaSet(getRegionReplicaSet())); + } + + @Override + protected void serializeAttributes(ByteBuffer byteBuffer) { + PlanNodeType.SERIES_SCHEMA_FETCH_SCAN.serialize(byteBuffer); + storageGroup.serialize(byteBuffer); + patternTree.serialize(byteBuffer); + + ReadWriteIOUtils.write(templateMap.size(), byteBuffer); + for (Template template : templateMap.values()) { + template.serialize(byteBuffer); + } + ReadWriteIOUtils.write(withTags, byteBuffer); + ReadWriteIOUtils.write(withAttributes, byteBuffer); + ReadWriteIOUtils.write(withTemplate, byteBuffer); + ReadWriteIOUtils.write(withAliasForce, byteBuffer); + } + + @Override + protected void serializeAttributes(DataOutputStream stream) throws IOException { + PlanNodeType.SERIES_SCHEMA_FETCH_SCAN.serialize(stream); + storageGroup.serialize(stream); + patternTree.serialize(stream); + ReadWriteIOUtils.write(templateMap.size(), stream); + for (Template template : templateMap.values()) { + template.serialize(stream); + } + ReadWriteIOUtils.write(withTags, stream); + ReadWriteIOUtils.write(withAttributes, stream); + ReadWriteIOUtils.write(withTemplate, stream); + ReadWriteIOUtils.write(withAliasForce, stream); + } + + public static SeriesSchemaFetchScanNode deserialize(ByteBuffer byteBuffer) { + PartialPath storageGroup = (PartialPath) PathDeserializeUtil.deserialize(byteBuffer); + PathPatternTree patternTree = PathPatternTree.deserialize(byteBuffer); + + int templateNum = ReadWriteIOUtils.readInt(byteBuffer); + Map templateMap = new HashMap<>(); + Template template; + for (int i = 0; i < templateNum; i++) { + template = new Template(); + template.deserialize(byteBuffer); + templateMap.put(template.getId(), template); + } + boolean withTags = ReadWriteIOUtils.readBool(byteBuffer); + boolean withAttributes = ReadWriteIOUtils.readBool(byteBuffer); + boolean withTemplate = ReadWriteIOUtils.readBool(byteBuffer); + boolean withAliasForce = ReadWriteIOUtils.readBool(byteBuffer); + PlanNodeId planNodeId = PlanNodeId.deserialize(byteBuffer); + return new SeriesSchemaFetchScanNode( + planNodeId, + storageGroup, + patternTree, + templateMap, + withTags, + withAttributes, + withTemplate, + withAliasForce); + } + + @Override + public R accept(PlanVisitor visitor, C context) { + return visitor.visitSeriesSchemaFetchScan(this, context); + } + + public boolean isWithTags() { + return withTags; + } + + public boolean isWithTemplate() { + return withTemplate; + } + + public boolean isWithAttributes() { + return withAttributes; + } + + public boolean isWithAliasForce() { + return withAliasForce; + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metedata/write/CreateAlignedTimeSeriesNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metedata/write/CreateAlignedTimeSeriesNode.java index 0028b90f49d66..b2aa0e71dbd69 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metedata/write/CreateAlignedTimeSeriesNode.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/metedata/write/CreateAlignedTimeSeriesNode.java @@ -23,6 +23,7 @@ import org.apache.iotdb.commons.exception.IllegalPathException; import org.apache.iotdb.commons.path.PartialPath; import org.apache.iotdb.db.queryengine.plan.analyze.IAnalysis; +import org.apache.iotdb.db.queryengine.plan.analyze.cache.schema.DataNodeDevicePathCache; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeType; @@ -211,7 +212,7 @@ public static CreateAlignedTimeSeriesNode deserialize(ByteBuffer byteBuffer) { byte[] bytes = new byte[length]; byteBuffer.get(bytes); try { - devicePath = new PartialPath(new String(bytes)); + devicePath = DataNodeDevicePathCache.getInstance().getPartialPath(new String(bytes)); } catch (IllegalPathException e) { throw new IllegalArgumentException("Can not deserialize CreateAlignedTimeSeriesNode", e); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/source/DeviceRegionScanNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/source/DeviceRegionScanNode.java index 8671c52ddc0cb..a4db348342bf1 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/source/DeviceRegionScanNode.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/source/DeviceRegionScanNode.java @@ -22,6 +22,7 @@ import org.apache.iotdb.common.rpc.thrift.TRegionReplicaSet; import org.apache.iotdb.commons.path.PartialPath; import org.apache.iotdb.commons.path.PathDeserializeUtil; +import org.apache.iotdb.db.queryengine.common.DeviceContext; import org.apache.iotdb.db.queryengine.common.header.ColumnHeader; import org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode; @@ -45,21 +46,21 @@ import java.util.stream.Collectors; public class DeviceRegionScanNode extends RegionScanNode { - private Map devicePathsToAligned; + private Map devicePathToContextMap; public DeviceRegionScanNode( PlanNodeId planNodeId, - Map devicePathsToAligned, + Map devicePathToContextMap, boolean outputCount, TRegionReplicaSet regionReplicaSet) { super(planNodeId); - this.devicePathsToAligned = devicePathsToAligned; + this.devicePathToContextMap = devicePathToContextMap; this.regionReplicaSet = regionReplicaSet; this.outputCount = outputCount; } - public Map getDevicePathsToAligned() { - return devicePathsToAligned; + public Map getDevicePathToContextMap() { + return devicePathToContextMap; } @Override @@ -75,7 +76,7 @@ public void addChild(PlanNode child) { @Override public PlanNode clone() { return new DeviceRegionScanNode( - getPlanNodeId(), getDevicePathsToAligned(), isOutputCount(), getRegionReplicaSet()); + getPlanNodeId(), getDevicePathToContextMap(), isOutputCount(), getRegionReplicaSet()); } @Override @@ -101,24 +102,23 @@ public int allowedChildCount() { public static PlanNode deserialize(ByteBuffer buffer) { int size = ReadWriteIOUtils.readInt(buffer); - Map devicePathsToAligned = new HashMap<>(); + Map devicePathToContextMap = new HashMap<>(); for (int i = 0; i < size; i++) { PartialPath path = (PartialPath) PathDeserializeUtil.deserialize(buffer); - boolean aligned = ReadWriteIOUtils.readBool(buffer); - devicePathsToAligned.put(path, aligned); + devicePathToContextMap.put(path, DeviceContext.deserialize(buffer)); } boolean outputCount = ReadWriteIOUtils.readBool(buffer); PlanNodeId planNodeId = PlanNodeId.deserialize(buffer); - return new DeviceRegionScanNode(planNodeId, devicePathsToAligned, outputCount, null); + return new DeviceRegionScanNode(planNodeId, devicePathToContextMap, outputCount, null); } @Override protected void serializeAttributes(ByteBuffer byteBuffer) { PlanNodeType.DEVICE_REGION_SCAN.serialize(byteBuffer); - ReadWriteIOUtils.write(devicePathsToAligned.size(), byteBuffer); - for (Map.Entry entry : devicePathsToAligned.entrySet()) { + ReadWriteIOUtils.write(devicePathToContextMap.size(), byteBuffer); + for (Map.Entry entry : devicePathToContextMap.entrySet()) { entry.getKey().serialize(byteBuffer); - ReadWriteIOUtils.write(entry.getValue(), byteBuffer); + entry.getValue().serializeAttributes(byteBuffer); } ReadWriteIOUtils.write(outputCount, byteBuffer); } @@ -126,10 +126,10 @@ protected void serializeAttributes(ByteBuffer byteBuffer) { @Override protected void serializeAttributes(DataOutputStream stream) throws IOException { PlanNodeType.DEVICE_REGION_SCAN.serialize(stream); - ReadWriteIOUtils.write(devicePathsToAligned.size(), stream); - for (Map.Entry entry : devicePathsToAligned.entrySet()) { + ReadWriteIOUtils.write(devicePathToContextMap.size(), stream); + for (Map.Entry entry : devicePathToContextMap.entrySet()) { entry.getKey().serialize(stream); - ReadWriteIOUtils.write(entry.getValue(), stream); + entry.getValue().serializeAttributes(stream); } ReadWriteIOUtils.write(outputCount, stream); } @@ -145,23 +145,23 @@ public String toString() { @Override public Set getDevicePaths() { - return new HashSet<>(devicePathsToAligned.keySet()); + return new HashSet<>(devicePathToContextMap.keySet()); } @Override public void addDevicePath(PartialPath devicePath, RegionScanNode node) { - this.devicePathsToAligned.put( - devicePath, ((DeviceRegionScanNode) node).devicePathsToAligned.get(devicePath)); + this.devicePathToContextMap.put( + devicePath, ((DeviceRegionScanNode) node).devicePathToContextMap.get(devicePath)); } @Override public void clearPath() { - this.devicePathsToAligned = new HashMap<>(); + this.devicePathToContextMap = new HashMap<>(); } @Override public long getSize() { - return devicePathsToAligned.size(); + return devicePathToContextMap.size(); } @Override @@ -170,12 +170,12 @@ public boolean equals(Object o) { if (o == null || getClass() != o.getClass()) return false; if (!super.equals(o)) return false; DeviceRegionScanNode that = (DeviceRegionScanNode) o; - return devicePathsToAligned.equals(that.devicePathsToAligned) + return devicePathToContextMap.equals(that.devicePathToContextMap) && outputCount == that.isOutputCount(); } @Override public int hashCode() { - return Objects.hash(super.hashCode(), devicePathsToAligned, outputCount); + return Objects.hash(super.hashCode(), devicePathToContextMap, outputCount); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/source/TimeseriesRegionScanNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/source/TimeseriesRegionScanNode.java index 256d8272b0020..c75542e627359 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/source/TimeseriesRegionScanNode.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/source/TimeseriesRegionScanNode.java @@ -25,7 +25,7 @@ import org.apache.iotdb.commons.path.PartialPath; import org.apache.iotdb.commons.path.PathType; import org.apache.iotdb.commons.utils.TestOnly; -import org.apache.iotdb.db.queryengine.common.TimeseriesSchemaInfo; +import org.apache.iotdb.db.queryengine.common.TimeseriesContext; import org.apache.iotdb.db.queryengine.common.header.ColumnHeader; import org.apache.iotdb.db.queryengine.common.header.ColumnHeaderConstant; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode; @@ -54,8 +54,7 @@ public class TimeseriesRegionScanNode extends RegionScanNode { // IDeviceID -> (MeasurementPath -> TimeseriesSchemaInfo) - private Map>> - deviceToTimeseriesSchemaInfo; + private Map>> deviceToTimeseriesSchemaInfo; public TimeseriesRegionScanNode( PlanNodeId planNodeId, boolean outputCount, TRegionReplicaSet regionReplicaSet) { @@ -66,7 +65,7 @@ public TimeseriesRegionScanNode( public TimeseriesRegionScanNode( PlanNodeId planNodeId, - Map>> deviceToTimeseriesSchemaInfo, + Map>> deviceToTimeseriesSchemaInfo, boolean outputCount, TRegionReplicaSet regionReplicaSet) { super(planNodeId); @@ -76,11 +75,11 @@ public TimeseriesRegionScanNode( } public void setDeviceToTimeseriesSchemaInfo( - Map>> deviceToTimeseriesSchemaInfo) { + Map>> deviceToTimeseriesSchemaInfo) { this.deviceToTimeseriesSchemaInfo = deviceToTimeseriesSchemaInfo; } - public Map>> + public Map>> getDeviceToTimeseriesSchemaInfo() { return deviceToTimeseriesSchemaInfo; } @@ -124,7 +123,7 @@ public int allowedChildCount() { public static PlanNode deserialize(ByteBuffer buffer) { int size = ReadWriteIOUtils.readInt(buffer); - Map>> deviceToTimeseriesSchemaInfo = + Map>> deviceToTimeseriesSchemaInfo = new HashMap<>(); for (int i = 0; i < size; i++) { @@ -136,13 +135,13 @@ public static PlanNode deserialize(ByteBuffer buffer) { PartialPath devicePath = new PartialPath(nodes); int pathSize = ReadWriteIOUtils.readInt(buffer); - Map> measurementToSchemaInfo = new HashMap<>(); + Map> measurementToSchemaInfo = new HashMap<>(); for (int j = 0; j < pathSize; j++) { PartialPath path = deserializePartialPath(nodes, buffer); int schemaSize = ReadWriteIOUtils.readInt(buffer); - List schemaInfos = new ArrayList<>(); + List schemaInfos = new ArrayList<>(); for (int k = 0; k < schemaSize; k++) { - schemaInfos.add(TimeseriesSchemaInfo.deserialize(buffer)); + schemaInfos.add(TimeseriesContext.deserialize(buffer)); } measurementToSchemaInfo.put(path, schemaInfos); } @@ -190,7 +189,7 @@ public String toString() { "%s -> %s", entry1.getKey().getFullPath(), entry1.getValue().stream() - .map(TimeseriesSchemaInfo::toString) + .map(TimeseriesContext::toString) .collect(Collectors.joining(", ")))) .collect(Collectors.joining(", ")))) .collect(Collectors.joining(", "))); @@ -240,7 +239,7 @@ public int hashCode() { protected void serializeAttributes(ByteBuffer byteBuffer) { PlanNodeType.TIMESERIES_REGION_SCAN.serialize(byteBuffer); ReadWriteIOUtils.write(deviceToTimeseriesSchemaInfo.size(), byteBuffer); - for (Map.Entry>> entry : + for (Map.Entry>> entry : deviceToTimeseriesSchemaInfo.entrySet()) { int size = entry.getKey().getNodeLength(); @@ -251,12 +250,12 @@ protected void serializeAttributes(ByteBuffer byteBuffer) { } ReadWriteIOUtils.write(entry.getValue().size(), byteBuffer); - for (Map.Entry> timseriesEntry : + for (Map.Entry> timseriesEntry : entry.getValue().entrySet()) { serializeMeasurements(timseriesEntry.getKey(), byteBuffer); ReadWriteIOUtils.write(timseriesEntry.getValue().size(), byteBuffer); - for (TimeseriesSchemaInfo timeseriesSchemaInfo : timseriesEntry.getValue()) { - timeseriesSchemaInfo.serializeAttributes(byteBuffer); + for (TimeseriesContext timeseriesContext : timseriesEntry.getValue()) { + timeseriesContext.serializeAttributes(byteBuffer); } } } @@ -267,7 +266,7 @@ protected void serializeAttributes(ByteBuffer byteBuffer) { protected void serializeAttributes(DataOutputStream stream) throws IOException { PlanNodeType.TIMESERIES_REGION_SCAN.serialize(stream); ReadWriteIOUtils.write(deviceToTimeseriesSchemaInfo.size(), stream); - for (Map.Entry>> entry : + for (Map.Entry>> entry : deviceToTimeseriesSchemaInfo.entrySet()) { int size = entry.getKey().getNodeLength(); @@ -278,12 +277,12 @@ protected void serializeAttributes(DataOutputStream stream) throws IOException { } ReadWriteIOUtils.write(entry.getValue().size(), stream); - for (Map.Entry> timseriesEntry : + for (Map.Entry> timseriesEntry : entry.getValue().entrySet()) { serializeMeasurements(timseriesEntry.getKey(), stream); ReadWriteIOUtils.write(timseriesEntry.getValue().size(), stream); - for (TimeseriesSchemaInfo timeseriesSchemaInfo : timseriesEntry.getValue()) { - timeseriesSchemaInfo.serializeAttributes(stream); + for (TimeseriesContext timeseriesContext : timseriesEntry.getValue()) { + timeseriesContext.serializeAttributes(stream); } } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/write/InsertRowNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/write/InsertRowNode.java index 1cdec3c126755..3f70e312223c4 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/write/InsertRowNode.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/write/InsertRowNode.java @@ -418,7 +418,9 @@ public static InsertRowNode deserialize(ByteBuffer byteBuffer) { void subDeserialize(ByteBuffer byteBuffer) { time = byteBuffer.getLong(); try { - devicePath = new PartialPath(ReadWriteIOUtils.readString(byteBuffer)); + devicePath = + DataNodeDevicePathCache.getInstance() + .getPartialPath(ReadWriteIOUtils.readString(byteBuffer)); } catch (IllegalPathException e) { throw new IllegalArgumentException(DESERIALIZE_ERROR, e); } @@ -742,7 +744,9 @@ protected static InsertRowNode subDeserializeFromWAL(ByteBuffer buffer) { InsertRowNode insertNode = new InsertRowNode(new PlanNodeId("")); insertNode.setTime(buffer.getLong()); try { - insertNode.setDevicePath(new PartialPath(ReadWriteIOUtils.readString(buffer))); + insertNode.setDevicePath( + DataNodeDevicePathCache.getInstance() + .getPartialPath(ReadWriteIOUtils.readString(buffer))); } catch (IllegalPathException e) { throw new IllegalArgumentException(DESERIALIZE_ERROR, e); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/write/InsertRowsOfOneDeviceNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/write/InsertRowsOfOneDeviceNode.java index 4bc938737364e..3c2797c507707 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/write/InsertRowsOfOneDeviceNode.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/write/InsertRowsOfOneDeviceNode.java @@ -27,6 +27,7 @@ import org.apache.iotdb.commons.utils.StatusUtils; import org.apache.iotdb.commons.utils.TimePartitionUtils; import org.apache.iotdb.db.queryengine.plan.analyze.IAnalysis; +import org.apache.iotdb.db.queryengine.plan.analyze.cache.schema.DataNodeDevicePathCache; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeType; @@ -229,7 +230,9 @@ public static InsertRowsOfOneDeviceNode deserialize(ByteBuffer byteBuffer) { List insertRowNodeIndex = new ArrayList<>(); try { - devicePath = new PartialPath(ReadWriteIOUtils.readString(byteBuffer)); + devicePath = + DataNodeDevicePathCache.getInstance() + .getPartialPath((ReadWriteIOUtils.readString(byteBuffer))); } catch (IllegalPathException e) { throw new IllegalArgumentException("Cannot deserialize InsertRowsOfOneDeviceNode", e); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/write/InsertTabletNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/write/InsertTabletNode.java index bc0adcbc85506..14cc778a52b53 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/write/InsertTabletNode.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/planner/plan/node/write/InsertTabletNode.java @@ -639,7 +639,9 @@ public static InsertTabletNode deserialize(ByteBuffer byteBuffer) { public void subDeserialize(ByteBuffer buffer) { try { - devicePath = new PartialPath(ReadWriteIOUtils.readString(buffer)); + devicePath = + DataNodeDevicePathCache.getInstance() + .getPartialPath((ReadWriteIOUtils.readString(buffer))); } catch (IllegalPathException e) { throw new IllegalArgumentException("Cannot deserialize InsertTabletNode", e); } @@ -930,7 +932,9 @@ public static InsertTabletNode deserializeFromWAL(ByteBuffer buffer) { private void subDeserializeFromWAL(ByteBuffer buffer) { searchIndex = buffer.getLong(); try { - devicePath = new PartialPath(ReadWriteIOUtils.readString(buffer)); + devicePath = + DataNodeDevicePathCache.getInstance() + .getPartialPath((ReadWriteIOUtils.readString(buffer))); } catch (IllegalPathException e) { throw new IllegalArgumentException("Cannot deserialize InsertTabletNode", e); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/IndexScan.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/IndexScan.java index 1aa4c5413d67a..df986c5ac6b74 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/IndexScan.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/relational/planner/optimizations/IndexScan.java @@ -124,7 +124,8 @@ public PlanNode visitTableScan(TableScanNode node, RewriterContext context) { deviceEntries, treeModelDatabase, context.getQueryContext().getGlobalTimeFilter(), - context.getPartitionFetcher()); + context.getPartitionFetcher(), + context.getQueryContext()); context.getAnalysis().setDataPartition(dataPartition); if (dataPartition.getDataPartitionMap().size() > 1) { @@ -160,9 +161,10 @@ private static DataPartition fetchDataPartitionByDevices( List deviceEntries, String database, Filter globalTimeFilter, - IPartitionFetcher partitionFetcher) { + IPartitionFetcher partitionFetcher, + MPPQueryContext context) { Pair, Pair> res = - getTimePartitionSlotList(globalTimeFilter); + getTimePartitionSlotList(globalTimeFilter, context); // there is no satisfied time range if (res.left.isEmpty() && Boolean.FALSE.equals(res.right.left)) { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/scheduler/load/LoadTsFileDispatcherImpl.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/scheduler/load/LoadTsFileDispatcherImpl.java index a630c94797b22..a0f6767813788 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/scheduler/load/LoadTsFileDispatcherImpl.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/scheduler/load/LoadTsFileDispatcherImpl.java @@ -33,7 +33,7 @@ import org.apache.iotdb.db.conf.IoTDBDescriptor; import org.apache.iotdb.db.exception.LoadFileException; import org.apache.iotdb.db.exception.mpp.FragmentInstanceDispatchException; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.queryengine.plan.planner.plan.FragmentInstance; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeType; @@ -166,7 +166,7 @@ public void dispatchLocally(FragmentInstance instance) throws FragmentInstanceDi } else if (planNode instanceof LoadSingleTsFileNode) { // do not need to split final TsFileResource tsFileResource = ((LoadSingleTsFileNode) planNode).getTsFileResource(); try { - PipeAgent.runtime().assignProgressIndexForTsFileLoad(tsFileResource); + PipeDataNodeAgent.runtime().assignProgressIndexForTsFileLoad(tsFileResource); tsFileResource.serialize(); StorageEngine.getInstance() @@ -257,7 +257,7 @@ private void dispatchLocally(TLoadCommandReq loadCommandReq) ProgressIndexType.deserializeFrom(ByteBuffer.wrap(loadCommandReq.getProgressIndex())); } else { // fallback to use local generated progress index for compatibility - progressIndex = PipeAgent.runtime().getNextProgressIndexForTsFileLoad(); + progressIndex = PipeDataNodeAgent.runtime().getNextProgressIndexForTsFileLoad(); LOGGER.info( "Use local generated load progress index {} for uuid {}.", progressIndex, diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/scheduler/load/LoadTsFileScheduler.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/scheduler/load/LoadTsFileScheduler.java index 72a3734cd0613..268f1d5f2ec47 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/scheduler/load/LoadTsFileScheduler.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/scheduler/load/LoadTsFileScheduler.java @@ -40,7 +40,7 @@ import org.apache.iotdb.db.exception.LoadFileException; import org.apache.iotdb.db.exception.LoadReadOnlyException; import org.apache.iotdb.db.exception.mpp.FragmentInstanceDispatchException; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.queryengine.common.MPPQueryContext; import org.apache.iotdb.db.queryengine.common.PlanFragmentId; import org.apache.iotdb.db.queryengine.execution.QueryStateMachine; @@ -50,6 +50,7 @@ import org.apache.iotdb.db.queryengine.execution.load.TsFileSplitter; import org.apache.iotdb.db.queryengine.load.LoadTsFileDataCacheMemoryBlock; import org.apache.iotdb.db.queryengine.load.LoadTsFileMemoryManager; +import org.apache.iotdb.db.queryengine.metric.load.LoadTsFileCostMetricsSet; import org.apache.iotdb.db.queryengine.plan.analyze.IPartitionFetcher; import org.apache.iotdb.db.queryengine.plan.planner.plan.DistributedQueryPlan; import org.apache.iotdb.db.queryengine.plan.planner.plan.FragmentInstance; @@ -107,6 +108,9 @@ public class LoadTsFileScheduler implements IScheduler { private static final IoTDBConfig CONFIG = IoTDBDescriptor.getInstance().getConfig(); + private static final LoadTsFileCostMetricsSet LOAD_TSFILE_COST_METRICS_SET = + LoadTsFileCostMetricsSet.getInstance(); + private static final long SINGLE_SCHEDULER_MAX_MEMORY_SIZE = IoTDBDescriptor.getInstance().getConfig().getThriftMaxFrameSize() >> 2; private static final int TRANSMIT_LIMIT = @@ -176,16 +180,38 @@ public void start() { partitionFetcher.queryDataPartition( slotList, queryContext.getSession().getUserName()))) { // do not decode, load locally - isLoadSingleTsFileSuccess = loadLocally(node); + final long startTime = System.nanoTime(); + try { + isLoadSingleTsFileSuccess = loadLocally(node); + } finally { + LOAD_TSFILE_COST_METRICS_SET.recordPhaseTimeCost( + LoadTsFileCostMetricsSet.LOAD_LOCALLY, System.nanoTime() - startTime); + } + node.clean(); } else { // need decode, load locally or remotely, use two phases method String uuid = UUID.randomUUID().toString(); dispatcher.setUuid(uuid); allReplicaSets.clear(); - boolean isFirstPhaseSuccess = firstPhase(node); - boolean isSecondPhaseSuccess = - secondPhase(isFirstPhaseSuccess, uuid, node.getTsFileResource()); + long startTime = System.nanoTime(); + final boolean isFirstPhaseSuccess; + try { + isFirstPhaseSuccess = firstPhase(node); + } finally { + LOAD_TSFILE_COST_METRICS_SET.recordPhaseTimeCost( + LoadTsFileCostMetricsSet.FIRST_PHASE, System.nanoTime() - startTime); + } + + startTime = System.nanoTime(); + final boolean isSecondPhaseSuccess; + try { + isSecondPhaseSuccess = + secondPhase(isFirstPhaseSuccess, uuid, node.getTsFileResource()); + } finally { + LOAD_TSFILE_COST_METRICS_SET.recordPhaseTimeCost( + LoadTsFileCostMetricsSet.SECOND_PHASE, System.nanoTime() - startTime); + } node.clean(); if (!isFirstPhaseSuccess || !isSecondPhaseSuccess) { @@ -367,7 +393,7 @@ private boolean secondPhase( } private ByteBuffer assignProgressIndex(TsFileResource tsFileResource) throws IOException { - PipeAgent.runtime().assignProgressIndexForTsFileLoad(tsFileResource); + PipeDataNodeAgent.runtime().assignProgressIndexForTsFileLoad(tsFileResource); try (final PublicBAOS byteArrayOutputStream = new PublicBAOS(); final DataOutputStream dataOutputStream = new DataOutputStream(byteArrayOutputStream)) { @@ -432,7 +458,9 @@ private boolean loadLocally(LoadSingleTsFileNode node) throws IoTDBException { Tag.DATABASE.toString(), databaseName, Tag.REGION.toString(), - dataRegion.getDataRegionId()); + dataRegion.getDataRegionId(), + Tag.TYPE.toString(), + Metric.LOAD_POINT_COUNT.toString()); if (!node.isGeneratedByRemoteConsensusLeader()) { MetricService.getInstance() .count( @@ -444,7 +472,9 @@ private boolean loadLocally(LoadSingleTsFileNode node) throws IoTDBException { Tag.DATABASE.toString(), databaseName, Tag.REGION.toString(), - dataRegion.getDataRegionId()); + dataRegion.getDataRegionId(), + Tag.TYPE.toString(), + Metric.LOAD_POINT_COUNT.toString()); } }); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/StatementVisitor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/StatementVisitor.java index 248cf881de12b..1fd8e8a58c287 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/StatementVisitor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/StatementVisitor.java @@ -28,10 +28,11 @@ import org.apache.iotdb.db.queryengine.plan.statement.crud.InsertTabletStatement; import org.apache.iotdb.db.queryengine.plan.statement.crud.LoadTsFileStatement; import org.apache.iotdb.db.queryengine.plan.statement.crud.QueryStatement; +import org.apache.iotdb.db.queryengine.plan.statement.internal.DeviceSchemaFetchStatement; import org.apache.iotdb.db.queryengine.plan.statement.internal.InternalBatchActivateTemplateStatement; import org.apache.iotdb.db.queryengine.plan.statement.internal.InternalCreateMultiTimeSeriesStatement; import org.apache.iotdb.db.queryengine.plan.statement.internal.InternalCreateTimeSeriesStatement; -import org.apache.iotdb.db.queryengine.plan.statement.internal.SchemaFetchStatement; +import org.apache.iotdb.db.queryengine.plan.statement.internal.SeriesSchemaFetchStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.AlterTimeSeriesStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.CountDatabaseStatement; import org.apache.iotdb.db.queryengine.plan.statement.metadata.CountDevicesStatement; @@ -118,6 +119,7 @@ import org.apache.iotdb.db.queryengine.plan.statement.sys.ShowVersionStatement; import org.apache.iotdb.db.queryengine.plan.statement.sys.StartRepairDataStatement; import org.apache.iotdb.db.queryengine.plan.statement.sys.StopRepairDataStatement; +import org.apache.iotdb.db.queryengine.plan.statement.sys.TestConnectionStatement; import org.apache.iotdb.db.queryengine.plan.statement.sys.quota.SetSpaceQuotaStatement; import org.apache.iotdb.db.queryengine.plan.statement.sys.quota.SetThrottleQuotaStatement; import org.apache.iotdb.db.queryengine.plan.statement.sys.quota.ShowSpaceQuotaStatement; @@ -214,6 +216,10 @@ public R visitShowClusterId(ShowClusterIdStatement showClusterIdStatement, C con return visitStatement(showClusterIdStatement, context); } + public R visitTestConnection(TestConnectionStatement testConnectionStatement, C context) { + return visitStatement(testConnectionStatement, context); + } + // UDF public R visitCreateFunction(CreateFunctionStatement createFunctionStatement, C context) { return visitStatement(createFunctionStatement, context); @@ -356,8 +362,14 @@ public R visitCountNodes(CountNodesStatement countStatement, C context) { return visitStatement(countStatement, context); } - public R visitSchemaFetch(SchemaFetchStatement schemaFetchStatement, C context) { - return visitStatement(schemaFetchStatement, context); + public R visitSeriesSchemaFetch( + SeriesSchemaFetchStatement seriesSchemaFetchStatement, C context) { + return visitStatement(seriesSchemaFetchStatement, context); + } + + public R visitDeviceSchemaFetch( + DeviceSchemaFetchStatement deviceSchemaFetchStatement, C context) { + return visitStatement(deviceSchemaFetchStatement, context); } public R visitShowChildPaths(ShowChildPathsStatement showChildPathsStatement, C context) { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/InsertTabletStatement.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/InsertTabletStatement.java index a5dd5fbf511f2..b38997ef9c0c4 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/InsertTabletStatement.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/crud/InsertTabletStatement.java @@ -280,10 +280,12 @@ public Object getFirstValueOfIndex(int index) { Object value; switch (dataTypes[index]) { case INT32: + case DATE: int[] intValues = (int[]) columns[index]; value = intValues[0]; break; case INT64: + case TIMESTAMP: long[] longValues = (long[]) columns[index]; value = longValues[0]; break; @@ -300,6 +302,8 @@ public Object getFirstValueOfIndex(int index) { value = boolValues[0]; break; case TEXT: + case BLOB: + case STRING: Binary[] binaryValues = (Binary[]) columns[index]; value = binaryValues[0]; break; diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/internal/DeviceSchemaFetchStatement.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/internal/DeviceSchemaFetchStatement.java new file mode 100644 index 0000000000000..00271f1909786 --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/internal/DeviceSchemaFetchStatement.java @@ -0,0 +1,58 @@ +/* + * 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.iotdb.db.queryengine.plan.statement.internal; + +import org.apache.iotdb.commons.path.PartialPath; +import org.apache.iotdb.commons.path.PathPatternTree; +import org.apache.iotdb.db.queryengine.plan.statement.Statement; +import org.apache.iotdb.db.queryengine.plan.statement.StatementType; +import org.apache.iotdb.db.queryengine.plan.statement.StatementVisitor; + +import java.util.List; + +public class DeviceSchemaFetchStatement extends Statement { + private final PathPatternTree patternTree; + private final PathPatternTree authorityScope; + + public DeviceSchemaFetchStatement(PathPatternTree patternTree, PathPatternTree authorityScope) { + super(); + this.patternTree = patternTree; + this.authorityScope = authorityScope; + setType(StatementType.FETCH_SCHEMA); + } + + public PathPatternTree getPatternTree() { + return patternTree; + } + + public PathPatternTree getAuthorityScope() { + return authorityScope; + } + + @Override + public List getPaths() { + return patternTree.getAllPathPatterns(); + } + + @Override + public R accept(StatementVisitor visitor, C context) { + return visitor.visitDeviceSchemaFetch(this, context); + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/internal/SchemaFetchStatement.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/internal/SeriesSchemaFetchStatement.java similarity index 80% rename from iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/internal/SchemaFetchStatement.java rename to iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/internal/SeriesSchemaFetchStatement.java index f9b3047e57006..f0b393c817f81 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/internal/SchemaFetchStatement.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/internal/SeriesSchemaFetchStatement.java @@ -29,23 +29,29 @@ import java.util.List; import java.util.Map; -public class SchemaFetchStatement extends Statement { +public class SeriesSchemaFetchStatement extends Statement { private final PathPatternTree patternTree; private final Map templateMap; private final boolean withTags; + private final boolean withAttributes; private final boolean withTemplate; + private final boolean withAliasForce; - public SchemaFetchStatement( + public SeriesSchemaFetchStatement( PathPatternTree patternTree, Map templateMap, boolean withTags, - boolean withTemplate) { + boolean withAttributes, + boolean withTemplate, + boolean withAliasForce) { super(); this.patternTree = patternTree; this.templateMap = templateMap; this.withTags = withTags; + this.withAttributes = withAttributes; this.withTemplate = withTemplate; + this.withAliasForce = withAliasForce; setType(StatementType.FETCH_SCHEMA); } @@ -59,7 +65,7 @@ public Map getTemplateMap() { @Override public R accept(StatementVisitor visitor, C context) { - return visitor.visitSchemaFetch(this, context); + return visitor.visitSeriesSchemaFetch(this, context); } @Override @@ -74,4 +80,12 @@ public boolean isWithTags() { public boolean isWithTemplate() { return withTemplate; } + + public boolean isWithAttributes() { + return withAttributes; + } + + public boolean isWithAliasForce() { + return withAliasForce; + } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/CountDevicesStatement.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/CountDevicesStatement.java index 06d32f7c9b53d..9b73e1f9b0a5a 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/CountDevicesStatement.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/CountDevicesStatement.java @@ -19,9 +19,15 @@ package org.apache.iotdb.db.queryengine.plan.statement.metadata; +import org.apache.iotdb.common.rpc.thrift.TSStatus; +import org.apache.iotdb.commons.auth.AuthException; +import org.apache.iotdb.commons.auth.entity.PrivilegeType; import org.apache.iotdb.commons.path.PartialPath; +import org.apache.iotdb.commons.path.PathPatternTreeUtils; +import org.apache.iotdb.db.auth.AuthorityChecker; import org.apache.iotdb.db.queryengine.plan.statement.StatementVisitor; import org.apache.iotdb.db.queryengine.plan.statement.component.WhereCondition; +import org.apache.iotdb.rpc.TSStatusCode; public class CountDevicesStatement extends CountStatement { @@ -43,6 +49,27 @@ public boolean hasTimeCondition() { return timeCondition != null; } + @Override + public TSStatus checkPermissionBeforeProcess(String userName) { + if (hasTimeCondition()) { + try { + if (!AuthorityChecker.SUPER_USER.equals(userName)) { + this.authorityScope = + PathPatternTreeUtils.intersectWithFullPathPrefixTree( + AuthorityChecker.getAuthorizedPathTree( + userName, PrivilegeType.READ_SCHEMA.ordinal()), + AuthorityChecker.getAuthorizedPathTree( + userName, PrivilegeType.READ_DATA.ordinal())); + } + } catch (AuthException e) { + return new TSStatus(e.getCode().getStatusCode()); + } + return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()); + } else { + return super.checkPermissionBeforeProcess(userName); + } + } + @Override public R accept(StatementVisitor visitor, C context) { return visitor.visitCountDevices(this, context); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/CountTimeSeriesStatement.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/CountTimeSeriesStatement.java index c7c259030a9cf..c0910185421bd 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/CountTimeSeriesStatement.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/CountTimeSeriesStatement.java @@ -19,10 +19,16 @@ package org.apache.iotdb.db.queryengine.plan.statement.metadata; +import org.apache.iotdb.common.rpc.thrift.TSStatus; +import org.apache.iotdb.commons.auth.AuthException; +import org.apache.iotdb.commons.auth.entity.PrivilegeType; import org.apache.iotdb.commons.path.PartialPath; +import org.apache.iotdb.commons.path.PathPatternTreeUtils; import org.apache.iotdb.commons.schema.filter.SchemaFilter; +import org.apache.iotdb.db.auth.AuthorityChecker; import org.apache.iotdb.db.queryengine.plan.statement.StatementVisitor; import org.apache.iotdb.db.queryengine.plan.statement.component.WhereCondition; +import org.apache.iotdb.rpc.TSStatusCode; public class CountTimeSeriesStatement extends CountStatement { @@ -54,6 +60,27 @@ public WhereCondition getTimeCondition() { return timeCondition; } + @Override + public TSStatus checkPermissionBeforeProcess(String userName) { + if (hasTimeCondition()) { + try { + if (!AuthorityChecker.SUPER_USER.equals(userName)) { + this.authorityScope = + PathPatternTreeUtils.intersectWithFullPathPrefixTree( + AuthorityChecker.getAuthorizedPathTree( + userName, PrivilegeType.READ_SCHEMA.ordinal()), + AuthorityChecker.getAuthorizedPathTree( + userName, PrivilegeType.READ_DATA.ordinal())); + } + } catch (AuthException e) { + return new TSStatus(e.getCode().getStatusCode()); + } + return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()); + } else { + return super.checkPermissionBeforeProcess(userName); + } + } + @Override public R accept(StatementVisitor visitor, C context) { return visitor.visitCountTimeSeries(this, context); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/ShowDevicesStatement.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/ShowDevicesStatement.java index 75f33c7b4a1cb..b0b7f8bba3178 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/ShowDevicesStatement.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/ShowDevicesStatement.java @@ -19,10 +19,16 @@ package org.apache.iotdb.db.queryengine.plan.statement.metadata; +import org.apache.iotdb.common.rpc.thrift.TSStatus; +import org.apache.iotdb.commons.auth.AuthException; +import org.apache.iotdb.commons.auth.entity.PrivilegeType; import org.apache.iotdb.commons.path.PartialPath; +import org.apache.iotdb.commons.path.PathPatternTreeUtils; import org.apache.iotdb.commons.schema.filter.SchemaFilter; +import org.apache.iotdb.db.auth.AuthorityChecker; import org.apache.iotdb.db.queryengine.plan.statement.StatementVisitor; import org.apache.iotdb.db.queryengine.plan.statement.component.WhereCondition; +import org.apache.iotdb.rpc.TSStatusCode; import java.util.Collections; import java.util.List; @@ -78,6 +84,27 @@ public boolean hasTimeCondition() { return timeCondition != null; } + @Override + public TSStatus checkPermissionBeforeProcess(String userName) { + if (hasTimeCondition()) { + try { + if (!AuthorityChecker.SUPER_USER.equals(userName)) { + this.authorityScope = + PathPatternTreeUtils.intersectWithFullPathPrefixTree( + AuthorityChecker.getAuthorizedPathTree( + userName, PrivilegeType.READ_SCHEMA.ordinal()), + AuthorityChecker.getAuthorizedPathTree( + userName, PrivilegeType.READ_DATA.ordinal())); + } + } catch (AuthException e) { + return new TSStatus(e.getCode().getStatusCode()); + } + return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()); + } else { + return super.checkPermissionBeforeProcess(userName); + } + } + @Override public R accept(StatementVisitor visitor, C context) { return visitor.visitShowDevices(this, context); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/ShowTTLStatement.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/ShowTTLStatement.java index 399e861923281..022e6b2173819 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/ShowTTLStatement.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/ShowTTLStatement.java @@ -28,12 +28,7 @@ import java.util.List; public class ShowTTLStatement extends ShowStatement implements IConfigStatement { - private List pathPatterns = new ArrayList<>(); - private boolean isAll = false; - - public boolean isAll() { - return isAll; - } + private final List pathPatterns = new ArrayList<>(); @Override public R accept(StatementVisitor visitor, C context) { @@ -53,8 +48,4 @@ public List getPaths() { public void addPathPatterns(PartialPath pathPattern) { pathPatterns.add(pathPattern); } - - public void setAll(boolean all) { - isAll = all; - } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/ShowTimeSeriesStatement.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/ShowTimeSeriesStatement.java index 82a389d622499..7d615cac33648 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/ShowTimeSeriesStatement.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/metadata/ShowTimeSeriesStatement.java @@ -19,10 +19,16 @@ package org.apache.iotdb.db.queryengine.plan.statement.metadata; +import org.apache.iotdb.common.rpc.thrift.TSStatus; +import org.apache.iotdb.commons.auth.AuthException; +import org.apache.iotdb.commons.auth.entity.PrivilegeType; import org.apache.iotdb.commons.path.PartialPath; +import org.apache.iotdb.commons.path.PathPatternTreeUtils; import org.apache.iotdb.commons.schema.filter.SchemaFilter; +import org.apache.iotdb.db.auth.AuthorityChecker; import org.apache.iotdb.db.queryengine.plan.statement.StatementVisitor; import org.apache.iotdb.db.queryengine.plan.statement.component.WhereCondition; +import org.apache.iotdb.rpc.TSStatusCode; import java.util.Collections; import java.util.List; @@ -77,6 +83,27 @@ public boolean hasTimeCondition() { return timeCondition != null; } + @Override + public TSStatus checkPermissionBeforeProcess(String userName) { + if (hasTimeCondition()) { + try { + if (!AuthorityChecker.SUPER_USER.equals(userName)) { + this.authorityScope = + PathPatternTreeUtils.intersectWithFullPathPrefixTree( + AuthorityChecker.getAuthorizedPathTree( + userName, PrivilegeType.READ_SCHEMA.ordinal()), + AuthorityChecker.getAuthorizedPathTree( + userName, PrivilegeType.READ_DATA.ordinal())); + } + } catch (AuthException e) { + return new TSStatus(e.getCode().getStatusCode()); + } + return new TSStatus(TSStatusCode.SUCCESS_STATUS.getStatusCode()); + } else { + return super.checkPermissionBeforeProcess(userName); + } + } + @Override public List getPaths() { return Collections.singletonList(pathPattern); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/sys/TestConnectionStatement.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/sys/TestConnectionStatement.java new file mode 100644 index 0000000000000..2e01ea151dc21 --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/plan/statement/sys/TestConnectionStatement.java @@ -0,0 +1,62 @@ +/* + * 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.iotdb.db.queryengine.plan.statement.sys; + +import org.apache.iotdb.common.rpc.thrift.TSStatus; +import org.apache.iotdb.commons.path.PartialPath; +import org.apache.iotdb.db.queryengine.plan.analyze.QueryType; +import org.apache.iotdb.db.queryengine.plan.statement.IConfigStatement; +import org.apache.iotdb.db.queryengine.plan.statement.Statement; +import org.apache.iotdb.db.queryengine.plan.statement.StatementVisitor; + +import java.util.Collections; +import java.util.List; + +public class TestConnectionStatement extends Statement implements IConfigStatement { + private boolean needDetails; + + public TestConnectionStatement(boolean needDetails) { + this.needDetails = needDetails; + } + + public boolean needDetails() { + return needDetails; + } + + @Override + public QueryType getQueryType() { + return QueryType.READ; + } + + @Override + public List getPaths() { + return Collections.emptyList(); + } + + @Override + public R accept(StatementVisitor visitor, C context) { + return visitor.visitTestConnection(this, context); + } + + @Override + public TSStatus checkPermissionBeforeProcess(String userName) { + return super.checkPermissionBeforeProcess(userName); + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/ISchemaRegion.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/ISchemaRegion.java index 1b679aa8bb0a5..12496ccd3c3f9 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/ISchemaRegion.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/ISchemaRegion.java @@ -199,11 +199,24 @@ void checkSchemaQuota(PartialPath devicePath, int timeSeriesNum) MeasurementPath fetchMeasurementPath(PartialPath fullPath) throws MetadataException; - ClusterSchemaTree fetchSchema( + ClusterSchemaTree fetchSeriesSchema( PathPatternTree patternTree, Map templateMap, boolean withTags, - boolean withTemplate) + boolean withAttributes, + boolean withTemplate, + boolean withAliasForce) + throws MetadataException; + + /** + * Fetch all the schema by the given patternTree in device level. Currently, devices with + * isAligned!=null will be filtered out. + * + * @param patternTree devices' pattern + * @param authorityScope the scope of the authority + * @return pattern tree with all leaves as device nodes + */ + ClusterSchemaTree fetchDeviceSchema(PathPatternTree patternTree, PathPatternTree authorityScope) throws MetadataException; // endregion diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionMemoryImpl.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionMemoryImpl.java index b7c7257b88034..dcf21c36e2409 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionMemoryImpl.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionMemoryImpl.java @@ -219,6 +219,7 @@ public synchronized void init() throws MetadataException { new MTreeBelowSGMemoryImpl( new PartialPath(storageGroupFullPath), tagManager::readTags, + tagManager::readAttributes, regionStatistics, metric); @@ -530,7 +531,8 @@ public void loadSnapshot(File latestSnapshotRootDir) { regionStatistics.activateTemplate(deviceMNode.getSchemaTemplateId()); } }, - tagManager::readTags); + tagManager::readTags, + tagManager::readAttributes); logger.info( "MTree snapshot loading of schemaRegion {} costs {}ms.", schemaRegionId, @@ -969,23 +971,34 @@ public MeasurementPath fetchMeasurementPath(PartialPath fullPath) throws Metadat } @Override - public ClusterSchemaTree fetchSchema( + public ClusterSchemaTree fetchSeriesSchema( PathPatternTree patternTree, Map templateMap, boolean withTags, - boolean withTemplate) + boolean withAttributes, + boolean withTemplate, + boolean withAliasForce) throws MetadataException { if (patternTree.isContainWildcard()) { ClusterSchemaTree schemaTree = new ClusterSchemaTree(); for (PartialPath path : patternTree.getAllPathPatterns()) { - schemaTree.mergeSchemaTree(mtree.fetchSchema(path, templateMap, withTags, withTemplate)); + schemaTree.mergeSchemaTree( + mtree.fetchSchema( + path, templateMap, withTags, withAttributes, withTemplate, withAliasForce)); } return schemaTree; } else { - return mtree.fetchSchemaWithoutWildcard(patternTree, templateMap, withTags, withTemplate); + return mtree.fetchSchemaWithoutWildcard( + patternTree, templateMap, withTags, withAttributes, withTemplate); } } + @Override + public ClusterSchemaTree fetchDeviceSchema( + PathPatternTree patternTree, PathPatternTree authorityScope) throws MetadataException { + return mtree.fetchDeviceSchema(patternTree, authorityScope); + } + // endregion // endregion diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionPBTreeImpl.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionPBTreeImpl.java index c1ec3c37df5b9..714bf8dec91a5 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionPBTreeImpl.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/impl/SchemaRegionPBTreeImpl.java @@ -212,6 +212,7 @@ public synchronized void init() throws MetadataException { new MTreeBelowSGCachedImpl( new PartialPath(storageGroupFullPath), tagManager::readTags, + tagManager::readAttributes, this::flushCallback, measurementInitProcess(), deviceInitProcess(), @@ -550,6 +551,7 @@ public void loadSnapshot(File latestSnapshotRootDir) { measurementInitProcess(), deviceInitProcess(), tagManager::readTags, + tagManager::readAttributes, this::flushCallback); logger.info( "MTree snapshot loading of schemaRegion {} costs {}ms.", @@ -1028,23 +1030,34 @@ public MeasurementPath fetchMeasurementPath(PartialPath fullPath) throws Metadat } @Override - public ClusterSchemaTree fetchSchema( + public ClusterSchemaTree fetchSeriesSchema( PathPatternTree patternTree, Map templateMap, boolean withTags, - boolean withTemplate) + boolean withAttributes, + boolean withTemplate, + boolean withAliasForcete) throws MetadataException { if (patternTree.isContainWildcard()) { ClusterSchemaTree schemaTree = new ClusterSchemaTree(); for (PartialPath path : patternTree.getAllPathPatterns()) { - schemaTree.mergeSchemaTree(mtree.fetchSchema(path, templateMap, withTags, withTemplate)); + schemaTree.mergeSchemaTree( + mtree.fetchSchema( + path, templateMap, withTags, withAttributes, withTemplate, withAliasForcete)); } return schemaTree; } else { - return mtree.fetchSchemaWithoutWildcard(patternTree, templateMap, withTags, withTemplate); + return mtree.fetchSchemaWithoutWildcard( + patternTree, templateMap, withTags, withAttributes, withTemplate); } } + @Override + public ClusterSchemaTree fetchDeviceSchema( + PathPatternTree patternTree, PathPatternTree authorityScope) throws MetadataException { + return mtree.fetchDeviceSchema(patternTree, authorityScope); + } + // endregion // endregion diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/MTreeBelowSGMemoryImpl.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/MTreeBelowSGMemoryImpl.java index 4abd4b1c52960..80ac04e9d9feb 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/MTreeBelowSGMemoryImpl.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/mem/MTreeBelowSGMemoryImpl.java @@ -128,6 +128,7 @@ public class MTreeBelowSGMemoryImpl { private final IMemMNode rootNode; private final Function, Map> tagGetter; + private final Function, Map> attributeGetter; private final IMNodeFactory nodeFactory = MNodeFactoryLoader.getInstance().getMemMNodeIMNodeFactory(); private final int levelOfSG; @@ -137,6 +138,7 @@ public class MTreeBelowSGMemoryImpl { public MTreeBelowSGMemoryImpl( PartialPath storageGroupPath, Function, Map> tagGetter, + Function, Map> attributeGetter, MemSchemaRegionStatistics regionStatistics, SchemaRegionMemMetric metric) { store = new MemMTreeStore(storageGroupPath, regionStatistics, metric); @@ -145,12 +147,14 @@ public MTreeBelowSGMemoryImpl( this.rootNode = store.generatePrefix(storageGroupPath); levelOfSG = storageGroupPath.getNodeLength() - 1; this.tagGetter = tagGetter; + this.attributeGetter = attributeGetter; } private MTreeBelowSGMemoryImpl( PartialPath storageGroupPath, MemMTreeStore store, Function, Map> tagGetter, + Function, Map> attributeGetter, MemSchemaRegionStatistics regionStatistics) { this.store = store; this.regionStatistics = regionStatistics; @@ -158,6 +162,7 @@ private MTreeBelowSGMemoryImpl( this.rootNode = store.generatePrefix(storageGroupPath); levelOfSG = storageGroupPath.getNodeLength() - 1; this.tagGetter = tagGetter; + this.attributeGetter = attributeGetter; } public void clear() { @@ -176,13 +181,15 @@ public static MTreeBelowSGMemoryImpl loadFromSnapshot( SchemaRegionMemMetric metric, Consumer> measurementProcess, Consumer> deviceProcess, - Function, Map> tagGetter) + Function, Map> tagGetter, + Function, Map> attributeGetter) throws IOException, IllegalPathException { return new MTreeBelowSGMemoryImpl( new PartialPath(storageGroupFullPath), MemMTreeStore.loadFromSnapshot( snapshotDir, measurementProcess, deviceProcess, regionStatistics, metric), tagGetter, + attributeGetter, regionStatistics); } @@ -701,7 +708,9 @@ public ClusterSchemaTree fetchSchema( PartialPath pathPattern, Map templateMap, boolean withTags, - boolean withTemplate) + boolean withAttributes, + boolean withTemplate, + boolean withAliasForce) throws MetadataException { ClusterSchemaTree schemaTree = new ClusterSchemaTree(); try (MeasurementCollector collector = @@ -716,14 +725,15 @@ protected Void collectMeasurement(IMeasurementMNode node) { skipTemplateChildren(deviceMNode); } else { MeasurementPath path = getCurrentMeasurementPathInTraverse(node); - if (nodes[nodes.length - 1].equals(node.getAlias())) { - // only when user query with alias, the alias in path will be set - path.setMeasurementAlias(node.getAlias()); - } - if (withTags) { - path.setTagMap(tagGetter.apply(node)); - } - schemaTree.appendSingleMeasurementPath(path); + schemaTree.appendSingleMeasurement( + path, + path.getMeasurementSchema(), + withTags ? tagGetter.apply(node) : null, + withAttributes ? attributeGetter.apply(node) : null, + withAliasForce || nodes[nodes.length - 1].equals(node.getAlias()) + ? node.getAlias() + : null, + deviceMNode.isAligned()); } return null; } @@ -739,6 +749,7 @@ public ClusterSchemaTree fetchSchemaWithoutWildcard( PathPatternTree patternTree, Map templateMap, boolean withTags, + boolean withAttributes, boolean withTemplate) throws MetadataException { ClusterSchemaTree schemaTree = new ClusterSchemaTree(); @@ -754,11 +765,13 @@ protected Void collectMeasurement(IMeasurementMNode node) { skipTemplateChildren(deviceMNode); } else { MeasurementPath path = getCurrentMeasurementPathInTraverse(node); - path.setMeasurementAlias(node.getAlias()); - if (withTags) { - path.setTagMap(tagGetter.apply(node)); - } - schemaTree.appendSingleMeasurementPath(path); + schemaTree.appendSingleMeasurement( + path, + path.getMeasurementSchema(), + withTags ? tagGetter.apply(node) : null, + withAttributes ? attributeGetter.apply(node) : null, + node.getAlias(), + deviceMNode.isAligned()); } return null; } @@ -770,6 +783,27 @@ protected Void collectMeasurement(IMeasurementMNode node) { return schemaTree; } + public ClusterSchemaTree fetchDeviceSchema( + PathPatternTree patternTree, PathPatternTree authorityScope) throws MetadataException { + ClusterSchemaTree schemaTree = new ClusterSchemaTree(); + for (PartialPath pattern : patternTree.getAllPathPatterns()) { + try (EntityCollector collector = + new EntityCollector(rootNode, pattern, store, false, authorityScope) { + @Override + protected Void collectEntity(IDeviceMNode node) { + if (node.isAlignedNullable() != null) { + schemaTree.appendTemplateDevice( + node.getPartialPath(), node.isAligned(), node.getSchemaTemplateId(), null); + } + return null; + } + }) { + collector.traverse(); + } + } + return schemaTree; + } + // endregion // region Interfaces and Implementation for MNode Query diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/pbtree/MTreeBelowSGCachedImpl.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/pbtree/MTreeBelowSGCachedImpl.java index d2ef703ee7f25..12af832364c62 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/pbtree/MTreeBelowSGCachedImpl.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/mtree/impl/pbtree/MTreeBelowSGCachedImpl.java @@ -121,6 +121,7 @@ public class MTreeBelowSGCachedImpl { private final ICachedMNode rootNode; private final Function, Map> tagGetter; + private final Function, Map> attributeGetter; private final IMNodeFactory nodeFactory = MNodeFactoryLoader.getInstance().getCachedMNodeIMNodeFactory(); private final int levelOfSG; @@ -130,6 +131,7 @@ public class MTreeBelowSGCachedImpl { public MTreeBelowSGCachedImpl( PartialPath storageGroupPath, Function, Map> tagGetter, + Function, Map> attributeGetter, Runnable flushCallback, Consumer> measurementProcess, Consumer> deviceProcess, @@ -138,6 +140,7 @@ public MTreeBelowSGCachedImpl( SchemaRegionCachedMetric metric) throws MetadataException, IOException { this.tagGetter = tagGetter; + this.attributeGetter = attributeGetter; this.regionStatistics = regionStatistics; store = PBTreeFactory.getInstance() @@ -177,6 +180,7 @@ private MTreeBelowSGCachedImpl( Consumer> measurementProcess, Consumer> deviceProcess, Function, Map> tagGetter, + Function, Map> attributeGetter, CachedSchemaRegionStatistics regionStatistics) throws MetadataException { this.store = store; @@ -185,6 +189,7 @@ private MTreeBelowSGCachedImpl( this.rootNode = store.generatePrefix(storageGroupPath); levelOfSG = storageGroupMNode.getPartialPath().getNodeLength() - 1; this.tagGetter = tagGetter; + this.attributeGetter = attributeGetter; // recover MNode try (MNodeCollector collector = @@ -226,6 +231,7 @@ public static MTreeBelowSGCachedImpl loadFromSnapshot( Consumer> measurementProcess, Consumer> deviceProcess, Function, Map> tagGetter, + Function, Map> attributeGetter, Runnable flushCallback) throws IOException, MetadataException { return new MTreeBelowSGCachedImpl( @@ -241,6 +247,7 @@ public static MTreeBelowSGCachedImpl loadFromSnapshot( measurementProcess, deviceProcess, tagGetter, + attributeGetter, regionStatistics); } @@ -818,7 +825,9 @@ public ClusterSchemaTree fetchSchema( PartialPath pathPattern, Map templateMap, boolean withTags, - boolean withTemplate) + boolean withAttributes, + boolean withTemplate, + boolean withAliasForce) throws MetadataException { ClusterSchemaTree schemaTree = new ClusterSchemaTree(); try (MeasurementCollector collector = @@ -834,14 +843,15 @@ protected Void collectMeasurement(IMeasurementMNode node) { skipTemplateChildren(deviceMNode); } else { MeasurementPath path = getCurrentMeasurementPathInTraverse(node); - if (nodes[nodes.length - 1].equals(node.getAlias())) { - // only when user query with alias, the alias in path will be set - path.setMeasurementAlias(node.getAlias()); - } - if (withTags) { - path.setTagMap(tagGetter.apply(node)); - } - schemaTree.appendSingleMeasurementPath(path); + schemaTree.appendSingleMeasurement( + path, + path.getMeasurementSchema(), + withTags ? tagGetter.apply(node) : null, + withAttributes ? attributeGetter.apply(node) : null, + withAliasForce || nodes[nodes.length - 1].equals(node.getAlias()) + ? node.getAlias() + : null, + deviceMNode.isAligned()); } return null; } @@ -857,6 +867,7 @@ public ClusterSchemaTree fetchSchemaWithoutWildcard( PathPatternTree patternTree, Map templateMap, boolean withTags, + boolean withAttributes, boolean withTemplate) throws MetadataException { ClusterSchemaTree schemaTree = new ClusterSchemaTree(); @@ -873,11 +884,13 @@ protected Void collectMeasurement(IMeasurementMNode node) { skipTemplateChildren(deviceMNode); } else { MeasurementPath path = getCurrentMeasurementPathInTraverse(node); - path.setMeasurementAlias(node.getAlias()); - if (withTags) { - path.setTagMap(tagGetter.apply(node)); - } - schemaTree.appendSingleMeasurementPath(path); + schemaTree.appendSingleMeasurement( + path, + path.getMeasurementSchema(), + withTags ? tagGetter.apply(node) : null, + withAttributes ? attributeGetter.apply(node) : null, + node.getAlias(), + deviceMNode.isAligned()); } return null; } @@ -889,6 +902,27 @@ protected Void collectMeasurement(IMeasurementMNode node) { return schemaTree; } + public ClusterSchemaTree fetchDeviceSchema( + PathPatternTree patternTree, PathPatternTree authorityScope) throws MetadataException { + ClusterSchemaTree schemaTree = new ClusterSchemaTree(); + for (PartialPath pattern : patternTree.getAllPathPatterns()) { + try (EntityCollector collector = + new EntityCollector(rootNode, pattern, store, false, authorityScope) { + @Override + protected Void collectEntity(IDeviceMNode node) { + if (node.isAlignedNullable() != null) { + schemaTree.appendTemplateDevice( + node.getPartialPath(), node.isAligned(), node.getSchemaTemplateId(), null); + } + return null; + } + }) { + collector.traverse(); + } + } + return schemaTree; + } + // endregion // region Interfaces and Implementation for MNode Query diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/tag/TagManager.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/tag/TagManager.java index 2643635731b3a..d184c4647f1d3 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/tag/TagManager.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/schemaengine/schemaregion/tag/TagManager.java @@ -739,6 +739,21 @@ public Map readTags(IMeasurementMNode node) { } } + /** + * Read the attributes of this node. + * + * @param node the node to query. + * @return the attribute key-value map. + * @throws RuntimeException If any IOException happens. + */ + public Map readAttributes(IMeasurementMNode node) { + try { + return readTagFile(node.getOffset()).getRight(); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + public void clear() throws IOException { this.tagIndex.clear(); if (tagLogFile != null) { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/DataNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/DataNode.java index db8abad45ea3b..41bee29aa943b 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/DataNode.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/DataNode.java @@ -33,7 +33,6 @@ import org.apache.iotdb.commons.consensus.ConsensusGroupId; import org.apache.iotdb.commons.exception.IllegalPathException; import org.apache.iotdb.commons.exception.StartupException; -import org.apache.iotdb.commons.file.SystemFileFactory; import org.apache.iotdb.commons.pipe.config.PipeConfig; import org.apache.iotdb.commons.pipe.plugin.meta.PipePluginMeta; import org.apache.iotdb.commons.service.JMXService; @@ -60,13 +59,14 @@ import org.apache.iotdb.confignode.rpc.thrift.TSystemConfigurationResp; import org.apache.iotdb.consensus.ConsensusFactory; import org.apache.iotdb.db.conf.DataNodeStartupCheck; +import org.apache.iotdb.db.conf.DataNodeSystemPropertiesHandler; import org.apache.iotdb.db.conf.IoTDBConfig; import org.apache.iotdb.db.conf.IoTDBDescriptor; import org.apache.iotdb.db.conf.IoTDBStartCheck; import org.apache.iotdb.db.conf.rest.IoTDBRestServiceDescriptor; import org.apache.iotdb.db.consensus.DataRegionConsensusImpl; import org.apache.iotdb.db.consensus.SchemaRegionConsensusImpl; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.protocol.client.ConfigNodeClient; import org.apache.iotdb.db.protocol.client.ConfigNodeClientManager; import org.apache.iotdb.db.protocol.client.ConfigNodeInfo; @@ -124,6 +124,7 @@ import java.util.stream.Collectors; import static org.apache.iotdb.commons.conf.IoTDBConstant.DEFAULT_CLUSTER_NAME; +import static org.apache.iotdb.db.conf.IoTDBStartCheck.PROPERTIES_FILE_NAME; public class DataNode implements DataNodeMBean { @@ -137,10 +138,6 @@ public class DataNode implements DataNodeMBean { IoTDBConstant.JMX_TYPE, ServiceType.DATA_NODE.getJmxName()); - private static File SYSTEM_PROPERTIES = - SystemFileFactory.INSTANCE.getFile( - config.getSystemDir() + File.separator + IoTDBStartCheck.PROPERTIES_FILE_NAME); - /** * When joining a cluster or getting configuration this node will retry at most "DEFAULT_RETRY" * times before returning a failure to the client. @@ -171,10 +168,12 @@ private DataNode() { // TODO: This needs removal of statics ... public static void reinitializeStatics() { - SYSTEM_PROPERTIES = - SystemFileFactory.INSTANCE.getFile( - config.getSystemDir() + File.separator + IoTDBStartCheck.PROPERTIES_FILE_NAME); registerManager = new RegisterManager(); + DataNodeSystemPropertiesHandler.getInstance() + .resetFilePath( + IoTDBDescriptor.getInstance().getConfig().getSystemDir() + + File.separator + + PROPERTIES_FILE_NAME); } private static RegisterManager registerManager = new RegisterManager(); @@ -196,10 +195,11 @@ protected void doAddNode() { isFirstStart = prepareDataNode(); if (isFirstStart) { - // Set target ConfigNodeList from iotdb-system.properties file + logger.info("DataNode is starting for the first time..."); ConfigNodeInfo.getInstance() .updateConfigNodeList(Collections.singletonList(config.getSeedConfigNode())); } else { + logger.info("DataNode is restarting..."); // Load registered ConfigNodes from system.properties ConfigNodeInfo.getInstance().loadConfigNodeList(); } @@ -208,8 +208,11 @@ protected void doAddNode() { pullAndCheckSystemConfigurations(); if (isFirstStart) { + sendRegisterRequestToConfigNode(true); + IoTDBStartCheck.getInstance().generateOrOverwriteSystemPropertiesFile(); + ConfigNodeInfo.getInstance().storeConfigNodeList(); // Register this DataNode to the cluster when first start - sendRegisterRequestToConfigNode(); + sendRegisterRequestToConfigNode(false); } else { // Send restart request of this DataNode sendRestartRequestToConfigNode(); @@ -234,11 +237,6 @@ protected void doAddNode() { } catch (StartupException | IOException e) { logger.error("Fail to start server", e); - if (isFirstStart) { - // Delete the system.properties file when first start failed. - // Therefore, the next time this DataNode is start will still be seen as the first time. - SYSTEM_PROPERTIES.deleteOnExit(); - } stop(); System.exit(-1); } @@ -248,9 +246,8 @@ protected void doAddNode() { private boolean prepareDataNode() throws StartupException, IOException { long startTime = System.currentTimeMillis(); - // Notice: Consider this DataNode as first start if the system.properties file doesn't exist - IoTDBStartCheck.getInstance().checkOldSystemConfig(); - boolean isFirstStart = IoTDBStartCheck.getInstance().checkIsFirstStart(); + // Init system properties handler + IoTDBStartCheck.checkOldSystemConfig(); // Set this node thisNode.setIp(config.getInternalAddress()); @@ -261,7 +258,7 @@ private boolean prepareDataNode() throws StartupException, IOException { checks.startUpCheck(); long endTime = System.currentTimeMillis(); logger.info("The DataNode is prepared successfully, which takes {} ms", (endTime - startTime)); - return isFirstStart; + return DataNodeSystemPropertiesHandler.getInstance().isFirstStart(); } /** @@ -287,9 +284,7 @@ private void pullAndCheckSystemConfigurations() throws StartupException { configurationResp = configNodeClient.getSystemConfiguration(); break; } catch (TException | ClientManagerException e) { - logger.warn( - "Cannot pull system configurations from ConfigNode-leader, because: {}", - e.getMessage()); + logger.warn("Cannot pull system configurations from ConfigNode-leader", e); retry--; } @@ -401,15 +396,18 @@ private void storeRuntimeConfigurations( /** * Register this DataNode into cluster. * + * @param isPreCheck do pre-check before formal registration * @throws StartupException if register failed. - * @throws IOException if serialize cluster name and dataNode Id failed. + * @throws IOException if serialize cluster name and datanode id failed. */ - private void sendRegisterRequestToConfigNode() throws StartupException, IOException { + private void sendRegisterRequestToConfigNode(boolean isPreCheck) + throws StartupException, IOException { logger.info("Sending register request to ConfigNode-leader..."); long startTime = System.currentTimeMillis(); /* Send register request */ int retry = DEFAULT_RETRY; TDataNodeRegisterReq req = new TDataNodeRegisterReq(); + req.setPreCheck(isPreCheck); req.setDataNodeConfiguration(generateDataNodeConfiguration()); req.setClusterName(config.getClusterName()); req.setVersionInfo(new TNodeVersionInfo(IoTDBConstant.VERSION, IoTDBConstant.BUILD_INFO)); @@ -442,7 +440,10 @@ private void sendRegisterRequestToConfigNode() throws StartupException, IOExcept } if (dataNodeRegisterResp.getStatus().getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { - + if (isPreCheck) { + logger.info("Successfully pass the precheck, will do the formal registration soon."); + return; + } /* Store runtime configurations when register success */ int dataNodeID = dataNodeRegisterResp.getDataNodeId(); config.setDataNodeId(dataNodeID); @@ -452,6 +453,7 @@ private void sendRegisterRequestToConfigNode() throws StartupException, IOExcept storeRuntimeConfigurations( dataNodeRegisterResp.getConfigNodeList(), dataNodeRegisterResp.getRuntimeConfiguration()); long endTime = System.currentTimeMillis(); + logger.info( "Successfully register to the cluster: {} , which takes {} ms.", config.getClusterName(), @@ -657,7 +659,7 @@ private void setUp() throws StartupException { // Register subscription agent before pipe agent registerManager.register(SubscriptionAgent.runtime()); - registerManager.register(PipeAgent.runtime()); + registerManager.register(PipeDataNodeAgent.runtime()); } /** Set up RPC and protocols after DataNode is available */ @@ -957,7 +959,7 @@ private void getTriggerInformationList(List allTriggerInformation) { private void preparePipeResources() throws StartupException { long startTime = System.currentTimeMillis(); - PipeAgent.runtime().preparePipeResources(resourcesInformationHolder); + PipeDataNodeAgent.runtime().preparePipeResources(resourcesInformationHolder); long endTime = System.currentTimeMillis(); logger.info("Prepare pipe resources successfully, which takes {} ms.", (endTime - startTime)); } @@ -1043,7 +1045,7 @@ private void initProtocols() throws StartupException { registerManager.register(RestService.getInstance()); } if (PipeConfig.getInstance().getPipeAirGapReceiverEnabled()) { - registerManager.register(PipeAgent.receiver().airGap()); + registerManager.register(PipeDataNodeAgent.receiver().airGap()); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/metrics/DataNodeMetricsHelper.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/metrics/DataNodeMetricsHelper.java index ade06cb875f55..e5e3f27f5c14e 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/metrics/DataNodeMetricsHelper.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/service/metrics/DataNodeMetricsHelper.java @@ -34,12 +34,13 @@ import org.apache.iotdb.db.queryengine.metric.DataExchangeCostMetricSet; import org.apache.iotdb.db.queryengine.metric.DataExchangeCountMetricSet; import org.apache.iotdb.db.queryengine.metric.DriverSchedulerMetricSet; -import org.apache.iotdb.db.queryengine.metric.LoadTsFileMemMetricSet; import org.apache.iotdb.db.queryengine.metric.QueryExecutionMetricSet; import org.apache.iotdb.db.queryengine.metric.QueryPlanCostMetricSet; import org.apache.iotdb.db.queryengine.metric.QueryRelatedResourceMetricSet; import org.apache.iotdb.db.queryengine.metric.QueryResourceMetricSet; import org.apache.iotdb.db.queryengine.metric.SeriesScanCostMetricSet; +import org.apache.iotdb.db.queryengine.metric.load.LoadTsFileCostMetricsSet; +import org.apache.iotdb.db.queryengine.metric.load.LoadTsFileMemMetricSet; import org.apache.iotdb.db.subscription.metric.SubscriptionMetrics; import org.apache.iotdb.metrics.metricsets.UpTimeMetrics; import org.apache.iotdb.metrics.metricsets.disk.DiskMetrics; @@ -93,6 +94,9 @@ public static void bind() { // bind subscription related metrics MetricService.getInstance().addMetricSet(SubscriptionMetrics.getInstance()); + + // bind load related metrics + MetricService.getInstance().addMetricSet(LoadTsFileCostMetricsSet.getInstance()); } private static void initSystemMetrics() { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/StorageEngine.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/StorageEngine.java index d26304e113cce..e30069f70f001 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/StorageEngine.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/StorageEngine.java @@ -713,7 +713,13 @@ public void deleteDataRegion(DataRegionId regionId) { region.abortCompaction(); region.syncDeleteDataFiles(); region.deleteFolder(systemDir); - if (CONFIG.getDataRegionConsensusProtocolClass().equals(ConsensusFactory.IOT_CONSENSUS)) { + if (CONFIG.getDataRegionConsensusProtocolClass().equals(ConsensusFactory.IOT_CONSENSUS) + || CONFIG + .getDataRegionConsensusProtocolClass() + .equals(ConsensusFactory.FAST_IOT_CONSENSUS) + || CONFIG + .getDataRegionConsensusProtocolClass() + .equals(ConsensusFactory.IOT_CONSENSUS_V2)) { // delete wal WALManager.getInstance() .deleteWALNode( diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/DataRegion.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/DataRegion.java index 2d9a7bed20c04..6ae9fb0f568e6 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/DataRegion.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/DataRegion.java @@ -47,6 +47,7 @@ import org.apache.iotdb.db.exception.query.QueryProcessException; import org.apache.iotdb.db.exception.quota.ExceedQuotaException; import org.apache.iotdb.db.pipe.extractor.dataregion.realtime.listener.PipeInsertionDataNodeListener; +import org.apache.iotdb.db.queryengine.common.DeviceContext; import org.apache.iotdb.db.queryengine.execution.fragment.QueryContext; import org.apache.iotdb.db.queryengine.execution.load.LoadTsFileRateLimiter; import org.apache.iotdb.db.queryengine.metric.QueryResourceMetricSet; @@ -1871,7 +1872,7 @@ private List getFileHandleListForQuery( @Override public IQueryDataSource queryForDeviceRegionScan( - Map devicePathToAligned, + Map devicePathToAligned, QueryContext queryContext, Filter globalTimeFilter, List timePartitions) @@ -1906,7 +1907,7 @@ public IQueryDataSource queryForDeviceRegionScan( private List getFileHandleListForQuery( Collection tsFileResources, - Map devicePathToAligned, + Map devicePathsToContext, QueryContext context, Filter globalTimeFilter, boolean isSeq) @@ -1924,7 +1925,7 @@ private List getFileHandleListForQuery( } else { tsFileResource .getProcessor() - .queryForDeviceRegionScan(devicePathToAligned, context, fileScanHandles); + .queryForDeviceRegionScan(devicePathsToContext, context, fileScanHandles); } } finally { closeQueryLock.readLock().unlock(); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/IDataRegionForQuery.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/IDataRegionForQuery.java index c9dc96b207423..c94a62c85662d 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/IDataRegionForQuery.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/IDataRegionForQuery.java @@ -20,6 +20,7 @@ import org.apache.iotdb.commons.path.IFullPath; import org.apache.iotdb.db.exception.query.QueryProcessException; +import org.apache.iotdb.db.queryengine.common.DeviceContext; import org.apache.iotdb.db.queryengine.execution.fragment.QueryContext; import org.apache.iotdb.db.storageengine.dataregion.read.IQueryDataSource; import org.apache.iotdb.db.storageengine.dataregion.read.QueryDataSource; @@ -49,7 +50,7 @@ QueryDataSource query( /** Get satisfied QueryDataSource from DataRegion for regionScan */ IQueryDataSource queryForDeviceRegionScan( - Map devicePathToAligned, + Map devicePathsToContext, QueryContext queryContext, Filter globalTimeFilter, List timePartitions) diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/VirtualDataRegion.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/VirtualDataRegion.java index 9476c6935981f..8131453937a23 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/VirtualDataRegion.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/VirtualDataRegion.java @@ -20,6 +20,7 @@ import org.apache.iotdb.commons.path.IFullPath; import org.apache.iotdb.db.exception.query.QueryProcessException; +import org.apache.iotdb.db.queryengine.common.DeviceContext; import org.apache.iotdb.db.queryengine.execution.fragment.QueryContext; import org.apache.iotdb.db.storageengine.dataregion.read.IQueryDataSource; import org.apache.iotdb.db.storageengine.dataregion.read.QueryDataSource; @@ -73,7 +74,7 @@ public QueryDataSource query( @Override public IQueryDataSource queryForDeviceRegionScan( - Map devicePathToAligned, + Map devicePathsToContext, QueryContext queryContext, Filter globalTimeFilter, List timePartitions) diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/exception/CompactionLastTimeCheckFailedException.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/exception/CompactionLastTimeCheckFailedException.java index 6ffcfad8cabc7..26458513ba889 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/exception/CompactionLastTimeCheckFailedException.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/exception/CompactionLastTimeCheckFailedException.java @@ -19,6 +19,10 @@ package org.apache.iotdb.db.storageengine.dataregion.compaction.execute.exception; +import org.apache.iotdb.commons.conf.IoTDBConstant; + +import org.apache.tsfile.file.metadata.IDeviceID; + public class CompactionLastTimeCheckFailedException extends RuntimeException { public CompactionLastTimeCheckFailedException( @@ -32,6 +36,19 @@ public CompactionLastTimeCheckFailedException( + lastTimestamp); } + public CompactionLastTimeCheckFailedException( + IDeviceID device, String measurement, long currentTimestamp, long lastTimestamp) { + super( + "Timestamp of the current point of " + + device + + IoTDBConstant.PATH_SEPARATOR + + measurement + + " is " + + currentTimestamp + + ", which should be later than the last time " + + lastTimestamp); + } + @Override public Throwable fillInStackTrace() { return this; diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/exception/CompactionValidationFailedException.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/exception/CompactionValidationFailedException.java index 86b9eb4219c4a..b60dd6845fe37 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/exception/CompactionValidationFailedException.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/exception/CompactionValidationFailedException.java @@ -21,22 +21,24 @@ import org.apache.iotdb.db.storageengine.dataregion.tsfile.TsFileResource; +import java.util.List; + public class CompactionValidationFailedException extends RuntimeException { - private TsFileResource overlappedTsFileResource = null; + private List overlappedTsFileResources = null; public CompactionValidationFailedException(String msg) { super(msg); } - public CompactionValidationFailedException(TsFileResource overlappedTsFileResource) { + public CompactionValidationFailedException(List overlappedTsFileResources) { super( "Failed to pass compaction validation, sequence files has overlap, file is " - + overlappedTsFileResource); - this.overlappedTsFileResource = overlappedTsFileResource; + + overlappedTsFileResources); + this.overlappedTsFileResources = overlappedTsFileResources; } - public TsFileResource getOverlappedTsFileResource() { - return overlappedTsFileResource; + public List getOverlappedTsFileResources() { + return overlappedTsFileResources; } @Override diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/performer/impl/ReadChunkCompactionPerformer.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/performer/impl/ReadChunkCompactionPerformer.java index 2187a442b6d24..f6d1909a2a793 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/performer/impl/ReadChunkCompactionPerformer.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/performer/impl/ReadChunkCompactionPerformer.java @@ -21,13 +21,11 @@ import org.apache.iotdb.commons.exception.IllegalPathException; import org.apache.iotdb.commons.exception.MetadataException; -import org.apache.iotdb.commons.path.PartialPath; import org.apache.iotdb.db.conf.IoTDBDescriptor; import org.apache.iotdb.db.exception.StorageEngineException; import org.apache.iotdb.db.storageengine.dataregion.compaction.execute.exception.CompactionTargetFileCountExceededException; import org.apache.iotdb.db.storageengine.dataregion.compaction.execute.performer.ISeqCompactionPerformer; import org.apache.iotdb.db.storageengine.dataregion.compaction.execute.task.CompactionTaskSummary; -import org.apache.iotdb.db.storageengine.dataregion.compaction.execute.utils.CompactionPathUtils; import org.apache.iotdb.db.storageengine.dataregion.compaction.execute.utils.CompactionTableSchemaCollector; import org.apache.iotdb.db.storageengine.dataregion.compaction.execute.utils.MultiTsFileDeviceIterator; import org.apache.iotdb.db.storageengine.dataregion.compaction.execute.utils.executor.readchunk.ReadChunkAlignedSeriesCompactionExecutor; @@ -186,9 +184,8 @@ private void compactNotAlignedSeries( deviceIterator.iterateNotAlignedSeriesAndChunkMetadataListOfCurrentDevice(); while (seriesIterator.hasNextSeries()) { checkThreadInterrupted(); - String series = seriesIterator.nextSeries(); + String measurement = seriesIterator.nextSeries(); // TODO: we can provide a configuration item to enable concurrent between each series - PartialPath path = CompactionPathUtils.getPath(device, series); LinkedList>> readerAndChunkMetadataList = seriesIterator.getMetadataListForCurrentSeries(); // remove the chunk metadata whose data type not match the data type of last chunk @@ -196,7 +193,7 @@ private void compactNotAlignedSeries( filterDataTypeNotMatchedChunkMetadata(readerAndChunkMetadataList); SingleSeriesCompactionExecutor compactionExecutorOfCurrentTimeSeries = new SingleSeriesCompactionExecutor( - path, readerAndChunkMetadataList, writer, targetResource, summary); + device, measurement, readerAndChunkMetadataList, writer, targetResource, summary); compactionExecutorOfCurrentTimeSeries.execute(); } writer.endChunkGroup(); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/task/AbstractCompactionTask.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/task/AbstractCompactionTask.java index 0a1152044aa8a..75556001fd625 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/task/AbstractCompactionTask.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/task/AbstractCompactionTask.java @@ -33,6 +33,7 @@ import org.apache.iotdb.db.storageengine.dataregion.compaction.execute.utils.CompactionUtils; import org.apache.iotdb.db.storageengine.dataregion.compaction.execute.utils.log.CompactionTaskStage; import org.apache.iotdb.db.storageengine.dataregion.compaction.execute.utils.log.TsFileIdentifier; +import org.apache.iotdb.db.storageengine.dataregion.compaction.repair.RepairDataFileScanUtil; import org.apache.iotdb.db.storageengine.dataregion.compaction.schedule.CompactionTaskManager; import org.apache.iotdb.db.storageengine.dataregion.modification.ModificationFile; import org.apache.iotdb.db.storageengine.dataregion.tsfile.TsFileManager; @@ -149,10 +150,10 @@ protected void handleException(Logger logger, Exception e) { } else { CompactionValidationFailedException validationException = (CompactionValidationFailedException) e; - TsFileResource overlappedTsFileResource = validationException.getOverlappedTsFileResource(); - if (overlappedTsFileResource != null) { - unsortedTsFileResources.add(overlappedTsFileResource); - } + List overlappedTsFileResource = + validationException.getOverlappedTsFileResources(); + unsortedTsFileResources = + overlappedTsFileResource == null ? unsortedTsFileResources : overlappedTsFileResource; } // these exceptions generally caused by unsorted data, mark all source files as NEED_TO_REPAIR for (TsFileResource resource : unsortedTsFileResources) { @@ -472,15 +473,15 @@ protected void validateCompactionResult( Long.parseLong(f2.getTsFile().getName().split("-")[1])) : timeDiff; }); - if (!validator.validateTsFilesIsHasNoOverlap(timePartitionSeqFiles)) { + List overlapFilesInTimePartition = + RepairDataFileScanUtil.checkTimePartitionHasOverlap(timePartitionSeqFiles); + if (!overlapFilesInTimePartition.isEmpty()) { LOGGER.error( "Failed to pass compaction validation, source seq files: {}, source unseq files: {}, target files: {}", sourceSeqFiles, sourceUnseqFiles, targetFiles); - throw new CompactionValidationFailedException( - "Failed to pass compaction validation, sequence files has overlap, time partition id is " - + timePartition); + throw new CompactionValidationFailedException(overlapFilesInTimePartition); } } if (needToValidateTsFileCorrectness && !validator.validateTsFiles(validTargetFiles)) { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/utils/CompactionPathUtils.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/utils/CompactionPathUtils.java index 53ba6680c2407..11f3d01952968 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/utils/CompactionPathUtils.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/utils/CompactionPathUtils.java @@ -26,22 +26,13 @@ import org.apache.tsfile.common.constant.TsFileConstant; import org.apache.tsfile.file.metadata.IDeviceID; -import static org.apache.tsfile.common.constant.TsFileConstant.PATH_SEPARATER_NO_REGEX; - public class CompactionPathUtils { private CompactionPathUtils() {} public static PartialPath getPath(IDeviceID device, String measurement) throws IllegalPathException { - PartialPath path; - String plainDeviceId = device.toString(); - if (plainDeviceId.contains(TsFileConstant.BACK_QUOTE_STRING)) { - path = DataNodeDevicePathCache.getInstance().getPartialPath(plainDeviceId); - } else { - path = new PartialPath(device.toString().split(PATH_SEPARATER_NO_REGEX)); - } - return path.concatNode(measurement); + return getPath(device).concatNode(measurement); } public static PartialPath getPath(IDeviceID device) throws IllegalPathException { @@ -50,7 +41,7 @@ public static PartialPath getPath(IDeviceID device) throws IllegalPathException if (plainDeviceId.contains(TsFileConstant.BACK_QUOTE_STRING)) { path = DataNodeDevicePathCache.getInstance().getPartialPath(plainDeviceId); } else { - path = new PartialPath(device.toString().split(PATH_SEPARATER_NO_REGEX)); + path = new PartialPath(plainDeviceId); } return path; } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/utils/MultiTsFileDeviceIterator.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/utils/MultiTsFileDeviceIterator.java index e4906ad716f23..8e70caa741e31 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/utils/MultiTsFileDeviceIterator.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/utils/MultiTsFileDeviceIterator.java @@ -69,6 +69,7 @@ public class MultiTsFileDeviceIterator implements AutoCloseable { private final Map deviceIteratorMap = new HashMap<>(); private final Map> modificationCache = new HashMap<>(); private Pair currentDevice = null; + private long timeLowerBoundForCurrentDevice; /** * Used for compaction with read chunk performer. @@ -173,7 +174,7 @@ public boolean hasNextDevice() { * @return Pair of device full path and whether this device is aligned */ @SuppressWarnings("squid:S135") - public Pair nextDevice() { + public Pair nextDevice() throws IllegalPathException { List toBeRemovedResources = new LinkedList<>(); Pair minDevice = null; // get the device from source files sorted from the newest to the oldest by version @@ -204,6 +205,10 @@ public Pair nextDevice() { for (TsFileResource resource : toBeRemovedResources) { deviceIteratorMap.remove(resource); } + + timeLowerBoundForCurrentDevice = + CommonDateTimeUtils.currentTime() + - DataNodeTTLCache.getInstance().getTTL(currentDevice.getLeft()); return currentDevice; } @@ -397,58 +402,45 @@ private void applyModificationForAlignedChunkMetadataList( // all the value chunks is empty chunk return; } + IDeviceID device = currentDevice.getLeft(); + Deletion ttlDeletion = null; + if (tsFileResource.getStartTime(device) < timeLowerBoundForCurrentDevice) { + ttlDeletion = + new Deletion( + CompactionPathUtils.getPath(device, IoTDBConstant.ONE_LEVEL_PATH_WILDCARD), + Long.MAX_VALUE, + Long.MIN_VALUE, + timeLowerBoundForCurrentDevice); + } List modifications = modificationCache.computeIfAbsent( tsFileResource, - r -> { - List list = - new LinkedList<>(ModificationFile.getNormalMods(r).getModifications()); - // add outdated device mods by ttl - for (IDeviceID device : r.getDevices()) { - // TODO: remove deviceId conversion - long timeLowerBound = - CommonDateTimeUtils.currentTime() - - DataNodeTTLCache.getInstance().getTTL(device); - if (r.getStartTime(device) < timeLowerBound) { - try { - list.add( - new Deletion( - CompactionPathUtils.getPath(device) - .concatNode(IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD), - Long.MAX_VALUE, - Long.MIN_VALUE, - timeLowerBound)); - } catch (IllegalPathException e) { - throw new RuntimeException(e); - } - } - } - return list; - }); + r -> new LinkedList<>(ModificationFile.getNormalMods(r).getModifications())); // construct the input params List> for QueryUtils.modifyAlignedChunkMetaData AlignedChunkMetadata alignedChunkMetadata = alignedChunkMetadataList.get(0); List valueChunkMetadataList = alignedChunkMetadata.getValueChunkMetadataList(); List> modificationForCurDevice = new ArrayList<>(); - List valueSeriesPaths = new ArrayList<>(valueChunkMetadataList.size()); - for (int i = 0; i < valueChunkMetadataList.size(); ++i) { - modificationForCurDevice.add(new ArrayList<>()); - IChunkMetadata valueChunkMetadata = valueChunkMetadataList.get(i); - valueSeriesPaths.add( - valueChunkMetadata == null - ? null - : CompactionPathUtils.getPath( - currentDevice.left, valueChunkMetadata.getMeasurementUid())); - } - - for (Modification modification : modifications) { - for (int i = 0; i < valueChunkMetadataList.size(); ++i) { - PartialPath path = valueSeriesPaths.get(i); - if (path != null && modification.getPath().matchFullPath(path)) { - modificationForCurDevice.get(i).add(modification); + for (IChunkMetadata valueChunkMetadata : valueChunkMetadataList) { + if (valueChunkMetadata == null) { + modificationForCurDevice.add(Collections.emptyList()); + continue; + } + List modificationList = new ArrayList<>(); + PartialPath path = + CompactionPathUtils.getPath( + currentDevice.getLeft(), valueChunkMetadata.getMeasurementUid()); + for (Modification modification : modifications) { + if (modification.getPath().matchFullPath(path)) { + modificationList.add(modification); } } + if (ttlDeletion != null) { + modificationList.add(ttlDeletion); + } + modificationForCurDevice.add( + modificationList.isEmpty() ? Collections.emptyList() : modificationList); } ModificationUtils.modifyAlignedChunkMetaData( @@ -626,17 +618,27 @@ public String nextSeries() throws IllegalPathException { if (seriesInThisIteration.isEmpty()) { return new LinkedList<>(); } + IDeviceID device = currentDevice.getLeft(); currentCompactingSeries = seriesInThisIteration.removeFirst(); LinkedList>> readerAndChunkMetadataForThisSeries = new LinkedList<>(); - PartialPath path = - CompactionPathUtils.getPath(currentDevice.getLeft(), currentCompactingSeries); + PartialPath path = CompactionPathUtils.getPath(device, currentCompactingSeries); for (TsFileResource resource : tsFileResourcesSortedByAsc) { TsFileSequenceReader reader = readerMap.get(resource); Map> chunkMetadataListMap = chunkMetadataCacheMap.get(reader); + Deletion ttlDeletion = null; + if (resource.getStartTime(device) < timeLowerBoundForCurrentDevice) { + ttlDeletion = + new Deletion( + CompactionPathUtils.getPath(device, IoTDBConstant.ONE_LEVEL_PATH_WILDCARD), + Long.MAX_VALUE, + Long.MIN_VALUE, + timeLowerBoundForCurrentDevice); + } + if (chunkMetadataListMap.containsKey(currentCompactingSeries)) { // get the chunk metadata list and modification list of current series in this tsfile List chunkMetadataListInThisResource = @@ -646,31 +648,7 @@ public String nextSeries() throws IllegalPathException { List modificationsInThisResource = modificationCache.computeIfAbsent( resource, - r -> { - List list = - new LinkedList<>(ModificationFile.getNormalMods(r).getModifications()); - // add outdated device mods by ttl - for (IDeviceID device : r.getDevices()) { - // TODO: remove deviceId conversion - long timeLowerBound = - CommonDateTimeUtils.currentTime() - - DataNodeTTLCache.getInstance().getTTL(device); - if (r.getStartTime(device) < timeLowerBound) { - try { - list.add( - new Deletion( - CompactionPathUtils.getPath(device) - .concatNode(IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD), - Long.MAX_VALUE, - Long.MIN_VALUE, - timeLowerBound)); - } catch (IllegalPathException e) { - throw new RuntimeException(e); - } - } - } - return list; - }); + r -> new LinkedList<>(ModificationFile.getNormalMods(r).getModifications())); LinkedList modificationForCurrentSeries = new LinkedList<>(); // collect the modifications for current series for (Modification modification : modificationsInThisResource) { @@ -678,6 +656,10 @@ public String nextSeries() throws IllegalPathException { modificationForCurrentSeries.add(modification); } } + // add ttl deletion for current series + if (ttlDeletion != null) { + modificationForCurrentSeries.add(ttlDeletion); + } // if there are modifications of current series, apply them to the chunk metadata if (!modificationForCurrentSeries.isEmpty()) { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/utils/executor/readchunk/SingleSeriesCompactionExecutor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/utils/executor/readchunk/SingleSeriesCompactionExecutor.java index dd90322e7ebcf..7e85af0a9fe3e 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/utils/executor/readchunk/SingleSeriesCompactionExecutor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/utils/executor/readchunk/SingleSeriesCompactionExecutor.java @@ -19,7 +19,6 @@ package org.apache.iotdb.db.storageengine.dataregion.compaction.execute.utils.executor.readchunk; -import org.apache.iotdb.commons.path.PartialPath; import org.apache.iotdb.db.conf.IoTDBDescriptor; import org.apache.iotdb.db.storageengine.dataregion.compaction.execute.exception.CompactionLastTimeCheckFailedException; import org.apache.iotdb.db.storageengine.dataregion.compaction.execute.task.CompactionTaskSummary; @@ -48,7 +47,7 @@ @SuppressWarnings("squid:S1319") public class SingleSeriesCompactionExecutor { private IDeviceID device; - private PartialPath series; + private String measurement; private LinkedList>> readerAndChunkMetadataList; private CompactionTsFileWriter fileWriter; private TsFileResource targetResource; @@ -74,13 +73,13 @@ public class SingleSeriesCompactionExecutor { IoTDBDescriptor.getInstance().getConfig().getChunkPointNumLowerBoundInCompaction(); public SingleSeriesCompactionExecutor( - PartialPath series, + IDeviceID device, IMeasurementSchema measurementSchema, LinkedList>> readerAndChunkMetadataList, CompactionTsFileWriter fileWriter, TsFileResource targetResource) { - this.device = series.getIDeviceID(); - this.series = series; + this.device = device; + this.measurement = measurementSchema.getMeasurementId(); this.readerAndChunkMetadataList = readerAndChunkMetadataList; this.fileWriter = fileWriter; this.schema = measurementSchema; @@ -92,13 +91,14 @@ public SingleSeriesCompactionExecutor( } public SingleSeriesCompactionExecutor( - PartialPath series, + IDeviceID device, + String measurement, LinkedList>> readerAndChunkMetadataList, CompactionTsFileWriter fileWriter, TsFileResource targetResource, CompactionTaskSummary summary) { - this.device = series.getIDeviceID(); - this.series = series; + this.device = device; + this.measurement = measurement; this.readerAndChunkMetadataList = readerAndChunkMetadataList; this.fileWriter = fileWriter; this.schema = null; @@ -166,7 +166,7 @@ private void constructChunkWriterFromReadChunk(Chunk chunk) { ChunkHeader chunkHeader = chunk.getHeader(); this.schema = new MeasurementSchema( - series.getMeasurement(), + measurement, chunkHeader.getDataType(), chunkHeader.getEncodingType(), chunkHeader.getCompressionType()); @@ -370,7 +370,7 @@ private void flushChunkWriter() throws IOException { private void checkAndUpdatePreviousTimestamp(long currentWritingTimestamp) { if (currentWritingTimestamp <= lastWriteTimestamp) { throw new CompactionLastTimeCheckFailedException( - series.getFullPath(), currentWritingTimestamp, lastWriteTimestamp); + device, measurement, currentWritingTimestamp, lastWriteTimestamp); } else { lastWriteTimestamp = currentWritingTimestamp; } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/utils/executor/readchunk/loader/ChunkLoader.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/utils/executor/readchunk/loader/ChunkLoader.java index c91f1500d9303..856fb868f08b3 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/utils/executor/readchunk/loader/ChunkLoader.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/utils/executor/readchunk/loader/ChunkLoader.java @@ -70,6 +70,9 @@ protected ModifiedStatus calculatePageModifiedStatus(PageHeader pageHeader) { return this.modifiedStatus; } ModifiedStatus pageModifiedStatus = ModifiedStatus.NONE_DELETED; + if (pageHeader.getStatistics() == null || pageHeader.getStatistics().getCount() == 0) { + return pageModifiedStatus; + } List deleteIntervalList = chunkMetadata.getDeleteIntervalList(); long startTime = pageHeader.getStartTime(); long endTime = pageHeader.getEndTime(); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/utils/writer/RepairUnsortedFileCompactionWriter.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/utils/writer/RepairUnsortedFileCompactionWriter.java index 5dce41978c607..3c9c25de6265d 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/utils/writer/RepairUnsortedFileCompactionWriter.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/compaction/execute/utils/writer/RepairUnsortedFileCompactionWriter.java @@ -63,24 +63,22 @@ public void endMeasurement(int subTaskId) throws IOException { mergeTimeValuePair(timeValuePair, previousTimeValuePair); continue; } - writeDataPoint( - previousTimeValuePair.getTimestamp(), - previousTimeValuePair.getValue(), - chunkWriters[subTaskId]); - chunkPointNumArray[subTaskId]++; + writeToChunkWriter(previousTimeValuePair, subTaskId); previousTimeValuePair = timeValuePair; } // write last time value pair - writeDataPoint( - previousTimeValuePair.getTimestamp(), - previousTimeValuePair.getValue(), - chunkWriters[subTaskId]); - chunkPointNumArray[subTaskId]++; + writeToChunkWriter(previousTimeValuePair, subTaskId); dataOfCurrentSeriesArr[subTaskId] = null; super.endMeasurement(subTaskId); } + private void writeToChunkWriter(TimeValuePair timeValuePair, int subTaskId) throws IOException { + writeDataPoint(timeValuePair.getTimestamp(), timeValuePair.getValue(), chunkWriters[subTaskId]); + chunkPointNumArray[subTaskId]++; + checkChunkSizeAndMayOpenANewChunk(fileWriter, chunkWriters[subTaskId], subTaskId); + } + private void mergeTimeValuePair(TimeValuePair from, TimeValuePair to) { if (!isAlign) { // ignore not aligned TimeValuePair with same timestamp diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/TsFileProcessor.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/TsFileProcessor.java index c43078a24e56b..1870aebc3a041 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/TsFileProcessor.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/TsFileProcessor.java @@ -35,8 +35,9 @@ import org.apache.iotdb.db.exception.WriteProcessException; import org.apache.iotdb.db.exception.WriteProcessRejectException; import org.apache.iotdb.db.exception.query.QueryProcessException; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.extractor.dataregion.realtime.listener.PipeInsertionDataNodeListener; +import org.apache.iotdb.db.queryengine.common.DeviceContext; import org.apache.iotdb.db.queryengine.execution.fragment.QueryContext; import org.apache.iotdb.db.queryengine.metric.QueryExecutionMetricSet; import org.apache.iotdb.db.queryengine.metric.QueryResourceMetricSet; @@ -299,7 +300,7 @@ public void insert(InsertRowNode insertRowNode, long[] costsForMetrics) startTime = System.nanoTime(); - PipeAgent.runtime().assignSimpleProgressIndexIfNeeded(insertRowNode); + PipeDataNodeAgent.runtime().assignSimpleProgressIndexIfNeeded(insertRowNode); if (!insertRowNode.isGeneratedByPipe()) { workMemTable.markAsNotGeneratedByPipe(); } @@ -373,7 +374,7 @@ public void insert(InsertRowsNode insertRowsNode, long[] costsForMetrics) startTime = System.nanoTime(); - PipeAgent.runtime().assignSimpleProgressIndexIfNeeded(insertRowsNode); + PipeDataNodeAgent.runtime().assignSimpleProgressIndexIfNeeded(insertRowsNode); if (!insertRowsNode.isGeneratedByPipe()) { workMemTable.markAsNotGeneratedByPipe(); } @@ -484,7 +485,7 @@ public void insertTablet( startTime = System.nanoTime(); - PipeAgent.runtime().assignSimpleProgressIndexIfNeeded(insertTabletNode); + PipeDataNodeAgent.runtime().assignSimpleProgressIndexIfNeeded(insertTabletNode); if (!insertTabletNode.isGeneratedByPipe()) { workMemTable.markAsNotGeneratedByPipe(); } @@ -1875,7 +1876,7 @@ public void queryForSeriesRegionScan( * get the related ChunkMetadata of data on disk. */ public void queryForDeviceRegionScan( - Map devicePathToAligned, + Map devicePathsToContext, QueryContext queryContext, List fileScanHandlesForQuery) { long startTime = System.nanoTime(); @@ -1885,9 +1886,9 @@ public void queryForDeviceRegionScan( new HashMap<>(); flushQueryLock.readLock().lock(); try { - for (Map.Entry entry : devicePathToAligned.entrySet()) { + for (Map.Entry entry : devicePathsToContext.entrySet()) { IDeviceID deviceID = entry.getKey(); - boolean isAligned = entry.getValue(); + boolean isAligned = entry.getValue().isAligned(); long timeLowerBound = getQueryTimeLowerBound(deviceID); Map> measurementToChunkMetadataList = new HashMap<>(); Map> measurementToMemChunkHandleList = new HashMap<>(); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/allocation/AbstractNodeAllocationStrategy.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/allocation/AbstractNodeAllocationStrategy.java index 62c438fcc6917..e98086e514628 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/allocation/AbstractNodeAllocationStrategy.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/allocation/AbstractNodeAllocationStrategy.java @@ -32,7 +32,7 @@ import org.slf4j.LoggerFactory; import java.io.File; -import java.io.FileNotFoundException; +import java.io.IOException; import java.util.Arrays; public abstract class AbstractNodeAllocationStrategy implements NodeAllocationStrategy { @@ -72,8 +72,8 @@ protected IWALNode createWALNode(String identifier) { protected IWALNode createWALNode(String identifier, String folder) { try { return new WALNode(identifier, folder); - } catch (FileNotFoundException e) { - logger.error("Fail to create wal node", e); + } catch (IOException e) { + logger.error("Meet exception when creating wal node", e); return WALFakeNode.getFailureInstance(e); } } @@ -82,7 +82,7 @@ protected IWALNode createWALNode( String identifier, String folder, long startFileVersion, long startSearchIndex) { try { return new WALNode(identifier, folder, startFileVersion, startSearchIndex); - } catch (FileNotFoundException e) { + } catch (IOException e) { logger.error("Fail to create wal node", e); return WALFakeNode.getFailureInstance(e); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/buffer/AbstractWALBuffer.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/buffer/AbstractWALBuffer.java index 08bca5f6649fb..c4c5bc13a3d49 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/buffer/AbstractWALBuffer.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/buffer/AbstractWALBuffer.java @@ -29,7 +29,6 @@ import org.slf4j.LoggerFactory; import java.io.File; -import java.io.FileNotFoundException; import java.io.IOException; import java.nio.file.Files; import java.nio.file.StandardCopyOption; @@ -58,7 +57,7 @@ public abstract class AbstractWALBuffer implements IWALBuffer { protected AbstractWALBuffer( String identifier, String logDirectory, long startFileVersion, long startSearchIndex) - throws FileNotFoundException { + throws IOException { this.identifier = identifier; this.logDirectory = logDirectory; File logDirFile = SystemFileFactory.INSTANCE.getFile(logDirectory); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/buffer/WALBuffer.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/buffer/WALBuffer.java index 7bf33a93f40cb..20970aea34b8f 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/buffer/WALBuffer.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/buffer/WALBuffer.java @@ -42,7 +42,6 @@ import org.slf4j.LoggerFactory; import java.io.File; -import java.io.FileNotFoundException; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.MappedByteBuffer; @@ -119,7 +118,7 @@ public class WALBuffer extends AbstractWALBuffer { // manage wal files which have MemTableIds private final Map> memTableIdsOfWal = new ConcurrentHashMap<>(); - public WALBuffer(String identifier, String logDirectory) throws FileNotFoundException { + public WALBuffer(String identifier, String logDirectory) throws IOException { this(identifier, logDirectory, new CheckpointManager(identifier, logDirectory), 0, 0L); } @@ -129,7 +128,7 @@ public WALBuffer( CheckpointManager checkpointManager, long startFileVersion, long startSearchIndex) - throws FileNotFoundException { + throws IOException { super(identifier, logDirectory, startFileVersion, startSearchIndex); this.checkpointManager = checkpointManager; currentFileStatus = WALFileStatus.CONTAINS_NONE_SEARCH_INDEX; @@ -521,8 +520,9 @@ public void run() { forceFlag, syncingBuffer.position(), syncingBuffer.capacity(), usedRatio * 100); // flush buffer to os + double compressionRatio = 1.0; try { - currentWALFileWriter.write(syncingBuffer, info.metaData); + compressionRatio = currentWALFileWriter.write(syncingBuffer, info.metaData); } catch (Throwable e) { logger.error( "Fail to sync wal node-{}'s buffer, change system mode to error.", identifier, e); @@ -535,12 +535,14 @@ public void run() { memTableIdsOfWal .computeIfAbsent(currentWALFileVersion, memTableIds -> new HashSet<>()) .addAll(info.metaData.getMemTablesId()); - checkpointManager.updateCostOfActiveMemTables(info.memTableId2WalDiskUsage); + checkpointManager.updateCostOfActiveMemTables(info.memTableId2WalDiskUsage, compressionRatio); boolean forceSuccess = false; // try to roll log writer if (info.rollWALFileWriterListener != null - || (forceFlag && currentWALFileWriter.size() >= config.getWalFileSizeThresholdInByte())) { + // TODO: Control the wal file by the number of WALEntry + || (forceFlag + && currentWALFileWriter.originalSize() >= config.getWalFileSizeThresholdInByte())) { try { rollLogWriter(searchIndex, currentWALFileWriter.getWalFileStatus()); forceSuccess = true; @@ -582,7 +584,7 @@ public void run() { position += fsyncListener.getWalEntryHandler().getSize(); } } - lastFsyncPosition = currentWALFileWriter.size(); + lastFsyncPosition = currentWALFileWriter.originalSize(); } WRITING_METRICS.recordWALBufferEntriesCount(info.fsyncListeners.size()); WRITING_METRICS.recordSyncWALBufferCost(System.nanoTime() - startTime, forceFlag); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/checkpoint/CheckpointManager.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/checkpoint/CheckpointManager.java index 8359330754d20..412dfcfc0a0c3 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/checkpoint/CheckpointManager.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/checkpoint/CheckpointManager.java @@ -34,7 +34,6 @@ import org.slf4j.LoggerFactory; import java.io.File; -import java.io.FileNotFoundException; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.file.Files; @@ -78,7 +77,7 @@ public class CheckpointManager implements AutoCloseable { // endregion - public CheckpointManager(String identifier, String logDirectory) throws FileNotFoundException { + public CheckpointManager(String identifier, String logDirectory) throws IOException { this.identifier = identifier; this.logDirectory = logDirectory; File logDirFile = SystemFileFactory.INSTANCE.getFile(logDirectory); @@ -345,12 +344,13 @@ public long getFirstValidWALVersionId() { } /** Update wal disk cost of active memTables. */ - public void updateCostOfActiveMemTables(Map memTableId2WalDiskUsage) { + public void updateCostOfActiveMemTables( + Map memTableId2WalDiskUsage, double compressionRate) { for (Map.Entry memTableWalUsage : memTableId2WalDiskUsage.entrySet()) { memTableId2Info.computeIfPresent( memTableWalUsage.getKey(), (k, v) -> { - v.addWalDiskUsage(memTableWalUsage.getValue()); + v.addWalDiskUsage((long) (memTableWalUsage.getValue() * compressionRate)); return v; }); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/CheckpointReader.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/CheckpointReader.java index 5d2bad0a87407..578ab21ae8c7b 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/CheckpointReader.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/CheckpointReader.java @@ -24,10 +24,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.File; -import java.io.FileInputStream; import java.io.IOException; import java.util.ArrayList; import java.util.List; @@ -47,8 +45,7 @@ public CheckpointReader(File logFile) { private void init() { checkpoints = new ArrayList<>(); - try (DataInputStream logStream = - new DataInputStream(new BufferedInputStream(new FileInputStream(logFile)))) { + try (DataInputStream logStream = new DataInputStream(new WALInputStream(logFile))) { maxMemTableId = logStream.readLong(); while (logStream.available() > 0) { Checkpoint checkpoint = Checkpoint.deserialize(logStream); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/CheckpointWriter.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/CheckpointWriter.java index cd6af49637764..322aa3c9f5d3c 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/CheckpointWriter.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/CheckpointWriter.java @@ -22,11 +22,11 @@ import org.apache.iotdb.db.storageengine.dataregion.wal.checkpoint.Checkpoint; import java.io.File; -import java.io.FileNotFoundException; +import java.io.IOException; /** CheckpointWriter writes the binary {@link Checkpoint} into .checkpoint file. */ public class CheckpointWriter extends LogWriter { - public CheckpointWriter(File logFile) throws FileNotFoundException { + public CheckpointWriter(File logFile) throws IOException { super(logFile); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/ILogWriter.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/ILogWriter.java index d89563a932817..f4d65612c4709 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/ILogWriter.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/ILogWriter.java @@ -33,8 +33,9 @@ public interface ILogWriter extends Closeable { * * @param buffer content that have been converted to bytes * @throws IOException if an I/O error occurs + * @return Compression rate of the buffer after compression */ - void write(ByteBuffer buffer) throws IOException; + double write(ByteBuffer buffer) throws IOException; /** * Forces any updates to this file to be written to the storage device that contains it. diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/LogWriter.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/LogWriter.java index 68f4deae31894..29335efde5cc6 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/LogWriter.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/LogWriter.java @@ -19,19 +19,23 @@ package org.apache.iotdb.db.storageengine.dataregion.wal.io; +import org.apache.iotdb.db.conf.IoTDBDescriptor; import org.apache.iotdb.db.storageengine.dataregion.wal.buffer.WALEntry; import org.apache.iotdb.db.storageengine.dataregion.wal.checkpoint.Checkpoint; +import org.apache.tsfile.compress.ICompressor; +import org.apache.tsfile.file.metadata.enums.CompressionType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.File; -import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.ClosedChannelException; import java.nio.channels.FileChannel; +import java.nio.charset.StandardCharsets; +import java.util.Objects; /** * LogWriter writes the binary logs into a file, including writing {@link WALEntry} into .wal file @@ -43,23 +47,89 @@ public abstract class LogWriter implements ILogWriter { protected final File logFile; protected final FileOutputStream logStream; protected final FileChannel logChannel; - protected long size; + protected long size = 0; + protected long originalSize = 0; + private final ByteBuffer headerBuffer = ByteBuffer.allocate(Integer.BYTES * 2 + 1); + private ICompressor compressor = + ICompressor.getCompressor( + IoTDBDescriptor.getInstance().getConfig().getWALCompressionAlgorithm()); + private ByteBuffer compressedByteBuffer; + // Minimum size to compress, default is 32 KB + private static long minCompressionSize = 32 * 1024L; - protected LogWriter(File logFile) throws FileNotFoundException { + protected LogWriter(File logFile) throws IOException { this.logFile = logFile; this.logStream = new FileOutputStream(logFile, true); this.logChannel = this.logStream.getChannel(); + if (!logFile.exists() || logFile.length() == 0) { + this.logChannel.write( + ByteBuffer.wrap(WALWriter.MAGIC_STRING.getBytes(StandardCharsets.UTF_8))); + size += logChannel.position(); + } + if (IoTDBDescriptor.getInstance().getConfig().getWALCompressionAlgorithm() + != CompressionType.UNCOMPRESSED) { + // TODO: Use a dynamic strategy to enlarge the buffer size + compressedByteBuffer = + ByteBuffer.allocate( + compressor.getMaxBytesForCompression( + IoTDBDescriptor.getInstance().getConfig().getWalBufferSize())); + } else { + compressedByteBuffer = null; + } } @Override - public void write(ByteBuffer buffer) throws IOException { - size += buffer.position(); + public double write(ByteBuffer buffer) throws IOException { + CompressionType compressionType = + IoTDBDescriptor.getInstance().getConfig().getWALCompressionAlgorithm(); + int bufferSize = buffer.position(); + if (bufferSize == 0) { + return 1.0; + } + originalSize += bufferSize; buffer.flip(); + boolean compressed = false; + int uncompressedSize = bufferSize; + if (compressionType != CompressionType.UNCOMPRESSED + /* Do not compress buffer that is less than min size */ + && bufferSize > minCompressionSize) { + if (Objects.isNull(compressedByteBuffer)) { + compressedByteBuffer = + ByteBuffer.allocate( + compressor.getMaxBytesForCompression( + IoTDBDescriptor.getInstance().getConfig().getWalBufferSize())); + } + compressedByteBuffer.clear(); + if (compressor.getType() != compressionType) { + compressor = ICompressor.getCompressor(compressionType); + } + compressor.compress(buffer, compressedByteBuffer); + buffer = compressedByteBuffer; + bufferSize = buffer.position(); + buffer.flip(); + compressed = true; + } + size += bufferSize; + /* + Header structure: + [CompressionType(1 byte)][dataBufferSize(4 bytes)][uncompressedSize(4 bytes)] + */ + headerBuffer.clear(); + headerBuffer.put( + compressed ? compressionType.serialize() : CompressionType.UNCOMPRESSED.serialize()); + headerBuffer.putInt(bufferSize); + if (compressed) { + headerBuffer.putInt(uncompressedSize); + } + size += headerBuffer.position(); try { + headerBuffer.flip(); + logChannel.write(headerBuffer); logChannel.write(buffer); } catch (ClosedChannelException e) { logger.warn("Cannot write to {}", logFile, e); } + return ((double) bufferSize / uncompressedSize); } @Override @@ -79,6 +149,10 @@ public long size() { return size; } + public long originalSize() { + return originalSize; + } + @Override public File getLogFile() { return logFile; @@ -97,4 +171,8 @@ public void close() throws IOException { } } } + + public long getOffset() throws IOException { + return logChannel.position(); + } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/WALByteBufReader.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/WALByteBufReader.java index f101eaf3647e5..882b5ea468c90 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/WALByteBufReader.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/WALByteBufReader.java @@ -22,6 +22,7 @@ import org.apache.iotdb.db.storageengine.dataregion.wal.buffer.WALEntry; import java.io.Closeable; +import java.io.DataInputStream; import java.io.File; import java.io.IOException; import java.nio.ByteBuffer; @@ -37,6 +38,7 @@ public class WALByteBufReader implements Closeable { private final File logFile; private final FileChannel channel; private final WALMetaData metaData; + private final DataInputStream logStream; private final Iterator sizeIterator; public WALByteBufReader(File logFile) throws IOException { @@ -46,6 +48,7 @@ public WALByteBufReader(File logFile) throws IOException { public WALByteBufReader(File logFile, FileChannel channel) throws IOException { this.logFile = logFile; this.channel = channel; + this.logStream = new DataInputStream(new WALInputStream(logFile)); this.metaData = WALMetaData.readFromWALFile(logFile, channel); this.sizeIterator = metaData.getBuffersSize().iterator(); channel.position(0); @@ -63,9 +66,14 @@ public boolean hasNext() { */ public ByteBuffer next() throws IOException { int size = sizeIterator.next(); + // TODO: Reuse this buffer ByteBuffer buffer = ByteBuffer.allocate(size); - channel.read(buffer); - buffer.clear(); + /* + Notice, we don't need to flip the buffer after calling + logStream.readFully, since this function does not change + the position of the buffer. + */ + logStream.readFully(buffer.array(), 0, size); return buffer; } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/WALInputStream.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/WALInputStream.java new file mode 100644 index 0000000000000..844c06436b762 --- /dev/null +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/WALInputStream.java @@ -0,0 +1,365 @@ +/* + * 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.iotdb.db.storageengine.dataregion.wal.io; + +import org.apache.iotdb.db.utils.MmapUtil; + +import org.apache.tsfile.compress.IUnCompressor; +import org.apache.tsfile.file.metadata.enums.CompressionType; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.IOException; +import java.io.InputStream; +import java.nio.ByteBuffer; +import java.nio.MappedByteBuffer; +import java.nio.channels.FileChannel; +import java.nio.charset.StandardCharsets; +import java.util.Objects; + +public class WALInputStream extends InputStream implements AutoCloseable { + + private static final Logger logger = LoggerFactory.getLogger(WALInputStream.class); + private final FileChannel channel; + private final ByteBuffer segmentHeaderBuffer = ByteBuffer.allocate(Integer.BYTES + Byte.BYTES); + private final ByteBuffer compressedHeader = ByteBuffer.allocate(Integer.BYTES); + private ByteBuffer dataBuffer = null; + private ByteBuffer compressedBuffer = null; + private long fileSize; + File logFile; + /* + The WAL file consist of following parts: + [MagicString] [Segment 1] [Segment 2] ... [Segment N] [Metadata] [MagicString] + The endOffset indicates the maximum offset that a segment can reach. + Aka, the last byte of the last segment. + */ + private long endOffset = -1; + + enum FileVersion { + V1, + V2, + UNKNOWN + }; + + FileVersion version; + + public WALInputStream(File logFile) throws IOException { + channel = FileChannel.open(logFile.toPath()); + fileSize = channel.size(); + analyzeFileVersion(); + getEndOffset(); + this.logFile = logFile; + } + + private void getEndOffset() throws IOException { + if (channel.size() < WALWriter.MAGIC_STRING_BYTES + Integer.BYTES) { + // An broken file + endOffset = channel.size(); + return; + } + ByteBuffer metadataSizeBuf = ByteBuffer.allocate(Integer.BYTES); + long position; + try { + if (version == FileVersion.V2) { + // New Version + ByteBuffer magicStringBuffer = ByteBuffer.allocate(WALWriter.MAGIC_STRING_BYTES); + channel.read(magicStringBuffer, channel.size() - WALWriter.MAGIC_STRING_BYTES); + magicStringBuffer.flip(); + if (!new String(magicStringBuffer.array(), StandardCharsets.UTF_8) + .equals(WALWriter.MAGIC_STRING)) { + // This is a broken wal file + endOffset = channel.size(); + return; + } else { + // This is a normal wal file + position = channel.size() - WALWriter.MAGIC_STRING_BYTES - Integer.BYTES; + } + } else { + // Old version + ByteBuffer magicStringBuffer = + ByteBuffer.allocate(WALWriter.MAGIC_STRING_V1.getBytes(StandardCharsets.UTF_8).length); + channel.read( + magicStringBuffer, + channel.size() - WALWriter.MAGIC_STRING_V1.getBytes(StandardCharsets.UTF_8).length); + magicStringBuffer.flip(); + if (!new String(magicStringBuffer.array(), StandardCharsets.UTF_8) + .equals(WALWriter.MAGIC_STRING_V1)) { + // this is a broken wal file + endOffset = channel.size(); + return; + } else { + position = + channel.size() + - WALWriter.MAGIC_STRING_V1.getBytes(StandardCharsets.UTF_8).length + - Integer.BYTES; + } + } + // Read the meta data size + channel.read(metadataSizeBuf, position); + metadataSizeBuf.flip(); + int metadataSize = metadataSizeBuf.getInt(); + endOffset = channel.size() - WALWriter.MAGIC_STRING_BYTES - Integer.BYTES - metadataSize - 1; + } finally { + channel.position(WALWriter.MAGIC_STRING_BYTES); + } + } + + private void analyzeFileVersion() throws IOException { + if (channel.size() < WALWriter.MAGIC_STRING_BYTES) { + version = FileVersion.UNKNOWN; + return; + } + if (isCurrentVersion()) { + this.version = FileVersion.V2; + return; + } + this.version = FileVersion.V1; + } + + private boolean isCurrentVersion() throws IOException { + channel.position(0); + ByteBuffer buffer = ByteBuffer.allocate(WALWriter.MAGIC_STRING_BYTES); + channel.read(buffer); + return new String(buffer.array(), StandardCharsets.UTF_8).equals(WALWriter.MAGIC_STRING); + } + + @Override + public int read() throws IOException { + if (Objects.isNull(dataBuffer) || dataBuffer.position() >= dataBuffer.limit()) { + loadNextSegment(); + } + return dataBuffer.get() & 0xFF; + } + + @Override + public int read(byte[] b, int off, int len) throws IOException { + if (Objects.isNull(dataBuffer) || dataBuffer.position() >= dataBuffer.limit()) { + loadNextSegment(); + } + if (dataBuffer.remaining() >= len) { + dataBuffer.get(b, off, len); + return len; + } + int toBeRead = len; + while (toBeRead > 0) { + int remaining = dataBuffer.remaining(); + int bytesRead = Math.min(remaining, toBeRead); + dataBuffer.get(b, off, bytesRead); + off += bytesRead; + toBeRead -= bytesRead; + if (toBeRead > 0) { + loadNextSegment(); + } + } + return len; + } + + @Override + public void close() throws IOException { + channel.close(); + dataBuffer = null; + } + + @Override + public int available() throws IOException { + long size = (endOffset - channel.position()); + if (!Objects.isNull(dataBuffer)) { + size += dataBuffer.limit() - dataBuffer.position(); + } + return (int) size; + } + + private void loadNextSegment() throws IOException { + if (channel.position() >= endOffset) { + throw new IOException("End of file"); + } + if (version == FileVersion.V2) { + loadNextSegmentV2(); + } else if (version == FileVersion.V1) { + loadNextSegmentV1(); + } else { + tryLoadSegment(); + } + } + + private void loadNextSegmentV1() throws IOException { + // just read raw data as input + if (channel.position() >= fileSize) { + throw new IOException("Unexpected end of file"); + } + if (Objects.isNull(dataBuffer)) { + // read 128 KB + dataBuffer = ByteBuffer.allocate(128 * 1024); + } + dataBuffer.clear(); + channel.read(dataBuffer); + dataBuffer.flip(); + } + + private void loadNextSegmentV2() throws IOException { + SegmentInfo segmentInfo = getNextSegmentInfo(); + if (segmentInfo.compressionType != CompressionType.UNCOMPRESSED) { + // A compressed segment + if (Objects.isNull(dataBuffer) + || dataBuffer.capacity() < segmentInfo.uncompressedSize + || dataBuffer.capacity() > segmentInfo.uncompressedSize * 2) { + if (!Objects.isNull(dataBuffer)) { + MmapUtil.clean((MappedByteBuffer) dataBuffer); + } + dataBuffer = ByteBuffer.allocateDirect(segmentInfo.uncompressedSize); + } + dataBuffer.clear(); + + if (Objects.isNull(compressedBuffer) + || compressedBuffer.capacity() < segmentInfo.dataInDiskSize + || compressedBuffer.capacity() > segmentInfo.dataInDiskSize * 2) { + if (!Objects.isNull(compressedBuffer)) { + MmapUtil.clean((MappedByteBuffer) compressedBuffer); + } + compressedBuffer = ByteBuffer.allocateDirect(segmentInfo.dataInDiskSize); + } + compressedBuffer.clear(); + // limit the buffer to prevent it from reading too much byte than expected + compressedBuffer.limit(segmentInfo.dataInDiskSize); + if (channel.read(compressedBuffer) != segmentInfo.dataInDiskSize) { + throw new IOException("Unexpected end of file"); + } + compressedBuffer.flip(); + + IUnCompressor unCompressor = IUnCompressor.getUnCompressor(segmentInfo.compressionType); + unCompressor.uncompress(compressedBuffer, dataBuffer); + } else { + // An uncompressed segment + if (Objects.isNull(dataBuffer) + || dataBuffer.capacity() < segmentInfo.dataInDiskSize + || dataBuffer.capacity() > segmentInfo.dataInDiskSize * 2) { + if (!Objects.isNull(dataBuffer)) { + MmapUtil.clean((MappedByteBuffer) dataBuffer); + } + dataBuffer = ByteBuffer.allocateDirect(segmentInfo.dataInDiskSize); + } + dataBuffer.clear(); + // limit the buffer to prevent it from reading too much byte than expected + dataBuffer.limit(segmentInfo.dataInDiskSize); + + if (channel.read(dataBuffer) != segmentInfo.dataInDiskSize) { + throw new IOException("Unexpected end of file"); + } + } + dataBuffer.flip(); + } + + private void tryLoadSegment() throws IOException { + long originPosition = channel.position(); + try { + loadNextSegmentV2(); + version = FileVersion.V2; + } catch (Throwable e) { + // failed to load in V2 way, try in V1 way + logger.warn("Failed to load WAL segment in V2 way, try in V1 way", e); + channel.position(originPosition); + } + + if (version == FileVersion.UNKNOWN) { + loadNextSegmentV1(); + version = FileVersion.V1; + } + } + + /** + * Since current WAL file is compressed, but some part of the system need to skip the offset of an + * uncompressed wal file, this method is used to skip to the given logical position. + * + * @param pos The logical offset to skip to + * @throws IOException If the file is broken or the given position is invalid + */ + public void skipToGivenLogicalPosition(long pos) throws IOException { + if (version == FileVersion.V2) { + channel.position(WALWriter.MAGIC_STRING_BYTES); + long posRemain = pos; + SegmentInfo segmentInfo = null; + do { + segmentInfo = getNextSegmentInfo(); + if (posRemain >= segmentInfo.uncompressedSize) { + posRemain -= segmentInfo.uncompressedSize; + channel.position(channel.position() + segmentInfo.dataInDiskSize); + } else { + break; + } + } while (posRemain >= 0); + + if (segmentInfo.compressionType != CompressionType.UNCOMPRESSED) { + compressedBuffer = ByteBuffer.allocate(segmentInfo.dataInDiskSize); + channel.read(compressedBuffer); + compressedBuffer.flip(); + IUnCompressor unCompressor = IUnCompressor.getUnCompressor(segmentInfo.compressionType); + dataBuffer = ByteBuffer.allocate(segmentInfo.uncompressedSize); + unCompressor.uncompress(compressedBuffer, dataBuffer); + } else { + dataBuffer = ByteBuffer.allocate(segmentInfo.dataInDiskSize); + channel.read(dataBuffer); + dataBuffer.flip(); + } + + dataBuffer.position((int) posRemain); + } else { + dataBuffer = null; + channel.position(pos); + } + } + + public void read(ByteBuffer buffer) throws IOException { + int totalBytesToBeRead = buffer.remaining(); + int currReadBytes = Math.min(dataBuffer.remaining(), buffer.remaining()); + dataBuffer.get(buffer.array(), buffer.position(), currReadBytes); + if (totalBytesToBeRead - currReadBytes > 0) { + loadNextSegment(); + read(buffer); + } + } + + public long getFileCurrentPos() throws IOException { + return channel.position(); + } + + private SegmentInfo getNextSegmentInfo() throws IOException { + segmentHeaderBuffer.clear(); + channel.read(segmentHeaderBuffer); + segmentHeaderBuffer.flip(); + SegmentInfo info = new SegmentInfo(); + info.compressionType = CompressionType.deserialize(segmentHeaderBuffer.get()); + info.dataInDiskSize = segmentHeaderBuffer.getInt(); + if (info.compressionType != CompressionType.UNCOMPRESSED) { + compressedHeader.clear(); + channel.read(compressedHeader); + compressedHeader.flip(); + info.uncompressedSize = compressedHeader.getInt(); + } else { + info.uncompressedSize = info.dataInDiskSize; + } + return info; + } + + private class SegmentInfo { + public CompressionType compressionType; + public int dataInDiskSize; + public int uncompressedSize; + } +} diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/WALMetaData.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/WALMetaData.java index 9ca700a62f7cc..7fa634ffbdcb1 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/WALMetaData.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/WALMetaData.java @@ -22,10 +22,14 @@ import org.apache.iotdb.consensus.iot.log.ConsensusReqReader; import org.apache.iotdb.db.utils.SerializedSize; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.File; import java.io.IOException; import java.nio.ByteBuffer; import java.nio.channels.FileChannel; +import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.HashSet; import java.util.List; @@ -36,6 +40,7 @@ * entry and the number of entries. */ public class WALMetaData implements SerializedSize { + private static final Logger logger = LoggerFactory.getLogger(WALMetaData.class); // search index 8 byte, wal entries' number 4 bytes private static final int FIXED_SERIALIZED_SIZE = Long.BYTES + Integer.BYTES; @@ -45,6 +50,7 @@ public class WALMetaData implements SerializedSize { private final List buffersSize; // memTable ids of this wal file private final Set memTablesId; + private long truncateOffSet = 0; public WALMetaData() { this(ConsensusReqReader.DEFAULT_SEARCH_INDEX, new ArrayList<>(), new HashSet<>()); @@ -79,7 +85,7 @@ public int serializedSize() { + (memTablesId.isEmpty() ? 0 : Integer.BYTES + memTablesId.size() * Long.BYTES); } - public void serialize(ByteBuffer buffer) { + public void serialize(File file, ByteBuffer buffer) { buffer.putLong(firstSearchIndex); buffer.putInt(buffersSize.size()); for (int size : buffersSize) { @@ -123,8 +129,7 @@ public long getFirstSearchIndex() { } public static WALMetaData readFromWALFile(File logFile, FileChannel channel) throws IOException { - if (channel.size() < WALWriter.MAGIC_STRING_BYTES - || !readTailMagic(channel).equals(WALWriter.MAGIC_STRING)) { + if (channel.size() < WALWriter.MAGIC_STRING_BYTES || !isValidMagicString(channel)) { throw new IOException(String.format("Broken wal file %s", logFile)); } // load metadata size @@ -153,10 +158,20 @@ public static WALMetaData readFromWALFile(File logFile, FileChannel channel) thr return metaData; } - private static String readTailMagic(FileChannel channel) throws IOException { + private static boolean isValidMagicString(FileChannel channel) throws IOException { ByteBuffer magicStringBytes = ByteBuffer.allocate(WALWriter.MAGIC_STRING_BYTES); channel.read(magicStringBytes, channel.size() - WALWriter.MAGIC_STRING_BYTES); magicStringBytes.flip(); - return new String(magicStringBytes.array()); + String magicString = new String(magicStringBytes.array(), StandardCharsets.UTF_8); + return magicString.equals(WALWriter.MAGIC_STRING) + || magicString.contains(WALWriter.MAGIC_STRING_V1); + } + + public void setTruncateOffSet(long offset) { + this.truncateOffSet = offset; + } + + public long getTruncateOffSet() { + return truncateOffSet; } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/WALReader.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/WALReader.java index ee50c73df9722..1310bb36b46f2 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/WALReader.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/WALReader.java @@ -26,12 +26,10 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.BufferedInputStream; import java.io.Closeable; import java.io.DataInputStream; import java.io.File; import java.io.IOException; -import java.nio.file.Files; import java.util.Iterator; import java.util.NoSuchElementException; @@ -46,6 +44,7 @@ public class WALReader implements Closeable { private final File logFile; private final boolean fileMayCorrupt; + private final WALInputStream walInputStream; private final DataInputStream logStream; private WALEntry nextEntry; private boolean fileCorrupted = false; @@ -57,9 +56,8 @@ public WALReader(File logFile) throws IOException { public WALReader(File logFile, boolean fileMayCorrupt) throws IOException { this.logFile = logFile; this.fileMayCorrupt = fileMayCorrupt; - this.logStream = - new DataInputStream( - new BufferedInputStream(Files.newInputStream(logFile.toPath()), STREAM_BUFFER_SIZE)); + this.walInputStream = new WALInputStream(logFile); + this.logStream = new DataInputStream(walInputStream); } /** Like {@link Iterator#hasNext()}. */ @@ -88,6 +86,10 @@ public boolean hasNext() { return nextEntry != null; } + public long getWALCurrentReadOffset() throws IOException { + return walInputStream.getFileCurrentPos(); + } + /** * Like {@link Iterator#next()}. * diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/WALWriter.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/WALWriter.java index 425fc676fad8c..7017b4be6cb04 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/WALWriter.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/io/WALWriter.java @@ -24,21 +24,26 @@ import org.apache.iotdb.db.storageengine.dataregion.wal.buffer.WALSignalEntry; import org.apache.iotdb.db.storageengine.dataregion.wal.utils.WALFileStatus; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.File; -import java.io.FileNotFoundException; import java.io.IOException; import java.nio.ByteBuffer; +import java.nio.charset.StandardCharsets; /** WALWriter writes the binary {@link WALEntry} into .wal file. */ public class WALWriter extends LogWriter { - public static final String MAGIC_STRING = "WAL"; - public static final int MAGIC_STRING_BYTES = MAGIC_STRING.getBytes().length; + private static final Logger logger = LoggerFactory.getLogger(WALWriter.class); + public static final String MAGIC_STRING_V1 = "WAL"; + public static final String MAGIC_STRING = "V2-WAL"; + public static final int MAGIC_STRING_BYTES = MAGIC_STRING.getBytes(StandardCharsets.UTF_8).length; private WALFileStatus walFileStatus = WALFileStatus.CONTAINS_NONE_SEARCH_INDEX; // wal files' metadata protected final WALMetaData metaData = new WALMetaData(); - public WALWriter(File logFile) throws FileNotFoundException { + public WALWriter(File logFile) throws IOException { super(logFile); } @@ -47,11 +52,11 @@ public WALWriter(File logFile) throws FileNotFoundException { * * @throws IOException when failing to write */ - public void write(ByteBuffer buffer, WALMetaData metaData) throws IOException { + public double write(ByteBuffer buffer, WALMetaData metaData) throws IOException { // update metadata updateMetaData(metaData); // flush buffer - write(buffer); + return write(buffer); } public void updateMetaData(WALMetaData metaData) { @@ -67,11 +72,18 @@ private void endFile() throws IOException { // mark info part ends endMarker.serialize(buffer); // flush meta data - metaData.serialize(buffer); + metaData.serialize(logFile, buffer); buffer.putInt(metaDataSize); // add magic string - buffer.put(MAGIC_STRING.getBytes()); - write(buffer); + buffer.put(MAGIC_STRING.getBytes(StandardCharsets.UTF_8)); + size += buffer.position(); + writeMetadata(buffer); + } + + private void writeMetadata(ByteBuffer buffer) throws IOException { + size += buffer.position(); + buffer.flip(); + logChannel.write(buffer); } @Override diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/node/WALNode.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/node/WALNode.java index e4a497de4d9b2..9a4b99f9ec05b 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/node/WALNode.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/node/WALNode.java @@ -64,6 +64,7 @@ import java.io.File; import java.io.FileNotFoundException; +import java.io.IOException; import java.nio.ByteBuffer; import java.util.ArrayList; import java.util.Arrays; @@ -107,13 +108,13 @@ public class WALNode implements IWALNode { // insert nodes whose search index are before this value can be deleted safely private volatile long safelyDeletedSearchIndex = DEFAULT_SAFELY_DELETED_SEARCH_INDEX; - public WALNode(String identifier, String logDirectory) throws FileNotFoundException { + public WALNode(String identifier, String logDirectory) throws IOException { this(identifier, logDirectory, 0, 0L); } public WALNode( String identifier, String logDirectory, long startFileVersion, long startSearchIndex) - throws FileNotFoundException { + throws IOException { this.identifier = identifier; this.logDirectory = SystemFileFactory.INSTANCE.getFile(logDirectory); if (!this.logDirectory.exists() && this.logDirectory.mkdirs()) { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/WALNodeRecoverTask.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/WALNodeRecoverTask.java index 237b353c9f9aa..07a06448359e6 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/WALNodeRecoverTask.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/WALNodeRecoverTask.java @@ -172,6 +172,7 @@ private long[] recoverLastFile() { } } } + metaData.setTruncateOffSet(walReader.getWALCurrentReadOffset()); metaData.add(walEntry.serializedSize(), searchIndex, walEntry.getMemTableId()); } } catch (Exception e) { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/WALRecoverWriter.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/WALRecoverWriter.java index 7015d45c58b04..5db0c17c9870b 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/WALRecoverWriter.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/WALRecoverWriter.java @@ -41,14 +41,14 @@ public WALRecoverWriter(File logFile) { public void recover(WALMetaData metaData) throws IOException { // locate broken data - int truncateSize; + long truncateSize; if (logFile.length() < MAGIC_STRING_BYTES) { // file without magic string truncateSize = 0; } else { if (readTailMagic().equals(MAGIC_STRING)) { // complete file return; } else { // file with broken magic string - truncateSize = metaData.getBuffersSize().stream().mapToInt(Integer::intValue).sum(); + truncateSize = metaData.getTruncateOffSet(); } } // truncate broken data diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/file/AbstractTsFileRecoverPerformer.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/file/AbstractTsFileRecoverPerformer.java index a23d0fb23b8ae..0880697b02c22 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/file/AbstractTsFileRecoverPerformer.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/file/AbstractTsFileRecoverPerformer.java @@ -20,7 +20,7 @@ package org.apache.iotdb.db.storageengine.dataregion.wal.recover.file; import org.apache.iotdb.db.exception.DataRegionException; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.storageengine.dataregion.tsfile.TsFileResource; import org.apache.iotdb.db.storageengine.dataregion.utils.TsFileResourceUtils; @@ -120,7 +120,7 @@ protected void reconstructResourceFile() throws IOException { } // set progress index for pipe to avoid data loss - PipeAgent.runtime().assignProgressIndexForTsFileRecovery(tsFileResource); + PipeDataNodeAgent.runtime().assignProgressIndexForTsFileRecovery(tsFileResource); tsFileResource.serialize(); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/file/UnsealedTsFileRecoverPerformer.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/file/UnsealedTsFileRecoverPerformer.java index 5c05f68d6d078..6bb9ef59898a4 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/file/UnsealedTsFileRecoverPerformer.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/file/UnsealedTsFileRecoverPerformer.java @@ -21,7 +21,7 @@ import org.apache.iotdb.commons.path.PartialPath; import org.apache.iotdb.db.exception.DataRegionException; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.write.DeleteDataNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.write.InsertNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.write.InsertRowsNode; @@ -257,7 +257,7 @@ public void endRecovery() throws WALRecoverException { } // set recover progress index for pipe - PipeAgent.runtime().assignProgressIndexForTsFileRecovery(tsFileResource); + PipeDataNodeAgent.runtime().assignProgressIndexForTsFileRecovery(tsFileResource); // if we put following codes in the 'if' clause above, this file can be continued writing // into it diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/utils/WALEntryPosition.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/utils/WALEntryPosition.java index 13b2f4c970418..c794745c6f56d 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/utils/WALEntryPosition.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/utils/WALEntryPosition.java @@ -21,6 +21,7 @@ import org.apache.iotdb.db.queryengine.plan.planner.plan.node.write.InsertNode; import org.apache.iotdb.db.storageengine.dataregion.wal.buffer.WALEntryValue; +import org.apache.iotdb.db.storageengine.dataregion.wal.io.WALInputStream; import org.apache.iotdb.db.storageengine.dataregion.wal.node.WALNode; import org.apache.tsfile.utils.Pair; @@ -100,11 +101,12 @@ ByteBuffer read() throws IOException { if (!canRead()) { throw new IOException("Target file hasn't been specified."); } - try (FileChannel channel = openReadFileChannel()) { + // TODO: Reuse the file stream + try (WALInputStream is = openReadFileStream()) { + is.skipToGivenLogicalPosition(position); ByteBuffer buffer = ByteBuffer.allocate(size); - channel.position(position); - channel.read(buffer); - buffer.clear(); + is.read(buffer); + buffer.flip(); return buffer; } } @@ -135,6 +137,27 @@ public FileChannel openReadFileChannel() throws IOException { } } + public WALInputStream openReadFileStream() throws IOException { + // TODO: Refactor this part of code + if (isInSealedFile()) { + walFile = walNode.getWALFile(walFileVersionId); + return new WALInputStream(walFile); + } else { + try { + walFile = walNode.getWALFile(walFileVersionId); + return new WALInputStream(walFile); + } catch (IOException e) { + // unsealed file may be renamed after sealed, so we should try again + if (isInSealedFile()) { + walFile = walNode.getWALFile(walFileVersionId); + return new WALInputStream(walFile); + } else { + throw e; + } + } + } + } + public File getWalFile() { return walFile; } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/utils/WALInsertNodeCache.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/utils/WALInsertNodeCache.java index 0a5718da6f14d..38e010db7db77 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/utils/WALInsertNodeCache.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/wal/utils/WALInsertNodeCache.java @@ -71,7 +71,7 @@ public class WALInsertNodeCache { private volatile boolean hasPipeRunning = false; - private WALInsertNodeCache(Integer dataRegionId) { + private WALInsertNodeCache(final Integer dataRegionId) { final long requestedAllocateSize = (long) Math.min( @@ -83,8 +83,8 @@ private WALInsertNodeCache(Integer dataRegionId) { .setShrinkMethod(oldMemory -> Math.max(oldMemory / 2, 1)) .setShrinkCallback( (oldMemory, newMemory) -> { - memoryUsageCheatFactor.set( - memoryUsageCheatFactor.get() * ((double) oldMemory / newMemory)); + memoryUsageCheatFactor.updateAndGet( + factor -> factor * ((double) oldMemory / newMemory)); isBatchLoadEnabled.set(newMemory >= CONFIG.getWalFileSizeThresholdInByte()); LOGGER.info( "WALInsertNodeCache.allocatedMemoryBlock of dataRegion {} has shrunk from {} to {}.", @@ -96,8 +96,8 @@ private WALInsertNodeCache(Integer dataRegionId) { oldMemory -> Math.min(Math.max(oldMemory, 1) * 2, requestedAllocateSize)) .setExpandCallback( (oldMemory, newMemory) -> { - memoryUsageCheatFactor.set( - memoryUsageCheatFactor.get() / ((double) newMemory / oldMemory)); + memoryUsageCheatFactor.updateAndGet( + factor -> factor / ((double) newMemory / oldMemory)); isBatchLoadEnabled.set(newMemory >= CONFIG.getWalFileSizeThresholdInByte()); LOGGER.info( "WALInsertNodeCache.allocatedMemoryBlock of dataRegion {} has expanded from {} to {}.", @@ -128,7 +128,7 @@ private WALInsertNodeCache(Integer dataRegionId) { /////////////////////////// Getter & Setter /////////////////////////// - public InsertNode getInsertNode(WALEntryPosition position) { + public InsertNode getInsertNode(final WALEntryPosition position) { final Pair pair = getByteBufferOrInsertNode(position); if (pair.getRight() != null) { @@ -145,7 +145,7 @@ public InsertNode getInsertNode(WALEntryPosition position) { final InsertNode insertNode = parse(ByteBuffer.wrap(pair.getLeft().array())); pair.setRight(insertNode); return insertNode; - } catch (Exception e) { + } catch (final Exception e) { LOGGER.error( "Parsing failed when recovering insertNode from wal, walFile:{}, position:{}, size:{}, exception:", position.getWalFile(), @@ -156,7 +156,7 @@ public InsertNode getInsertNode(WALEntryPosition position) { } } - private InsertNode parse(ByteBuffer buffer) { + private InsertNode parse(final ByteBuffer buffer) { final PlanNode node = WALEntry.deserializeForConsensus(buffer); if (node instanceof InsertNode) { return (InsertNode) node; @@ -165,7 +165,7 @@ private InsertNode parse(ByteBuffer buffer) { } } - public ByteBuffer getByteBuffer(WALEntryPosition position) { + public ByteBuffer getByteBuffer(final WALEntryPosition position) { Pair pair = getByteBufferOrInsertNode(position); if (pair.getLeft() != null) { @@ -187,7 +187,7 @@ public ByteBuffer getByteBuffer(WALEntryPosition position) { return ByteBuffer.wrap(pair.getLeft().array()); } - public Pair getByteBufferOrInsertNode(WALEntryPosition position) { + public Pair getByteBufferOrInsertNode(final WALEntryPosition position) { hasPipeRunning = true; final Pair pair = @@ -202,7 +202,8 @@ public Pair getByteBufferOrInsertNode(WALEntryPosition p return pair; } - public void cacheInsertNodeIfNeeded(WALEntryPosition walEntryPosition, InsertNode insertNode) { + public void cacheInsertNodeIfNeeded( + final WALEntryPosition walEntryPosition, final InsertNode insertNode) { // reduce memory usage if (hasPipeRunning) { lruCache.put(walEntryPosition, new Pair<>(null, insertNode)); @@ -225,11 +226,11 @@ public double getCacheRequestCount() { /////////////////////////// MemTable /////////////////////////// - public void addMemTable(long memTableId) { + public void addMemTable(final long memTableId) { memTablesNeedSearch.add(memTableId); } - public void removeMemTable(long memTableId) { + public void removeMemTable(final long memTableId) { memTablesNeedSearch.remove(memTableId); } @@ -239,7 +240,7 @@ class WALInsertNodeCacheLoader implements CacheLoader> { @Override - public @Nullable Pair load(@NonNull WALEntryPosition key) + public @Nullable Pair load(@NonNull final WALEntryPosition key) throws Exception { return new Pair<>(key.read(), null); } @@ -247,10 +248,10 @@ class WALInsertNodeCacheLoader /** Batch load all wal entries in the file when any one key is absent. */ @Override public @NonNull Map<@NonNull WALEntryPosition, @NonNull Pair> loadAll( - @NonNull Iterable walEntryPositions) { + @NonNull final Iterable walEntryPositions) { final Map> loadedEntries = new HashMap<>(); - for (WALEntryPosition walEntryPosition : walEntryPositions) { + for (final WALEntryPosition walEntryPosition : walEntryPositions) { if (loadedEntries.containsKey(walEntryPosition) || !walEntryPosition.canRead()) { continue; } @@ -261,7 +262,7 @@ class WALInsertNodeCacheLoader if (!walEntryPosition.isInSealedFile()) { try { loadedEntries.put(walEntryPosition, load(walEntryPosition)); - } catch (Exception e) { + } catch (final Exception e) { LOGGER.info( "Fail to cache wal entries from the wal file with version id {}", walFileVersionId, @@ -295,7 +296,7 @@ class WALInsertNodeCacheLoader position += size; } - } catch (IOException e) { + } catch (final IOException e) { LOGGER.info( "Fail to cache wal entries from the wal file with version id {}", walFileVersionId, @@ -309,7 +310,7 @@ class WALInsertNodeCacheLoader /////////////////////////// Singleton /////////////////////////// - public static WALInsertNodeCache getInstance(Integer regionId) { + public static WALInsertNodeCache getInstance(final Integer regionId) { return InstanceHolder.getOrCreateInstance(regionId); } @@ -317,7 +318,7 @@ private static class InstanceHolder { private static final Map INSTANCE_MAP = new ConcurrentHashMap<>(); - public static WALInsertNodeCache getOrCreateInstance(Integer key) { + public static WALInsertNodeCache getOrCreateInstance(final Integer key) { return INSTANCE_MAP.computeIfAbsent(key, k -> new WALInsertNodeCache(key)); } @@ -334,7 +335,7 @@ public boolean isBatchLoadEnabled() { } @TestOnly - public void setIsBatchLoadEnabled(boolean isBatchLoadEnabled) { + public void setIsBatchLoadEnabled(final boolean isBatchLoadEnabled) { this.isBatchLoadEnabled.set(isBatchLoadEnabled); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/rescon/disk/FolderManager.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/rescon/disk/FolderManager.java index b32307ada8bae..0851a698aba12 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/rescon/disk/FolderManager.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/rescon/disk/FolderManager.java @@ -79,4 +79,8 @@ public String getNextFolder() throws DiskSpaceInsufficientException { throw e; } } + + public List getFolders() { + return folders; + } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionAgentLauncher.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionAgentLauncher.java index 32dd078dd7805..d83996cda470b 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionAgentLauncher.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionAgentLauncher.java @@ -87,7 +87,7 @@ public static synchronized void launchSubscriptionTopicAgent() throws StartupExc } return; - } catch (SubscriptionException | ClientManagerException | TException e) { + } catch (final SubscriptionException | ClientManagerException | TException e) { retry++; LOGGER.warn( "Failed to get topic meta from config node for {} times, will retry at most {} times.", @@ -97,7 +97,7 @@ public static synchronized void launchSubscriptionTopicAgent() throws StartupExc try { Thread.sleep( retry * SubscriptionConfig.getInstance().getSubscriptionLaunchRetryIntervalMs()); - } catch (InterruptedException interruptedException) { + } catch (final InterruptedException interruptedException) { LOGGER.info( "Interrupted while sleeping, will retry to get topic meta from config node.", interruptedException); @@ -146,7 +146,7 @@ public static synchronized void launchSubscriptionConsumerAgent() throws Startup } return; - } catch (SubscriptionException | ClientManagerException | TException e) { + } catch (final SubscriptionException | ClientManagerException | TException e) { retry++; LOGGER.warn( "Failed to get consumer group meta from config node for {} times, will retry at most {} times.", @@ -156,7 +156,7 @@ public static synchronized void launchSubscriptionConsumerAgent() throws Startup try { Thread.sleep( retry * SubscriptionConfig.getInstance().getSubscriptionLaunchRetryIntervalMs()); - } catch (InterruptedException interruptedException) { + } catch (final InterruptedException interruptedException) { LOGGER.info( "Interrupted while sleeping, will retry to get consumer group meta from config node.", interruptedException); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionBrokerAgent.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionBrokerAgent.java index aff4893c61a03..21064ac34c89a 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionBrokerAgent.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionBrokerAgent.java @@ -141,23 +141,22 @@ public void bindPrefetchingQueue(final SubscriptionConnectorSubtask subtask) { broker.bindPrefetchingQueue(subtask.getTopicName(), subtask.getInputPendingQueue()); } - public void unbindPrefetchingQueue(final SubscriptionConnectorSubtask subtask) { - final String consumerGroupId = subtask.getConsumerGroupId(); + public void unbindPrefetchingQueue( + final String consumerGroupId, final String topicName, final boolean doRemove) { final SubscriptionBroker broker = consumerGroupIdToSubscriptionBroker.get(consumerGroupId); if (Objects.isNull(broker)) { LOGGER.warn("Subscription: consumer group [{}] does not exist", consumerGroupId); return; } - broker.unbindPrefetchingQueue(subtask.getTopicName()); + broker.unbindPrefetchingQueue(topicName, doRemove); } - public void executePrefetch(final SubscriptionConnectorSubtask subtask) { - final String consumerGroupId = subtask.getConsumerGroupId(); + public void executePrefetch(final String consumerGroupId, final String topicName) { final SubscriptionBroker broker = consumerGroupIdToSubscriptionBroker.get(consumerGroupId); if (Objects.isNull(broker)) { LOGGER.warn("Subscription: consumer group [{}] does not exist", consumerGroupId); return; } - broker.executePrefetch(subtask.getTopicName()); + broker.executePrefetch(topicName); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionConsumerAgent.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionConsumerAgent.java index d6572923635c4..983abb0364269 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionConsumerAgent.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionConsumerAgent.java @@ -62,7 +62,7 @@ protected void releaseWriteLock() { ////////////////////////// ConsumerGroupMeta Management Entry ////////////////////////// public TPushConsumerGroupMetaRespExceptionMessage handleSingleConsumerGroupMetaChanges( - ConsumerGroupMeta consumerGroupMetaFromCoordinator) { + final ConsumerGroupMeta consumerGroupMetaFromCoordinator) { acquireWriteLock(); try { if (consumerGroupMetaFromCoordinator.isEmpty()) { @@ -71,7 +71,7 @@ public TPushConsumerGroupMetaRespExceptionMessage handleSingleConsumerGroupMetaC handleSingleConsumerGroupMetaChangesInternal(consumerGroupMetaFromCoordinator); } return null; - } catch (Exception e) { + } catch (final Exception e) { final String consumerGroupId = consumerGroupMetaFromCoordinator.getConsumerGroupId(); final String exceptionMessage = String.format( @@ -114,6 +114,13 @@ private void handleSingleConsumerGroupMetaChangesInternal( return; } + // unbind and remove prefetching queue + final Set topicsUnsubByGroup = + ConsumerGroupMeta.getTopicsUnsubByGroup(metaInAgent, metaFromCoordinator); + for (final String topicName : topicsUnsubByGroup) { + SubscriptionAgent.broker().unbindPrefetchingQueue(consumerGroupId, topicName, true); + } + // TODO: Currently we fully replace the entire ConsumerGroupMeta without carefully checking the // changes in its fields. consumerGroupMetaKeeper.removeConsumerGroupMeta(consumerGroupId); @@ -121,14 +128,15 @@ private void handleSingleConsumerGroupMetaChangesInternal( } public TPushConsumerGroupMetaRespExceptionMessage handleConsumerGroupMetaChanges( - List consumerGroupMetasFromCoordinator) { + final List consumerGroupMetasFromCoordinator) { acquireWriteLock(); try { - for (ConsumerGroupMeta consumerGroupMetaFromCoordinator : consumerGroupMetasFromCoordinator) { + for (final ConsumerGroupMeta consumerGroupMetaFromCoordinator : + consumerGroupMetasFromCoordinator) { try { handleSingleConsumerGroupMetaChangesInternal(consumerGroupMetaFromCoordinator); return null; - } catch (Exception e) { + } catch (final Exception e) { final String consumerGroupId = consumerGroupMetaFromCoordinator.getConsumerGroupId(); final String exceptionMessage = String.format( @@ -146,12 +154,12 @@ public TPushConsumerGroupMetaRespExceptionMessage handleConsumerGroupMetaChanges } public TPushConsumerGroupMetaRespExceptionMessage handleDropConsumerGroup( - String consumerGroupId) { + final String consumerGroupId) { acquireWriteLock(); try { handleDropConsumerGroupInternal(consumerGroupId); return null; - } catch (Exception e) { + } catch (final Exception e) { final String exceptionMessage = String.format( "Subscription: Failed to drop consumer group %s, because %s", consumerGroupId, e); @@ -163,7 +171,7 @@ public TPushConsumerGroupMetaRespExceptionMessage handleDropConsumerGroup( } } - private void handleDropConsumerGroupInternal(String consumerGroupId) { + private void handleDropConsumerGroupInternal(final String consumerGroupId) { if (SubscriptionAgent.broker().isBrokerExist(consumerGroupId)) { if (!SubscriptionAgent.broker().dropBroker(consumerGroupId)) { final String exceptionMessage = @@ -180,7 +188,7 @@ private void handleDropConsumerGroupInternal(String consumerGroupId) { consumerGroupMetaKeeper.removeConsumerGroupMeta(consumerGroupId); } - public boolean isConsumerExisted(String consumerGroupId, String consumerId) { + public boolean isConsumerExisted(final String consumerGroupId, final String consumerId) { acquireReadLock(); try { final ConsumerGroupMeta consumerGroupMeta = @@ -191,7 +199,8 @@ public boolean isConsumerExisted(String consumerGroupId, String consumerId) { } } - public Set getTopicsSubscribedByConsumer(String consumerGroupId, String consumerId) { + public Set getTopicsSubscribedByConsumer( + final String consumerGroupId, final String consumerId) { acquireReadLock(); try { return consumerGroupMetaKeeper.getTopicsSubscribedByConsumer(consumerGroupId, consumerId); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionReceiverAgent.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionReceiverAgent.java index 1bb0735b019a3..71f319374cd53 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionReceiverAgent.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionReceiverAgent.java @@ -51,7 +51,7 @@ public class SubscriptionReceiverAgent { PipeSubscribeRequestVersion.VERSION_1.getVersion(), SubscriptionReceiverV1::new); } - public TPipeSubscribeResp handle(TPipeSubscribeReq req) { + public TPipeSubscribeResp handle(final TPipeSubscribeReq req) { final byte reqVersion = req.getVersion(); if (RECEIVER_CONSTRUCTORS.containsKey(reqVersion)) { return getReceiver(reqVersion).handle(req); @@ -69,7 +69,7 @@ public TPipeSubscribeResp handle(TPipeSubscribeReq req) { } } - private SubscriptionReceiver getReceiver(byte reqVersion) { + private SubscriptionReceiver getReceiver(final byte reqVersion) { if (receiverThreadLocal.get() == null) { return setAndGetReceiver(reqVersion); } @@ -88,7 +88,7 @@ private SubscriptionReceiver getReceiver(byte reqVersion) { return receiverThreadLocal.get(); } - private SubscriptionReceiver setAndGetReceiver(byte reqVersion) { + private SubscriptionReceiver setAndGetReceiver(final byte reqVersion) { if (RECEIVER_CONSTRUCTORS.containsKey(reqVersion)) { receiverThreadLocal.set(RECEIVER_CONSTRUCTORS.get(reqVersion).get()); } else { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionTopicAgent.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionTopicAgent.java index fb27e8825b8e8..bc1741704224f 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionTopicAgent.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/agent/SubscriptionTopicAgent.java @@ -60,12 +60,12 @@ protected void releaseWriteLock() { ////////////////////////// Topic Management Entry ////////////////////////// public TPushTopicMetaRespExceptionMessage handleSingleTopicMetaChanges( - TopicMeta topicMetaFromCoordinator) { + final TopicMeta topicMetaFromCoordinator) { acquireWriteLock(); try { handleSingleTopicMetaChangesInternal(topicMetaFromCoordinator); return null; - } catch (Exception e) { + } catch (final Exception e) { final String topicName = topicMetaFromCoordinator.getTopicName(); final String exceptionMessage = String.format( @@ -86,13 +86,13 @@ private void handleSingleTopicMetaChangesInternal(final TopicMeta metaFromCoordi } public TPushTopicMetaRespExceptionMessage handleTopicMetaChanges( - List topicMetasFromCoordinator) { + final List topicMetasFromCoordinator) { acquireWriteLock(); try { - for (TopicMeta topicMetaFromCoordinator : topicMetasFromCoordinator) { + for (final TopicMeta topicMetaFromCoordinator : topicMetasFromCoordinator) { try { handleSingleTopicMetaChangesInternal(topicMetaFromCoordinator); - } catch (Exception e) { + } catch (final Exception e) { final String topicName = topicMetaFromCoordinator.getTopicName(); final String exceptionMessage = String.format( @@ -109,12 +109,12 @@ public TPushTopicMetaRespExceptionMessage handleTopicMetaChanges( } } - public TPushTopicMetaRespExceptionMessage handleDropTopic(String topicName) { + public TPushTopicMetaRespExceptionMessage handleDropTopic(final String topicName) { acquireWriteLock(); try { handleDropTopicInternal(topicName); return null; - } catch (Exception e) { + } catch (final Exception e) { final String exceptionMessage = String.format("Subscription: Failed to drop topic %s, because %s", topicName, e); LOGGER.warn(exceptionMessage); @@ -125,11 +125,11 @@ public TPushTopicMetaRespExceptionMessage handleDropTopic(String topicName) { } } - private void handleDropTopicInternal(String topicName) { + private void handleDropTopicInternal(final String topicName) { topicMetaKeeper.removeTopicMeta(topicName); } - public boolean isTopicExisted(String topicName) { + public boolean isTopicExisted(final String topicName) { acquireReadLock(); try { return topicMetaKeeper.containsTopicMeta(topicName); @@ -138,7 +138,7 @@ public boolean isTopicExisted(String topicName) { } } - public String getTopicFormat(String topicName) { + public String getTopicFormat(final String topicName) { acquireReadLock(); try { return topicMetaKeeper @@ -149,4 +149,16 @@ public String getTopicFormat(String topicName) { releaseReadLock(); } } + + public String getTopicMode(final String topicName) { + acquireReadLock(); + try { + return topicMetaKeeper + .getTopicMeta(topicName) + .getConfig() + .getStringOrDefault(TopicConstant.MODE_KEY, TopicConstant.MODE_DEFAULT_VALUE); + } finally { + releaseReadLock(); + } + } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/SubscriptionBroker.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/SubscriptionBroker.java index 90785c1602e62..f3bd0371fdd2c 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/SubscriptionBroker.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/SubscriptionBroker.java @@ -65,6 +65,18 @@ public List poll(final String consumerId, final Set t final String topicName = entry.getKey(); final SubscriptionPrefetchingQueue prefetchingQueue = entry.getValue(); if (topicNames.contains(topicName)) { + // before determining if it is closed + if (prefetchingQueue.isCompleted()) { + LOGGER.info( + "Subscription: prefetching queue bound to topic [{}] is completed, return termination response to client", + topicName); + events.add(prefetchingQueue.generateSubscriptionPollTerminationResponse()); + continue; + } + if (prefetchingQueue.isClosed()) { + LOGGER.warn("Subscription: prefetching queue bound to topic [{}] is closed", topicName); + continue; + } final SubscriptionEvent event = prefetchingQueue.poll(consumerId); if (Objects.nonNull(event)) { events.add(event); @@ -95,6 +107,10 @@ public List pollTsFile( LOGGER.warn(errorMessage); throw new SubscriptionException(errorMessage); } + if (prefetchingQueue.isClosed()) { + LOGGER.warn("Subscription: prefetching queue bound to topic [{}] is closed", topicName); + return Collections.emptyList(); + } final SubscriptionEvent event = ((SubscriptionPrefetchingTsFileQueue) prefetchingQueue) .pollTsFile(consumerId, fileName, writingOffset); @@ -117,6 +133,10 @@ public List commit( "Subscription: prefetching queue bound to topic [{}] does not exist", topicName); continue; } + if (prefetchingQueue.isClosed()) { + LOGGER.warn("Subscription: prefetching queue bound to topic [{}] is closed", topicName); + continue; + } if (!nack) { if (prefetchingQueue.ack(commitContext)) { successfulCommitContexts.add(commitContext); @@ -155,18 +175,30 @@ public void bindPrefetchingQueue( } } - public void unbindPrefetchingQueue(final String topicName) { + public void unbindPrefetchingQueue(final String topicName, final boolean doRemove) { final SubscriptionPrefetchingQueue prefetchingQueue = topicNameToPrefetchingQueue.get(topicName); if (Objects.isNull(prefetchingQueue)) { LOGGER.warn("Subscription: prefetching queue bound to topic [{}] does not exist", topicName); return; } - // clean up uncommitted events + + // mark prefetching queue closed first + prefetchingQueue.markClosed(); + + // clean up events in prefetching queue, this operation is idempotent prefetchingQueue.cleanup(); - topicNameToPrefetchingQueue.remove(topicName); - SubscriptionPrefetchingQueueMetrics.getInstance() - .deregister(prefetchingQueue.getPrefetchingQueueId()); + + // mark prefetching queue completed only for topic of query mode + if (SubscriptionAgent.topic().getTopicMode(topicName).equals(TopicConstant.MODE_QUERY_VALUE)) { + prefetchingQueue.markCompleted(); + } + + if (doRemove) { + topicNameToPrefetchingQueue.remove(topicName); + SubscriptionPrefetchingQueueMetrics.getInstance() + .deregister(prefetchingQueue.getPrefetchingQueueId()); + } } public void executePrefetch(final String topicName) { @@ -176,6 +208,10 @@ public void executePrefetch(final String topicName) { LOGGER.warn("Subscription: prefetching queue bound to topic [{}] does not exist", topicName); return; } + if (prefetchingQueue.isClosed()) { + LOGGER.warn("Subscription: prefetching queue bound to topic [{}] is closed", topicName); + return; + } prefetchingQueue.executePrefetch(); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/SubscriptionPrefetchingQueue.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/SubscriptionPrefetchingQueue.java index 43aef19568148..09e076653eacc 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/SubscriptionPrefetchingQueue.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/SubscriptionPrefetchingQueue.java @@ -21,15 +21,20 @@ import org.apache.iotdb.commons.pipe.task.connection.UnboundedBlockingPendingQueue; import org.apache.iotdb.db.conf.IoTDBDescriptor; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.subscription.event.SubscriptionEvent; import org.apache.iotdb.db.subscription.event.SubscriptionEventBinaryCache; import org.apache.iotdb.pipe.api.event.Event; +import org.apache.iotdb.rpc.subscription.payload.poll.ErrorPayload; import org.apache.iotdb.rpc.subscription.payload.poll.SubscriptionCommitContext; +import org.apache.iotdb.rpc.subscription.payload.poll.SubscriptionPollResponse; +import org.apache.iotdb.rpc.subscription.payload.poll.SubscriptionPollResponseType; +import org.apache.iotdb.rpc.subscription.payload.poll.TerminationPayload; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.util.Collections; import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; @@ -46,6 +51,9 @@ public abstract class SubscriptionPrefetchingQueue { protected final Map uncommittedEvents; private final AtomicLong subscriptionCommitIdGenerator = new AtomicLong(0); + private volatile boolean isCompleted = false; + private volatile boolean isClosed = false; + public SubscriptionPrefetchingQueue( final String brokerId, final String topicName, @@ -61,11 +69,16 @@ public SubscriptionPrefetchingQueue( public abstract void executePrefetch(); - /** clean up uncommitted events */ public void cleanup() { + // clean up uncommitted events for (final SubscriptionEvent event : uncommittedEvents.values()) { + event.clearReferenceCount(); SubscriptionEventBinaryCache.getInstance().resetByteBuffer(event, true); } + uncommittedEvents.clear(); + + // no need to clean up events in inputPendingQueue, see + // org.apache.iotdb.db.pipe.task.subtask.connector.PipeConnectorSubtask.close } /////////////////////////////// commit /////////////////////////////// @@ -110,16 +123,16 @@ protected SubscriptionCommitContext generateSubscriptionCommitContext() { // leader transfers or restarts. return new SubscriptionCommitContext( IoTDBDescriptor.getInstance().getConfig().getDataNodeId(), - PipeAgent.runtime().getRebootTimes(), + PipeDataNodeAgent.runtime().getRebootTimes(), topicName, brokerId, subscriptionCommitIdGenerator.getAndIncrement()); } - protected SubscriptionCommitContext generateInvalidSubscriptionCommitContext() { + private SubscriptionCommitContext generateInvalidSubscriptionCommitContext() { return new SubscriptionCommitContext( IoTDBDescriptor.getInstance().getConfig().getDataNodeId(), - PipeAgent.runtime().getRebootTimes(), + PipeDataNodeAgent.runtime().getRebootTimes(), topicName, brokerId, -1); @@ -150,4 +163,41 @@ public long getUncommittedEventCount() { public long getCurrentCommitId() { return subscriptionCommitIdGenerator.get(); } + + /////////////////////////////// termination /////////////////////////////// + + public boolean isClosed() { + return isClosed; + } + + public void markClosed() { + isClosed = true; + } + + public boolean isCompleted() { + return isCompleted; + } + + public void markCompleted() { + isCompleted = true; + } + + public SubscriptionEvent generateSubscriptionPollTerminationResponse() { + return new SubscriptionEvent( + Collections.emptyList(), + new SubscriptionPollResponse( + SubscriptionPollResponseType.TERMINATION.getType(), + new TerminationPayload(), + generateInvalidSubscriptionCommitContext())); + } + + public SubscriptionEvent generateSubscriptionPollErrorResponse( + final String errorMessage, final boolean critical) { + return new SubscriptionEvent( + Collections.emptyList(), + new SubscriptionPollResponse( + SubscriptionPollResponseType.ERROR.getType(), + new ErrorPayload(errorMessage, critical), + generateInvalidSubscriptionCommitContext())); + } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/SubscriptionPrefetchingTabletsQueue.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/SubscriptionPrefetchingTabletsQueue.java index 195194ef3c899..935494537b3c3 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/SubscriptionPrefetchingTabletsQueue.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/SubscriptionPrefetchingTabletsQueue.java @@ -25,6 +25,7 @@ import org.apache.iotdb.db.pipe.event.UserDefinedEnrichedEvent; import org.apache.iotdb.db.pipe.event.common.tablet.PipeInsertNodeTabletInsertionEvent; import org.apache.iotdb.db.pipe.event.common.tablet.PipeRawTabletInsertionEvent; +import org.apache.iotdb.db.pipe.event.common.terminate.PipeTerminateEvent; import org.apache.iotdb.db.pipe.event.common.tsfile.PipeTsFileInsertionEvent; import org.apache.iotdb.db.pipe.resource.memory.PipeMemoryManager; import org.apache.iotdb.db.subscription.event.SubscriptionEvent; @@ -63,6 +64,15 @@ public SubscriptionPrefetchingTabletsQueue( this.prefetchingQueue = new LinkedBlockingQueue<>(); } + @Override + public void cleanup() { + super.cleanup(); + + // no need to clean up events in prefetchingQueue, since all events in prefetchingQueue are also + // in uncommittedEvents + prefetchingQueue.clear(); + } + @Override public SubscriptionEvent poll(final String consumerId) { if (prefetchingQueue.isEmpty()) { @@ -129,6 +139,17 @@ private void prefetchOnce() { continue; } + if (event instanceof PipeTerminateEvent) { + LOGGER.info( + "Subscription: SubscriptionPrefetchingTabletsQueue {} commit PipeTerminateEvent {}", + this, + event); + // commit directly + ((PipeTerminateEvent) event) + .decreaseReferenceCount(SubscriptionPrefetchingTsFileQueue.class.getName(), true); + continue; + } + if (event instanceof TabletInsertionEvent) { final List currentTablets = convertToTablets((TabletInsertionEvent) event); if (currentTablets.isEmpty()) { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/SubscriptionPrefetchingTsFileQueue.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/SubscriptionPrefetchingTsFileQueue.java index fc5a1a8a81eeb..dbb6880968113 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/SubscriptionPrefetchingTsFileQueue.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/broker/SubscriptionPrefetchingTsFileQueue.java @@ -22,11 +22,13 @@ import org.apache.iotdb.commons.pipe.event.EnrichedEvent; import org.apache.iotdb.commons.pipe.task.connection.UnboundedBlockingPendingQueue; import org.apache.iotdb.db.pipe.event.UserDefinedEnrichedEvent; +import org.apache.iotdb.db.pipe.event.common.terminate.PipeTerminateEvent; import org.apache.iotdb.db.pipe.event.common.tsfile.PipeTsFileInsertionEvent; +import org.apache.iotdb.db.subscription.event.SubscriptionEvent; +import org.apache.iotdb.db.subscription.event.SubscriptionEventBinaryCache; import org.apache.iotdb.db.subscription.event.SubscriptionTsFileEvent; import org.apache.iotdb.pipe.api.event.Event; import org.apache.iotdb.pipe.api.event.dml.insertion.TabletInsertionEvent; -import org.apache.iotdb.rpc.subscription.payload.poll.ErrorPayload; import org.apache.iotdb.rpc.subscription.payload.poll.FileInitPayload; import org.apache.iotdb.rpc.subscription.payload.poll.FilePiecePayload; import org.apache.iotdb.rpc.subscription.payload.poll.FileSealPayload; @@ -41,7 +43,6 @@ import org.slf4j.LoggerFactory; import java.io.IOException; -import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Objects; @@ -64,7 +65,22 @@ public SubscriptionPrefetchingTsFileQueue( } @Override - public SubscriptionTsFileEvent poll(final String consumerId) { + public void cleanup() { + super.cleanup(); + + // clean up events in consumerIdToCurrentEventMap + consumerIdToCurrentEventMap + .values() + .forEach( + (event) -> { + event.clearReferenceCount(); + SubscriptionEventBinaryCache.getInstance().resetByteBuffer(event, true); + }); + consumerIdToCurrentEventMap.clear(); + } + + @Override + public SubscriptionEvent poll(final String consumerId) { if (hasUnPollableOnTheFlySubscriptionTsFileEvent(consumerId)) { return null; } @@ -78,6 +94,25 @@ public SubscriptionTsFileEvent poll(final String consumerId) { Event event; while (Objects.nonNull( event = UserDefinedEnrichedEvent.maybeOf(inputPendingQueue.waitedPoll()))) { + if (!(event instanceof EnrichedEvent)) { + LOGGER.warn( + "Subscription: SubscriptionPrefetchingTsFileQueue {} only support poll EnrichedEvent. Ignore {}.", + this, + event); + continue; + } + + if (event instanceof PipeTerminateEvent) { + LOGGER.info( + "Subscription: SubscriptionPrefetchingTsFileQueue {} commit PipeTerminateEvent {}", + this, + event); + // commit directly + ((PipeTerminateEvent) event) + .decreaseReferenceCount(SubscriptionPrefetchingTsFileQueue.class.getName(), true); + continue; + } + if (event instanceof TabletInsertionEvent) { final String errorMessage = String.format( @@ -112,7 +147,7 @@ public SubscriptionTsFileEvent poll(final String consumerId) { return null; } - public synchronized @NonNull SubscriptionTsFileEvent pollTsFile( + public synchronized @NonNull SubscriptionEvent pollTsFile( final String consumerId, final String fileName, final long writingOffset) { // 1. Extract current event and check it final SubscriptionTsFileEvent event = consumerIdToCurrentEventMap.get(consumerId); @@ -257,7 +292,7 @@ public SubscriptionTsFileEvent poll(final String consumerId) { return pollTsFile(consumerId, writingOffset, event); } - private synchronized @NonNull SubscriptionTsFileEvent pollTsFile( + private synchronized @NonNull SubscriptionEvent pollTsFile( final String consumerId, final long writingOffset, final SubscriptionTsFileEvent event) { Pair newEventWithCommittable = event.matchOrResetNext(writingOffset); @@ -360,18 +395,8 @@ private synchronized SubscriptionTsFileEvent getPollableOnTheFlySubscriptionTsFi return null; } - private SubscriptionTsFileEvent generateSubscriptionPollErrorResponse( - final String errorMessage, final boolean critical) { - return new SubscriptionTsFileEvent( - Collections.emptyList(), - new SubscriptionPollResponse( - SubscriptionPollResponseType.ERROR.getType(), - new ErrorPayload(errorMessage, critical), - super.generateInvalidSubscriptionCommitContext())); - } - - private SubscriptionTsFileEvent generateSubscriptionPollErrorResponse(final String errorMessage) { + private SubscriptionEvent generateSubscriptionPollErrorResponse(final String errorMessage) { // consider non-critical by default, meaning the client can retry - return generateSubscriptionPollErrorResponse(errorMessage, false); + return super.generateSubscriptionPollErrorResponse(errorMessage, false); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/event/SubscriptionEvent.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/event/SubscriptionEvent.java index c327b7e058d73..0f7feb08e95e4 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/event/SubscriptionEvent.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/event/SubscriptionEvent.java @@ -76,6 +76,12 @@ public void decreaseReferenceCount() { } } + public void clearReferenceCount() { + for (final EnrichedEvent enrichedEvent : enrichedEvents) { + enrichedEvent.clearReferenceCount(this.getClass().getName()); + } + } + //////////////////////////// pollable //////////////////////////// public void recordLastPolledTimestamp() { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/event/SubscriptionEventBinaryCache.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/event/SubscriptionEventBinaryCache.java index 4a592f8a86f3b..5f7ea9adc5cbd 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/event/SubscriptionEventBinaryCache.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/event/SubscriptionEventBinaryCache.java @@ -106,8 +106,8 @@ private SubscriptionEventBinaryCache() { .setShrinkMethod(oldMemory -> Math.max(oldMemory / 2, 1)) .setShrinkCallback( (oldMemory, newMemory) -> { - memoryUsageCheatFactor.set( - memoryUsageCheatFactor.get() * ((double) oldMemory / newMemory)); + memoryUsageCheatFactor.updateAndGet( + factor -> factor * ((double) oldMemory / newMemory)); LOGGER.info( "SubscriptionEventBinaryCache.allocatedMemoryBlock has shrunk from {} to {}.", oldMemory, @@ -117,8 +117,8 @@ private SubscriptionEventBinaryCache() { oldMemory -> Math.min(Math.max(oldMemory, 1) * 2, maxMemorySizeInBytes)) .setExpandCallback( (oldMemory, newMemory) -> { - memoryUsageCheatFactor.set( - memoryUsageCheatFactor.get() / ((double) newMemory / oldMemory)); + memoryUsageCheatFactor.updateAndGet( + factor -> factor / ((double) newMemory / oldMemory)); LOGGER.info( "SubscriptionEventBinaryCache.allocatedMemoryBlock has expanded from {} to {}.", oldMemory, diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/receiver/SubscriptionReceiverV1.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/receiver/SubscriptionReceiverV1.java index 8339c3d3c8812..388bcc1b8e172 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/receiver/SubscriptionReceiverV1.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/receiver/SubscriptionReceiverV1.java @@ -31,7 +31,6 @@ import org.apache.iotdb.db.protocol.client.ConfigNodeClient; import org.apache.iotdb.db.protocol.client.ConfigNodeClientManager; import org.apache.iotdb.db.protocol.client.ConfigNodeInfo; -import org.apache.iotdb.db.queryengine.plan.parser.ASTVisitor; import org.apache.iotdb.db.subscription.agent.SubscriptionAgent; import org.apache.iotdb.db.subscription.broker.SubscriptionPrefetchingQueue; import org.apache.iotdb.db.subscription.event.SubscriptionEvent; @@ -72,6 +71,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import java.io.IOException; import java.nio.ByteBuffer; import java.util.Collections; import java.util.List; @@ -247,7 +247,7 @@ private TPipeSubscribeResp handlePipeSubscribeHeartbeatInternal( private TPipeSubscribeResp handlePipeSubscribeSubscribe(final PipeSubscribeSubscribeReq req) { try { return handlePipeSubscribeSubscribeInternal(req); - } catch (final SubscriptionException e) { + } catch (final SubscriptionException | IOException e) { final String exceptionMessage = String.format( "Subscription: something unexpected happened when subscribing: %s, req: %s", e, req); @@ -258,7 +258,7 @@ private TPipeSubscribeResp handlePipeSubscribeSubscribe(final PipeSubscribeSubsc } private TPipeSubscribeResp handlePipeSubscribeSubscribeInternal( - final PipeSubscribeSubscribeReq req) { + final PipeSubscribeSubscribeReq req) throws IOException { // check consumer config thread local final ConsumerConfig consumerConfig = consumerConfigThreadLocal.get(); if (Objects.isNull(consumerConfig)) { @@ -268,18 +268,21 @@ private TPipeSubscribeResp handlePipeSubscribeSubscribeInternal( } // subscribe topics - Set topicNames = req.getTopicNames(); - topicNames = topicNames.stream().map(ASTVisitor::parseIdentifier).collect(Collectors.toSet()); + final Set topicNames = req.getTopicNames(); subscribe(consumerConfig, topicNames); LOGGER.info("Subscription: consumer {} subscribe {} successfully", consumerConfig, topicNames); - return PipeSubscribeSubscribeResp.toTPipeSubscribeResp(RpcUtils.SUCCESS_STATUS); + return PipeSubscribeSubscribeResp.toTPipeSubscribeResp( + RpcUtils.SUCCESS_STATUS, + SubscriptionAgent.consumer() + .getTopicsSubscribedByConsumer( + consumerConfig.getConsumerGroupId(), consumerConfig.getConsumerId())); } private TPipeSubscribeResp handlePipeSubscribeUnsubscribe(final PipeSubscribeUnsubscribeReq req) { try { return handlePipeSubscribeUnsubscribeInternal(req); - } catch (final SubscriptionException e) { + } catch (final SubscriptionException | IOException e) { final String exceptionMessage = String.format( "Subscription: something unexpected happened when unsubscribing: %s, req: %s", @@ -291,7 +294,7 @@ private TPipeSubscribeResp handlePipeSubscribeUnsubscribe(final PipeSubscribeUns } private TPipeSubscribeResp handlePipeSubscribeUnsubscribeInternal( - final PipeSubscribeUnsubscribeReq req) { + final PipeSubscribeUnsubscribeReq req) throws IOException { // check consumer config thread local final ConsumerConfig consumerConfig = consumerConfigThreadLocal.get(); if (Objects.isNull(consumerConfig)) { @@ -302,13 +305,16 @@ private TPipeSubscribeResp handlePipeSubscribeUnsubscribeInternal( } // unsubscribe topics - Set topicNames = req.getTopicNames(); - topicNames = topicNames.stream().map(ASTVisitor::parseIdentifier).collect(Collectors.toSet()); + final Set topicNames = req.getTopicNames(); unsubscribe(consumerConfig, topicNames); LOGGER.info( "Subscription: consumer {} unsubscribe {} successfully", consumerConfig, topicNames); - return PipeSubscribeUnsubscribeResp.toTPipeSubscribeResp(RpcUtils.SUCCESS_STATUS); + return PipeSubscribeUnsubscribeResp.toTPipeSubscribeResp( + RpcUtils.SUCCESS_STATUS, + SubscriptionAgent.consumer() + .getTopicsSubscribedByConsumer( + consumerConfig.getConsumerGroupId(), consumerConfig.getConsumerId())); } private TPipeSubscribeResp handlePipeSubscribePoll(final PipeSubscribePollReq req) { @@ -403,15 +409,12 @@ private List handlePipeSubscribePollInternal( SubscriptionAgent.consumer() .getTopicsSubscribedByConsumer( consumerConfig.getConsumerGroupId(), consumerConfig.getConsumerId()); - final Set topicNames; - if (messagePayload.getTopicNames().isEmpty()) { + + Set topicNames = messagePayload.getTopicNames(); + if (topicNames.isEmpty()) { // poll all subscribed topics topicNames = subscribedTopicNames; } else { - topicNames = - messagePayload.getTopicNames().stream() - .map(ASTVisitor::parseIdentifier) - .collect(Collectors.toSet()); // filter unsubscribed topics topicNames.removeIf((topicName) -> !subscribedTopicNames.contains(topicName)); } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/task/subtask/SubscriptionConnectorSubtask.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/task/subtask/SubscriptionConnectorSubtask.java index bb4838b903e7e..b429b8399420e 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/task/subtask/SubscriptionConnectorSubtask.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/task/subtask/SubscriptionConnectorSubtask.java @@ -31,14 +31,14 @@ public class SubscriptionConnectorSubtask extends PipeConnectorSubtask { private final String consumerGroupId; public SubscriptionConnectorSubtask( - String taskID, - long creationTime, - String attributeSortedString, - int connectorIndex, - UnboundedBlockingPendingQueue inputPendingQueue, - PipeConnector outputPipeConnector, - String topicName, - String consumerGroupId) { + final String taskID, + final long creationTime, + final String attributeSortedString, + final int connectorIndex, + final UnboundedBlockingPendingQueue inputPendingQueue, + final PipeConnector outputPipeConnector, + final String topicName, + final String consumerGroupId) { super( taskID, creationTime, @@ -56,7 +56,7 @@ protected boolean executeOnce() { return false; } - SubscriptionAgent.broker().executePrefetch(this); + SubscriptionAgent.broker().executePrefetch(consumerGroupId, topicName); // always return true return true; } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/task/subtask/SubscriptionConnectorSubtaskLifeCycle.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/task/subtask/SubscriptionConnectorSubtaskLifeCycle.java index 14633dfafefe9..41e690cbce918 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/task/subtask/SubscriptionConnectorSubtaskLifeCycle.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/task/subtask/SubscriptionConnectorSubtaskLifeCycle.java @@ -38,9 +38,9 @@ public class SubscriptionConnectorSubtaskLifeCycle extends PipeConnectorSubtaskL private int registeredTaskCount; public SubscriptionConnectorSubtaskLifeCycle( - PipeConnectorSubtaskExecutor executor, // SubscriptionSubtaskExecutor - PipeConnectorSubtask subtask, // SubscriptionConnectorSubtask - UnboundedBlockingPendingQueue pendingQueue) { + final PipeConnectorSubtaskExecutor executor, // SubscriptionSubtaskExecutor + final PipeConnectorSubtask subtask, // SubscriptionConnectorSubtask + final UnboundedBlockingPendingQueue pendingQueue) { super(executor, subtask, pendingQueue); runningTaskCount = 0; @@ -54,6 +54,7 @@ public synchronized void register() { } if (registeredTaskCount == 0) { + // bind prefetching queue SubscriptionAgent.broker().bindPrefetchingQueue((SubscriptionConnectorSubtask) subtask); executor.register(subtask); runningTaskCount = 0; @@ -68,11 +69,13 @@ public synchronized void register() { } @Override - public synchronized boolean deregister(String ignored) { + public synchronized boolean deregister(final String ignored) { if (registeredTaskCount <= 0) { throw new IllegalStateException("registeredTaskCount <= 0"); } + // no need to discard events of pipe + try { if (registeredTaskCount > 1) { return false; @@ -91,45 +94,15 @@ public synchronized boolean deregister(String ignored) { } } - @Override - public synchronized void start() { - if (runningTaskCount < 0) { - throw new IllegalStateException("runningTaskCount < 0"); - } - - if (runningTaskCount == 0) { - executor.start(subtask.getTaskID()); - } - - runningTaskCount++; - LOGGER.info( - "Start subtask {}. runningTaskCount: {}, registeredTaskCount: {}", - subtask, - runningTaskCount, - registeredTaskCount); - } - - @Override - public synchronized void stop() { - if (runningTaskCount <= 0) { - throw new IllegalStateException("runningTaskCount <= 0"); - } - - if (runningTaskCount == 1) { - executor.stop(subtask.getTaskID()); - } - - runningTaskCount--; - LOGGER.info( - "Stop subtask {}. runningTaskCount: {}, registeredTaskCount: {}", - subtask, - runningTaskCount, - registeredTaskCount); - } - @Override public synchronized void close() { - executor.deregister(subtask.getTaskID()); - SubscriptionAgent.broker().unbindPrefetchingQueue((SubscriptionConnectorSubtask) subtask); + super.close(); + + // Here, the prefetching queue is not actually removed, because it's uncertain whether the + // corresponding underlying pipe is automatically terminated. The actual removal is carried out + // when dropping the subscription. + final String consumerGroupId = ((SubscriptionConnectorSubtask) subtask).getConsumerGroupId(); + final String topicName = ((SubscriptionConnectorSubtask) subtask).getTopicName(); + SubscriptionAgent.broker().unbindPrefetchingQueue(consumerGroupId, topicName, false); } } diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/task/subtask/SubscriptionConnectorSubtaskManager.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/task/subtask/SubscriptionConnectorSubtaskManager.java index 35a4a3ab4ac81..45d62174e4be8 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/task/subtask/SubscriptionConnectorSubtaskManager.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/subscription/task/subtask/SubscriptionConnectorSubtaskManager.java @@ -26,7 +26,7 @@ import org.apache.iotdb.commons.pipe.plugin.builtin.BuiltinPipePlugin; import org.apache.iotdb.commons.pipe.progress.PipeEventCommitManager; import org.apache.iotdb.commons.pipe.task.connection.UnboundedBlockingPendingQueue; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.execution.PipeConnectorSubtaskExecutor; import org.apache.iotdb.db.pipe.metric.PipeDataRegionEventCounter; import org.apache.iotdb.db.pipe.task.subtask.connector.PipeConnectorSubtask; @@ -102,7 +102,7 @@ public synchronized String register( : new UnboundedBlockingPendingQueue<>(new PipeDataRegionEventCounter()); final PipeConnector pipeConnector = - PipeAgent.plugin().dataRegion().reflectConnector(pipeConnectorParameters); + PipeDataNodeAgent.plugin().dataRegion().reflectConnector(pipeConnectorParameters); // 1. Construct, validate and customize PipeConnector, and then handshake (create connection) // with the target try { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/tools/WalChecker.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/tools/WalChecker.java index cbf2ead7464e5..5e53e9f664a62 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/tools/WalChecker.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/tools/WalChecker.java @@ -22,15 +22,14 @@ import org.apache.iotdb.db.storageengine.dataregion.wal.buffer.WALEntry; import org.apache.iotdb.db.storageengine.dataregion.wal.buffer.WALEntryType; import org.apache.iotdb.db.storageengine.dataregion.wal.exception.WALException; +import org.apache.iotdb.db.storageengine.dataregion.wal.io.WALInputStream; import org.apache.iotdb.db.storageengine.dataregion.wal.utils.WALFileUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.BufferedInputStream; import java.io.DataInputStream; import java.io.File; -import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; @@ -86,8 +85,7 @@ public List doCheck() throws WALException { } private boolean checkFile(File walFile) { - try (DataInputStream logStream = - new DataInputStream(new BufferedInputStream(new FileInputStream(walFile)))) { + try (DataInputStream logStream = new DataInputStream(new WALInputStream(walFile))) { while (logStream.available() > 0) { WALEntry walEntry = WALEntry.deserialize(logStream); if (walEntry.getType() == WALEntryType.WAL_FILE_INFO_END_MARKER) { diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/MemUtils.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/MemUtils.java index 89af1e7842756..5a09d96f7e2c8 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/MemUtils.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/MemUtils.java @@ -203,7 +203,7 @@ public static String bytesCntToStr(long inputCnt) { } public static long strToBytesCnt(String str) { - if (str == null) { + if (str == null || str.isEmpty()) { return 0; } str = str.toLowerCase(); diff --git a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/TypeInferenceUtils.java b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/TypeInferenceUtils.java index 5665fd9aa5a98..165ea4b8b0fa0 100644 --- a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/TypeInferenceUtils.java +++ b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/TypeInferenceUtils.java @@ -20,6 +20,7 @@ package org.apache.iotdb.db.utils; import org.apache.iotdb.commons.path.MeasurementPath; +import org.apache.iotdb.db.conf.IoTDBConfig; import org.apache.iotdb.db.conf.IoTDBDescriptor; import org.apache.iotdb.db.exception.sql.SemanticException; import org.apache.iotdb.db.queryengine.plan.analyze.ExpressionUtils; @@ -40,17 +41,7 @@ public class TypeInferenceUtils { - private static final TSDataType booleanStringInferType = - IoTDBDescriptor.getInstance().getConfig().getBooleanStringInferType(); - - private static final TSDataType integerStringInferType = - IoTDBDescriptor.getInstance().getConfig().getIntegerStringInferType(); - - private static final TSDataType floatingStringInferType = - IoTDBDescriptor.getInstance().getConfig().getFloatingStringInferType(); - - private static final TSDataType nanStringInferType = - IoTDBDescriptor.getInstance().getConfig().getNanStringInferType(); + private static final IoTDBConfig CONF = IoTDBDescriptor.getInstance().getConfig(); private TypeInferenceUtils() {} @@ -108,18 +99,18 @@ public static TSDataType getPredictedDataType(Object value, boolean inferType) { } else if (inferType) { String strValue = value.toString(); if (isBoolean(strValue)) { - return booleanStringInferType; + return CONF.getBooleanStringInferType(); } else if (isNumber(strValue)) { if (isLong(StringUtils.trim(strValue))) { - return integerStringInferType; + return CONF.getIntegerStringInferType(); } else { - return floatingStringInferType; + return CONF.getFloatingStringInferType(); } } else if ("null".equals(strValue) || "NULL".equals(strValue)) { return null; // "NaN" is returned if the NaN Literal is given in Parser } else if ("NaN".equals(strValue)) { - return nanStringInferType; + return CONF.getNanStringInferType(); } else if (isBlob(strValue)) { return TSDataType.BLOB; } else { diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/cache/DataNodeSchemaCacheTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/cache/DataNodeSchemaCacheTest.java index f264bd4ba3b19..fc1e2f6ff6943 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/cache/DataNodeSchemaCacheTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/cache/DataNodeSchemaCacheTest.java @@ -206,18 +206,21 @@ private ISchemaTree generateSchemaTree1() throws IllegalPathException { new MeasurementSchema("s1", TSDataType.INT32), s1TagMap, null, + null, false); schemaTree.appendSingleMeasurement( new PartialPath("root.sg1.d1.s2"), new MeasurementSchema("s2", TSDataType.FLOAT), null, null, + null, false); schemaTree.appendSingleMeasurement( new PartialPath("root.sg1.d1.s3"), new MeasurementSchema("s3", TSDataType.BOOLEAN), null, null, + null, false); schemaTree.setDatabases(Collections.singleton("root.sg1")); return schemaTree; @@ -231,18 +234,21 @@ private ISchemaTree generateSchemaTree2() throws IllegalPathException { new MeasurementSchema("s3", TSDataType.BOOLEAN), null, null, + null, false); schemaTree.appendSingleMeasurement( new PartialPath("root.sg1.d1.s4"), new MeasurementSchema("s4", TSDataType.TEXT), null, null, + null, false); schemaTree.appendSingleMeasurement( new PartialPath("root.sg1.d1.s5"), new MeasurementSchema("s5", TSDataType.INT64), null, null, + null, false); schemaTree.setDatabases(Collections.singleton("root.sg1")); return schemaTree; diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/schemaRegion/SchemaRegionBasicTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/schemaRegion/SchemaRegionBasicTest.java index 4064376cd96f0..6dcb9200c059a 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/schemaRegion/SchemaRegionBasicTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/schemaRegion/SchemaRegionBasicTest.java @@ -103,11 +103,11 @@ public void testFetchSchemaPerfomance() throws Exception { } } patternTree.constructTree(); - schemaRegion.fetchSchema(patternTree, Collections.EMPTY_MAP, false, true); + schemaRegion.fetchSeriesSchema(patternTree, Collections.EMPTY_MAP, false, false, true, false); long startTime; startTime = System.currentTimeMillis(); for (int i = 0; i < 10; i++) { - schemaRegion.fetchSchema(patternTree, Collections.EMPTY_MAP, false, true); + schemaRegion.fetchSeriesSchema(patternTree, Collections.EMPTY_MAP, false, false, true, false); } System.out.println("cost time: " + (System.currentTimeMillis() - startTime)); } @@ -153,7 +153,8 @@ public void testFetchSchema() throws Exception { patternTree.constructTree(); ; ClusterSchemaTree schemas = - schemaRegion.fetchSchema(patternTree, Collections.EMPTY_MAP, true, true); + schemaRegion.fetchSeriesSchema( + patternTree, Collections.EMPTY_MAP, true, false, true, false); List measurementPaths = schemas.searchMeasurementPaths(new PartialPath("root.sg.wf01.wt01.*")).left; Assert.assertEquals(measurementPaths.size(), 2); @@ -182,7 +183,9 @@ public void testFetchSchema() throws Exception { patternTree = new PathPatternTree(); patternTree.appendPathPattern(new PartialPath("root.sg.wf01.wt01.temp")); patternTree.constructTree(); - schemas = schemaRegion.fetchSchema(patternTree, Collections.EMPTY_MAP, false, true); + schemas = + schemaRegion.fetchSeriesSchema( + patternTree, Collections.EMPTY_MAP, false, false, true, false); measurementPaths = schemas.searchMeasurementPaths(new PartialPath("root.sg.wf01.wt01.temp")).left; Assert.assertEquals(measurementPaths.size(), 1); @@ -368,7 +371,7 @@ public void testDeleteTimeseries() throws Exception { schemaRegion.deleteTimeseriesInBlackList(patternTree); List schemas = schemaRegion - .fetchSchema(ALL_MATCH_SCOPE, Collections.EMPTY_MAP, false, true) + .fetchSeriesSchema(ALL_MATCH_SCOPE, Collections.EMPTY_MAP, false, false, true, false) .searchMeasurementPaths(ALL_MATCH_PATTERN) .left; Assert.assertEquals(1, schemas.size()); diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/schemaRegion/SchemaRegionSimpleRecoverTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/schemaRegion/SchemaRegionSimpleRecoverTest.java index d85d203ec64d7..0811e3c35efdc 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/schemaRegion/SchemaRegionSimpleRecoverTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/schemaRegion/SchemaRegionSimpleRecoverTest.java @@ -84,15 +84,25 @@ public void testRecoverWithAlignedTemplate() throws Exception { new PartialPath("root.sg.d1"), 2, templateId), template); ClusterSchemaTree schemaTree = - schemaRegion.fetchSchema( - ALL_MATCH_SCOPE, Collections.singletonMap(templateId, template), true, true); + schemaRegion.fetchSeriesSchema( + ALL_MATCH_SCOPE, + Collections.singletonMap(templateId, template), + true, + false, + true, + false); Assert.assertTrue(schemaTree.getAllDevices().get(0).isAligned()); simulateRestart(); schemaRegion = getSchemaRegion("root.sg", 0); schemaTree = - schemaRegion.fetchSchema( - ALL_MATCH_SCOPE, Collections.singletonMap(templateId, template), true, true); + schemaRegion.fetchSeriesSchema( + ALL_MATCH_SCOPE, + Collections.singletonMap(templateId, template), + true, + false, + true, + false); Assert.assertTrue(schemaTree.getAllDevices().get(0).isAligned()); } } diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/schemaRegion/SchemaRegionTemplateTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/schemaRegion/SchemaRegionTemplateTest.java index 3aa6d9019fdbf..555a081f00151 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/schemaRegion/SchemaRegionTemplateTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/metadata/schemaRegion/SchemaRegionTemplateTest.java @@ -77,8 +77,13 @@ public void testFetchNestedTemplateDevice() throws Exception { new PartialPath("root.sg.d1.GPS"), 3, templateId), template); ClusterSchemaTree schemaTree = - schemaRegion.fetchSchema( - ALL_MATCH_SCOPE, Collections.singletonMap(templateId, template), true, true); + schemaRegion.fetchSeriesSchema( + ALL_MATCH_SCOPE, + Collections.singletonMap(templateId, template), + true, + false, + true, + false); Assert.assertEquals(2, schemaTree.getAllDevices().size()); for (DeviceSchemaInfo deviceSchemaInfo : schemaTree.getAllDevices()) { Assert.assertEquals(templateId, deviceSchemaInfo.getTemplateId()); @@ -213,7 +218,7 @@ public void testFetchSchemaWithTemplate() throws Exception { // check fetch schema ClusterSchemaTree schemaTree = - schemaRegion.fetchSchema(ALL_MATCH_SCOPE, templateMap, true, true); + schemaRegion.fetchSeriesSchema(ALL_MATCH_SCOPE, templateMap, true, false, true, false); schemaTree.setTemplateMap(templateMap); List schemas = schemaTree.searchMeasurementPaths(ALL_MATCH_PATTERN).left; Assert.assertEquals(expectedTimeseries.size(), schemas.size()); @@ -258,16 +263,16 @@ public void testDeleteSchemaWithTemplate() throws Exception { patternTree.appendFullPath(new PartialPath("root.db.d1.s1")); ClusterSchemaTree schemaTree = - schemaRegion.fetchSchema( - patternTree, Collections.singletonMap(templateId, template), false, true); + schemaRegion.fetchSeriesSchema( + patternTree, Collections.singletonMap(templateId, template), false, false, true, false); schemaTree.setTemplateMap(Collections.singletonMap(templateId, template)); Assert.assertEquals( 1, schemaTree.searchMeasurementPaths(new PartialPath("root.db.d1.s1")).left.size()); patternTree = new PathPatternTree(); patternTree.appendFullPath(new PartialPath("root.db.d1.s3")); schemaTree = - schemaRegion.fetchSchema( - patternTree, Collections.singletonMap(templateId, template), false, true); + schemaRegion.fetchSeriesSchema( + patternTree, Collections.singletonMap(templateId, template), false, false, true, false); schemaTree.setTemplateMap(Collections.singletonMap(templateId, template)); Assert.assertEquals( 0, schemaTree.searchMeasurementPaths(new PartialPath("root.db.d1.s3")).left.size()); diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/connector/PipeDataNodeThriftRequestTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/connector/PipeDataNodeThriftRequestTest.java index 069917dfb429a..9cd69a452f6ee 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/connector/PipeDataNodeThriftRequestTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/connector/PipeDataNodeThriftRequestTest.java @@ -38,9 +38,11 @@ import org.apache.iotdb.db.queryengine.plan.statement.Statement; import org.apache.iotdb.rpc.RpcUtils; +import org.apache.tsfile.common.conf.TSFileConfig; import org.apache.tsfile.enums.TSDataType; import org.apache.tsfile.file.metadata.enums.CompressionType; import org.apache.tsfile.file.metadata.enums.TSEncoding; +import org.apache.tsfile.utils.Binary; import org.apache.tsfile.utils.PublicBAOS; import org.apache.tsfile.utils.ReadWriteIOUtils; import org.apache.tsfile.write.record.Tablet; @@ -52,6 +54,7 @@ import java.io.DataOutputStream; import java.io.IOException; import java.nio.ByteBuffer; +import java.time.LocalDate; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -62,9 +65,9 @@ public class PipeDataNodeThriftRequestTest { @Test public void testPipeTransferDataNodeHandshakeReq() throws IOException { - PipeTransferDataNodeHandshakeV1Req req = + final PipeTransferDataNodeHandshakeV1Req req = PipeTransferDataNodeHandshakeV1Req.toTPipeTransferReq(TIME_PRECISION); - PipeTransferDataNodeHandshakeV1Req deserializeReq = + final PipeTransferDataNodeHandshakeV1Req deserializeReq = PipeTransferDataNodeHandshakeV1Req.fromTPipeTransferReq(req); Assert.assertEquals(req.getVersion(), deserializeReq.getVersion()); @@ -76,7 +79,7 @@ public void testPipeTransferDataNodeHandshakeReq() throws IOException { @Test public void testPipeTransferInsertNodeReq() { - PipeTransferTabletInsertNodeReq req = + final PipeTransferTabletInsertNodeReq req = PipeTransferTabletInsertNodeReq.toTPipeTransferReq( new InsertRowNode( new PlanNodeId(""), @@ -87,7 +90,7 @@ public void testPipeTransferInsertNodeReq() { 1, new Object[] {1}, false)); - PipeTransferTabletInsertNodeReq deserializeReq = + final PipeTransferTabletInsertNodeReq deserializeReq = PipeTransferTabletInsertNodeReq.fromTPipeTransferReq(req); Assert.assertEquals(req.getVersion(), deserializeReq.getVersion()); @@ -96,8 +99,8 @@ public void testPipeTransferInsertNodeReq() { Assert.assertEquals(req.getInsertNode(), deserializeReq.getInsertNode()); - Statement statement = req.constructStatement(); - List paths = new ArrayList<>(); + final Statement statement = req.constructStatement(); + final List paths = new ArrayList<>(); paths.add(new PartialPath(new String[] {"root", "sg", "d", "s"})); Assert.assertEquals(statement.getPaths(), paths); } @@ -105,9 +108,9 @@ public void testPipeTransferInsertNodeReq() { @Test public void testPipeTransferTabletBinaryReq() { // Not do real test here since "serializeToWal" needs private inner class of walBuffer - PipeTransferTabletBinaryReq req = + final PipeTransferTabletBinaryReq req = PipeTransferTabletBinaryReq.toTPipeTransferReq(ByteBuffer.wrap(new byte[] {'a', 'b'})); - PipeTransferTabletBinaryReq deserializeReq = + final PipeTransferTabletBinaryReq deserializeReq = PipeTransferTabletBinaryReq.fromTPipeTransferReq(req); Assert.assertEquals(req.getVersion(), deserializeReq.getVersion()); @@ -117,7 +120,7 @@ public void testPipeTransferTabletBinaryReq() { @Test public void testPipeTransferSchemaPlanReq() { - PipeTransferPlanNodeReq req = + final PipeTransferPlanNodeReq req = PipeTransferPlanNodeReq.toTPipeTransferReq( new CreateAlignedTimeSeriesNode( new PlanNodeId(""), @@ -130,7 +133,8 @@ public void testPipeTransferSchemaPlanReq() { null, null)); - PipeTransferPlanNodeReq deserializeReq = PipeTransferPlanNodeReq.fromTPipeTransferReq(req); + final PipeTransferPlanNodeReq deserializeReq = + PipeTransferPlanNodeReq.fromTPipeTransferReq(req); Assert.assertEquals(req.getVersion(), deserializeReq.getVersion()); Assert.assertEquals(req.getType(), deserializeReq.getType()); @@ -149,22 +153,33 @@ public void testPipeTransferTabletReq() { schemaList.add(new MeasurementSchema("s4", TSDataType.DOUBLE)); schemaList.add(new MeasurementSchema("s5", TSDataType.BOOLEAN)); schemaList.add(new MeasurementSchema("s6", TSDataType.TEXT)); - Tablet t = new Tablet("root.sg.d", schemaList, 1024); + schemaList.add(new MeasurementSchema("s7", TSDataType.TIMESTAMP)); + schemaList.add(new MeasurementSchema("s8", TSDataType.DATE)); + schemaList.add(new MeasurementSchema("s9", TSDataType.BLOB)); + schemaList.add(new MeasurementSchema("s10", TSDataType.STRING)); + final Tablet t = new Tablet("root.sg.d", schemaList, 1024); t.rowSize = 2; t.addTimestamp(0, 2000); t.addTimestamp(1, 1000); t.addValue("s1", 0, 2); t.addValue("s6", 0, "2"); + t.addValue("s8", 0, LocalDate.of(2024, 2, 2)); + t.addValue("s9", 0, new Binary("2", TSFileConfig.STRING_CHARSET)); + t.addValue("s10", 0, "2"); t.addValue("s1", 1, 1); t.addValue("s6", 1, "1"); - PipeTransferTabletRawReq req = PipeTransferTabletRawReq.toTPipeTransferReq(t, false); - PipeTransferTabletRawReq deserializeReq = PipeTransferTabletRawReq.fromTPipeTransferReq(req); + t.addValue("s8", 1, LocalDate.of(2024, 1, 1)); + t.addValue("s9", 1, new Binary("1", TSFileConfig.STRING_CHARSET)); + t.addValue("s10", 1, "1"); + final PipeTransferTabletRawReq req = PipeTransferTabletRawReq.toTPipeTransferReq(t, false); + final PipeTransferTabletRawReq deserializeReq = + PipeTransferTabletRawReq.fromTPipeTransferReq(req); Assert.assertEquals(req.getVersion(), deserializeReq.getVersion()); Assert.assertEquals(req.getType(), deserializeReq.getType()); Assert.assertArrayEquals(req.getBody(), deserializeReq.getBody()); - Statement statement = + final Statement statement = req.constructStatement(); // will call PipeTransferTabletRawReq.sortTablet() here List paths = new ArrayList<>(); paths.add(new PartialPath(new String[] {"root", "sg", "d", "s1"})); @@ -173,8 +188,12 @@ public void testPipeTransferTabletReq() { paths.add(new PartialPath(new String[] {"root", "sg", "d", "s4"})); paths.add(new PartialPath(new String[] {"root", "sg", "d", "s5"})); paths.add(new PartialPath(new String[] {"root", "sg", "d", "s6"})); + paths.add(new PartialPath(new String[] {"root", "sg", "d", "s7"})); + paths.add(new PartialPath(new String[] {"root", "sg", "d", "s8"})); + paths.add(new PartialPath(new String[] {"root", "sg", "d", "s9"})); + paths.add(new PartialPath(new String[] {"root", "sg", "d", "s10"})); Assert.assertEquals(statement.getPaths(), paths); - } catch (IOException e) { + } catch (final IOException e) { Assert.fail(); } } @@ -185,7 +204,7 @@ public void testPipeTransferTabletBatchReq() throws IOException { final List insertNodeBuffers = new ArrayList<>(); final List tabletBuffers = new ArrayList<>(); - InsertRowNode node = + final InsertRowNode node = new InsertRowNode( new PlanNodeId(""), new PartialPath(new String[] {"root", "sg", "d"}), @@ -211,14 +230,25 @@ public void testPipeTransferTabletBatchReq() throws IOException { schemaList.add(new MeasurementSchema("s4", TSDataType.DOUBLE)); schemaList.add(new MeasurementSchema("s5", TSDataType.BOOLEAN)); schemaList.add(new MeasurementSchema("s6", TSDataType.TEXT)); - Tablet t = new Tablet("root.sg.d", schemaList, 1024); + schemaList.add(new MeasurementSchema("s7", TSDataType.TIMESTAMP)); + schemaList.add(new MeasurementSchema("s8", TSDataType.DATE)); + schemaList.add(new MeasurementSchema("s9", TSDataType.BLOB)); + schemaList.add(new MeasurementSchema("s10", TSDataType.STRING)); + + final Tablet t = new Tablet("root.sg.d", schemaList, 1024); t.rowSize = 2; t.addTimestamp(0, 2000); t.addTimestamp(1, 1000); t.addValue("s1", 0, 2); t.addValue("s6", 0, "2"); + t.addValue("s8", 0, LocalDate.of(2024, 2, 2)); + t.addValue("s9", 0, new Binary("2", TSFileConfig.STRING_CHARSET)); + t.addValue("s10", 0, "2"); t.addValue("s1", 1, 1); t.addValue("s6", 1, "1"); + t.addValue("s8", 1, LocalDate.of(2024, 1, 1)); + t.addValue("s9", 1, new Binary("1", TSFileConfig.STRING_CHARSET)); + t.addValue("s10", 1, "1"); try (final PublicBAOS byteArrayOutputStream = new PublicBAOS(); final DataOutputStream outputStream = new DataOutputStream(byteArrayOutputStream)) { @@ -228,11 +258,11 @@ public void testPipeTransferTabletBatchReq() throws IOException { ByteBuffer.wrap(byteArrayOutputStream.getBuf(), 0, byteArrayOutputStream.size())); } - PipeTransferTabletBatchReq req = + final PipeTransferTabletBatchReq req = PipeTransferTabletBatchReq.toTPipeTransferReq( binaryBuffers, insertNodeBuffers, tabletBuffers); - PipeTransferTabletBatchReq deserializedReq = + final PipeTransferTabletBatchReq deserializedReq = PipeTransferTabletBatchReq.fromTPipeTransferReq(req); Assert.assertArrayEquals( @@ -244,12 +274,12 @@ public void testPipeTransferTabletBatchReq() throws IOException { @Test public void testPipeTransferFilePieceReq() throws IOException { - byte[] body = "testPipeTransferFilePieceReq".getBytes(); - String fileName = "1.tsfile"; + final byte[] body = "testPipeTransferFilePieceReq".getBytes(); + final String fileName = "1.tsfile"; - PipeTransferTsFilePieceReq req = + final PipeTransferTsFilePieceReq req = PipeTransferTsFilePieceReq.toTPipeTransferReq(fileName, 0, body); - PipeTransferTsFilePieceReq deserializeReq = + final PipeTransferTsFilePieceReq deserializeReq = PipeTransferTsFilePieceReq.fromTPipeTransferReq(req); Assert.assertEquals(req.getVersion(), deserializeReq.getVersion()); @@ -263,12 +293,12 @@ public void testPipeTransferFilePieceReq() throws IOException { @Test public void testPipeTransferFilePieceWithModReq() throws IOException { - byte[] body = "testPipeTransferFilePieceWithModReq".getBytes(); - String fileName = "1.tsfile.mod"; + final byte[] body = "testPipeTransferFilePieceWithModReq".getBytes(); + final String fileName = "1.tsfile.mod"; - PipeTransferTsFilePieceWithModReq req = + final PipeTransferTsFilePieceWithModReq req = PipeTransferTsFilePieceWithModReq.toTPipeTransferReq(fileName, 0, body); - PipeTransferTsFilePieceWithModReq deserializeReq = + final PipeTransferTsFilePieceWithModReq deserializeReq = PipeTransferTsFilePieceWithModReq.fromTPipeTransferReq(req); Assert.assertEquals(req.getVersion(), deserializeReq.getVersion()); @@ -282,12 +312,12 @@ public void testPipeTransferFilePieceWithModReq() throws IOException { @Test public void testPipeTransferSchemaSnapshotPieceReq() throws IOException { - byte[] body = "testPipeTransferSchemaSnapshotPieceReq".getBytes(); - String fileName = "1.temp"; + final byte[] body = "testPipeTransferSchemaSnapshotPieceReq".getBytes(); + final String fileName = "1.temp"; - PipeTransferSchemaSnapshotPieceReq req = + final PipeTransferSchemaSnapshotPieceReq req = PipeTransferSchemaSnapshotPieceReq.toTPipeTransferReq(fileName, 0, body); - PipeTransferSchemaSnapshotPieceReq deserializeReq = + final PipeTransferSchemaSnapshotPieceReq deserializeReq = PipeTransferSchemaSnapshotPieceReq.fromTPipeTransferReq(req); Assert.assertEquals(req.getVersion(), deserializeReq.getVersion()); @@ -301,10 +331,12 @@ public void testPipeTransferSchemaSnapshotPieceReq() throws IOException { @Test public void testPipeTransferTsFileSealReq() throws IOException { - String fileName = "1.tsfile"; + final String fileName = "1.tsfile"; - PipeTransferTsFileSealReq req = PipeTransferTsFileSealReq.toTPipeTransferReq(fileName, 100); - PipeTransferTsFileSealReq deserializeReq = PipeTransferTsFileSealReq.fromTPipeTransferReq(req); + final PipeTransferTsFileSealReq req = + PipeTransferTsFileSealReq.toTPipeTransferReq(fileName, 100); + final PipeTransferTsFileSealReq deserializeReq = + PipeTransferTsFileSealReq.fromTPipeTransferReq(req); Assert.assertEquals(req.getVersion(), deserializeReq.getVersion()); Assert.assertEquals(req.getType(), deserializeReq.getType()); @@ -316,16 +348,16 @@ public void testPipeTransferTsFileSealReq() throws IOException { @Test public void testPipeTransferSchemaSnapshotSealReq() throws IOException { - String mTreeSnapshotName = "mtree.snapshot"; - String tLogName = "tlog.txt"; - String databaseName = "root.db"; + final String mTreeSnapshotName = "mtree.snapshot"; + final String tLogName = "tlog.txt"; + final String databaseName = "root.db"; // CREATE_TIME_SERIES - String typeString = "19"; + final String typeString = "19"; - PipeTransferSchemaSnapshotSealReq req = + final PipeTransferSchemaSnapshotSealReq req = PipeTransferSchemaSnapshotSealReq.toTPipeTransferReq( "root.**", mTreeSnapshotName, 100, tLogName, 10, databaseName, typeString); - PipeTransferSchemaSnapshotSealReq deserializeReq = + final PipeTransferSchemaSnapshotSealReq deserializeReq = PipeTransferSchemaSnapshotSealReq.fromTPipeTransferReq(req); Assert.assertEquals(req.getVersion(), deserializeReq.getVersion()); @@ -339,9 +371,9 @@ public void testPipeTransferSchemaSnapshotSealReq() throws IOException { @Test public void testPipeTransferFilePieceResp() throws IOException { - PipeTransferFilePieceResp resp = + final PipeTransferFilePieceResp resp = PipeTransferFilePieceResp.toTPipeTransferResp(RpcUtils.SUCCESS_STATUS, 100); - PipeTransferFilePieceResp deserializeResp = + final PipeTransferFilePieceResp deserializeResp = PipeTransferFilePieceResp.fromTPipeTransferResp(resp); Assert.assertEquals(resp.getStatus(), deserializeResp.getStatus()); diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/event/PipeDataTypeTransformerTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/event/PipeDataTypeTransformerTest.java index ee05f26fb82be..a2249a35e50e6 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/event/PipeDataTypeTransformerTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/event/PipeDataTypeTransformerTest.java @@ -50,6 +50,10 @@ public void createDataTypeList() { tsDataTypeList.add(TSDataType.DOUBLE); tsDataTypeList.add(TSDataType.BOOLEAN); tsDataTypeList.add(TSDataType.TEXT); + tsDataTypeList.add(TSDataType.TIMESTAMP); + tsDataTypeList.add(TSDataType.DATE); + tsDataTypeList.add(TSDataType.BLOB); + tsDataTypeList.add(TSDataType.STRING); tsDataTypeList.add(null); nullTypeList = null; @@ -60,14 +64,19 @@ public void createDataTypeList() { typeList.add(Type.DOUBLE); typeList.add(Type.BOOLEAN); typeList.add(Type.TEXT); + typeList.add(Type.TIMESTAMP); + typeList.add(Type.DATE); + typeList.add(Type.BLOB); + typeList.add(Type.STRING); typeList.add(null); } @Test public void testDataTypeTransformer() { - List nullResultList = + final List nullResultList = PipeDataTypeTransformer.transformToPipeDataTypeList(nullTsDataTypeList); - List resultList = PipeDataTypeTransformer.transformToPipeDataTypeList(tsDataTypeList); + final List resultList = + PipeDataTypeTransformer.transformToPipeDataTypeList(tsDataTypeList); Assert.assertEquals(nullResultList, nullTypeList); Assert.assertEquals(resultList, typeList); } diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/event/PipeTabletInsertionEventTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/event/PipeTabletInsertionEventTest.java index 8c4d9ce691746..44fa83cca6235 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/event/PipeTabletInsertionEventTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/event/PipeTabletInsertionEventTest.java @@ -38,6 +38,7 @@ import org.junit.Before; import org.junit.Test; +import java.time.LocalDate; import java.util.Arrays; public class PipeTabletInsertionEventTest { @@ -49,7 +50,8 @@ public class PipeTabletInsertionEventTest { final String deviceId = "root.sg.d1"; final long[] times = new long[] {110L, 111L, 112L, 113L, 114L}; - final String[] measurementIds = new String[] {"s1", "s2", "s3", "s4", "s5", "s6"}; + final String[] measurementIds = + new String[] {"s1", "s2", "s3", "s4", "s5", "s6", "s7", "s8", "s9", "s10"}; final TSDataType[] dataTypes = new TSDataType[] { TSDataType.INT32, @@ -57,10 +59,14 @@ public class PipeTabletInsertionEventTest { TSDataType.FLOAT, TSDataType.DOUBLE, TSDataType.BOOLEAN, - TSDataType.TEXT + TSDataType.TEXT, + TSDataType.TIMESTAMP, + TSDataType.DATE, + TSDataType.BLOB, + TSDataType.STRING, }; - final MeasurementSchema[] schemas = new MeasurementSchema[6]; + final MeasurementSchema[] schemas = new MeasurementSchema[10]; final String pattern = "root.sg.d1"; @@ -90,6 +96,10 @@ private void createInsertRowNode() throws IllegalPathException { values[3] = 1D; values[4] = false; values[5] = BytesUtils.valueOf("text"); + values[6] = 20000L; + values[7] = LocalDate.of(2024, 1, 1); + values[8] = BytesUtils.valueOf("blob"); + values[9] = BytesUtils.valueOf("string"); insertRowNode = new InsertRowNode( @@ -125,6 +135,10 @@ private void createInsertTabletNode() throws IllegalPathException { values[3] = new double[times.length]; values[4] = new boolean[times.length]; values[5] = new Binary[times.length]; + values[6] = new long[times.length]; + values[7] = new LocalDate[times.length]; + values[8] = new Binary[times.length]; + values[9] = new Binary[times.length]; for (int r = 0; r < times.length; r++) { ((int[]) values[0])[r] = 100; @@ -133,6 +147,10 @@ private void createInsertTabletNode() throws IllegalPathException { ((double[]) values[3])[r] = 1D; ((boolean[]) values[4])[r] = false; ((Binary[]) values[5])[r] = BytesUtils.valueOf("text"); + ((long[]) values[6])[r] = 20000L; + ((LocalDate[]) values[7])[r] = LocalDate.of(2024, 1, 1); + ((Binary[]) values[8])[r] = BytesUtils.valueOf("blob"); + ((Binary[]) values[9])[r] = BytesUtils.valueOf("string"); } this.insertTabletNode = @@ -177,6 +195,10 @@ private void createTablet() { values[3] = new double[1]; values[4] = new boolean[1]; values[5] = new Binary[1]; + values[6] = new long[times.length]; + values[7] = new LocalDate[times.length]; + values[8] = new Binary[times.length]; + values[9] = new Binary[times.length]; for (int r = 0; r < 1; r++) { ((int[]) values[0])[r] = 100; @@ -185,6 +207,10 @@ private void createTablet() { ((double[]) values[3])[r] = 1D; ((boolean[]) values[4])[r] = false; ((Binary[]) values[5])[r] = BytesUtils.valueOf("text"); + ((long[]) values[6])[r] = 20000L; + ((LocalDate[]) values[7])[r] = LocalDate.of(2024, 1, 1); + ((Binary[]) values[8])[r] = BytesUtils.valueOf("blob"); + ((Binary[]) values[9])[r] = BytesUtils.valueOf("string"); } tabletForInsertRowNode = new Tablet(deviceId, Arrays.asList(schemas), 1); @@ -205,6 +231,10 @@ private void createTablet() { values[3] = new double[times.length]; values[4] = new boolean[times.length]; values[5] = new Binary[times.length]; + values[6] = new long[times.length]; + values[7] = new LocalDate[times.length]; + values[8] = new Binary[times.length]; + values[9] = new Binary[times.length]; for (int r = 0; r < times.length; r++) { ((int[]) values[0])[r] = 100; @@ -213,6 +243,10 @@ private void createTablet() { ((double[]) values[3])[r] = 1D; ((boolean[]) values[4])[r] = false; ((Binary[]) values[5])[r] = BytesUtils.valueOf("text"); + ((long[]) values[6])[r] = 20000L; + ((LocalDate[]) values[7])[r] = LocalDate.of(2024, 1, 1); + ((Binary[]) values[8])[r] = BytesUtils.valueOf("blob"); + ((Binary[]) values[9])[r] = BytesUtils.valueOf("string"); } tabletForInsertTabletNode = new Tablet(deviceId, Arrays.asList(schemas), times.length); diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/extractor/SchemaRegionListeningQueueTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/extractor/SchemaRegionListeningQueueTest.java index 008204ab160ac..daafda17c5b81 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/extractor/SchemaRegionListeningQueueTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/extractor/SchemaRegionListeningQueueTest.java @@ -24,7 +24,7 @@ import org.apache.iotdb.commons.exception.IllegalPathException; import org.apache.iotdb.commons.path.PartialPath; import org.apache.iotdb.commons.pipe.datastructure.queue.ConcurrentIterableLinkedQueue; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.event.common.schema.PipeSchemaRegionWritePlanEvent; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.write.ActivateTemplateNode; @@ -59,7 +59,7 @@ public static void setup() { @AfterClass public static void cleanup() throws IOException { - PipeAgent.runtime().schemaListener(new SchemaRegionId(0)).close(); + PipeDataNodeAgent.runtime().schemaListener(new SchemaRegionId(0)).close(); if (snapshotDir.exists()) { FileUtils.deleteDirectory(snapshotDir); } @@ -67,8 +67,8 @@ public static void cleanup() throws IOException { @Test public void testSnapshot() throws TException, IOException, AuthException, IllegalPathException { - PipeAgent.runtime().schemaListener(new SchemaRegionId(0)).open(); - PipeAgent.runtime().notifySchemaLeaderReady(new SchemaRegionId(0)); + PipeDataNodeAgent.runtime().schemaListener(new SchemaRegionId(0)).open(); + PipeDataNodeAgent.runtime().notifySchemaLeaderReady(new SchemaRegionId(0)); CreateTimeSeriesNode node1 = new CreateTimeSeriesNode( @@ -87,19 +87,19 @@ public void testSnapshot() throws TException, IOException, AuthException, Illega new ActivateTemplateNode( new PlanNodeId("ActivateTemplateNode"), new PartialPath("root.sg.d1.s1"), 2, 1)); - PipeAgent.runtime().schemaListener(new SchemaRegionId(0)).tryListenToNode(node1); - PipeAgent.runtime().schemaListener(new SchemaRegionId(0)).tryListenToNode(node2); + PipeDataNodeAgent.runtime().schemaListener(new SchemaRegionId(0)).tryListenToNode(node1); + PipeDataNodeAgent.runtime().schemaListener(new SchemaRegionId(0)).tryListenToNode(node2); // tryListenToSnapshots() cannot be tested here since we cannot operate the reference count of // the original or deserialized events - PipeAgent.runtime().schemaListener(new SchemaRegionId(0)).createSnapshot(snapshotDir); - PipeAgent.runtime().schemaListener(new SchemaRegionId(0)).close(); + PipeDataNodeAgent.runtime().schemaListener(new SchemaRegionId(0)).createSnapshot(snapshotDir); + PipeDataNodeAgent.runtime().schemaListener(new SchemaRegionId(0)).close(); - PipeAgent.runtime().schemaListener(new SchemaRegionId(0)).loadSnapshot(snapshotDir); - Assert.assertTrue(PipeAgent.runtime().schemaListener(new SchemaRegionId(0)).isOpened()); + PipeDataNodeAgent.runtime().schemaListener(new SchemaRegionId(0)).loadSnapshot(snapshotDir); + Assert.assertTrue(PipeDataNodeAgent.runtime().schemaListener(new SchemaRegionId(0)).isOpened()); ConcurrentIterableLinkedQueue.DynamicIterator itr = - PipeAgent.runtime().schemaListener(new SchemaRegionId(0)).newIterator(0); + PipeDataNodeAgent.runtime().schemaListener(new SchemaRegionId(0)).newIterator(0); Event event1 = itr.next(0); Assert.assertEquals(node1, ((PipeSchemaRegionWritePlanEvent) event1).getPlanNode()); diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/pattern/CachedSchemaPatternMatcherTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/pattern/CachedSchemaPatternMatcherTest.java index 07855ebe829f5..e959782d2aa54 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/pattern/CachedSchemaPatternMatcherTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/pattern/CachedSchemaPatternMatcherTest.java @@ -22,9 +22,12 @@ import org.apache.iotdb.commons.pipe.config.constant.PipeExtractorConstant; import org.apache.iotdb.commons.pipe.config.plugin.configuraion.PipeTaskRuntimeConfiguration; import org.apache.iotdb.commons.pipe.config.plugin.env.PipeTaskExtractorRuntimeEnvironment; +import org.apache.iotdb.commons.pipe.event.EnrichedEvent; +import org.apache.iotdb.commons.pipe.pattern.PipePattern; import org.apache.iotdb.commons.pipe.pattern.PrefixPipePattern; import org.apache.iotdb.db.pipe.event.realtime.PipeRealtimeEvent; import org.apache.iotdb.db.pipe.extractor.dataregion.realtime.PipeRealtimeDataRegionExtractor; +import org.apache.iotdb.db.pipe.extractor.dataregion.realtime.epoch.TsFileEpoch; import org.apache.iotdb.pipe.api.customizer.parameter.PipeParameters; import org.apache.iotdb.pipe.api.event.Event; @@ -49,6 +52,27 @@ public class CachedSchemaPatternMatcherTest { + private static class MockedPipeRealtimeEvent extends PipeRealtimeEvent { + + public MockedPipeRealtimeEvent( + EnrichedEvent event, + TsFileEpoch tsFileEpoch, + Map device2Measurements, + PipePattern pattern) { + super(event, tsFileEpoch, device2Measurements, pattern); + } + + @Override + public boolean shouldParseTime() { + return false; + } + + @Override + public boolean shouldParsePattern() { + return false; + } + } + private CachedSchemaPatternMatcher matcher; private ExecutorService executorService; private List extractors; @@ -128,8 +152,8 @@ public void testCachedMatcher() throws Exception { long totalTime = 0; for (int i = 0; i < epochNum; i++) { for (int j = 0; j < deviceNum; j++) { - PipeRealtimeEvent event = - new PipeRealtimeEvent( + MockedPipeRealtimeEvent event = + new MockedPipeRealtimeEvent( null, null, Collections.singletonMap(new StringArrayDeviceID("root.db" + i), measurements), @@ -138,7 +162,7 @@ public void testCachedMatcher() throws Exception { matcher.match(event).forEach(extractor -> extractor.extract(event)); totalTime += (System.currentTimeMillis() - startTime); } - PipeRealtimeEvent event = new PipeRealtimeEvent(null, null, deviceMap, null); + MockedPipeRealtimeEvent event = new MockedPipeRealtimeEvent(null, null, deviceMap, null); long startTime = System.currentTimeMillis(); matcher.match(event).forEach(extractor -> extractor.extract(event)); totalTime += (System.currentTimeMillis() - startTime); diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/resource/PipeTsFileResourceManagerTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/resource/PipeTsFileResourceManagerTest.java index be5e2c3a63391..0281bb0351946 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/resource/PipeTsFileResourceManagerTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/resource/PipeTsFileResourceManagerTest.java @@ -23,7 +23,7 @@ import org.apache.iotdb.commons.exception.IllegalPathException; import org.apache.iotdb.commons.path.PartialPath; import org.apache.iotdb.commons.utils.FileUtils; -import org.apache.iotdb.db.pipe.agent.PipeAgent; +import org.apache.iotdb.db.pipe.agent.PipeDataNodeAgent; import org.apache.iotdb.db.pipe.resource.tsfile.PipeTsFileResource; import org.apache.iotdb.db.pipe.resource.tsfile.PipeTsFileResourceManager; import org.apache.iotdb.db.storageengine.dataregion.modification.Deletion; @@ -65,7 +65,7 @@ public class PipeTsFileResourceManagerTest { @Before public void setUp() throws Exception { pipeTsFileResourceManager = new PipeTsFileResourceManager(); - PipeAgent.runtime().startPeriodicalJobExecutor(); + PipeDataNodeAgent.runtime().startPeriodicalJobExecutor(); createTsfile(TS_FILE_NAME); creatModsFile(MODS_FILE_NAME); @@ -151,8 +151,8 @@ public void tearDown() throws Exception { FileUtils.deleteFileOrDirectory(pipeFolder); } - PipeAgent.runtime().stopPeriodicalJobExecutor(); - PipeAgent.runtime().clearPeriodicalJobExecutor(); + PipeDataNodeAgent.runtime().stopPeriodicalJobExecutor(); + PipeDataNodeAgent.runtime().clearPeriodicalJobExecutor(); } @Test diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/common/schematree/ClusterSchemaTreeTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/common/schematree/ClusterSchemaTreeTest.java index 14d9173767601..60d1914ec9f96 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/common/schematree/ClusterSchemaTreeTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/common/schematree/ClusterSchemaTreeTest.java @@ -1031,6 +1031,7 @@ public void testHasView() throws IllegalPathException { new MeasurementSchema("s1", TSDataType.INT32), null, null, + null, false); Assert.assertFalse(schemaTree.hasLogicalViewMeasurement()); schemaTree.appendSingleMeasurement( @@ -1038,6 +1039,7 @@ public void testHasView() throws IllegalPathException { new LogicalViewSchema("s1", new TimeSeriesViewOperand("root.db.d.s1")), null, null, + null, false); Assert.assertTrue(schemaTree.hasLogicalViewMeasurement()); } diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/execution/operator/OperatorMemoryTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/execution/operator/OperatorMemoryTest.java index 7f68cbb6d665d..9145e98a7b9be 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/execution/operator/OperatorMemoryTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/execution/operator/OperatorMemoryTest.java @@ -837,13 +837,15 @@ public void SchemaFetchScanOperatorTest() { driverContext.addOperatorContext(1, planNodeId, SeriesScanOperator.class.getSimpleName()); SchemaFetchScanOperator operator = - new SchemaFetchScanOperator( + SchemaFetchScanOperator.ofSeries( planNodeId, driverContext.getOperatorContexts().get(0), null, null, null, false, + false, + false, false); assertEquals(DEFAULT_MAX_TSBLOCK_SIZE_IN_BYTES, operator.calculateMaxPeekMemory()); diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/execution/operator/schema/SchemaFetchScanOperatorTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/execution/operator/schema/SchemaFetchScanOperatorTest.java index d85699fde9da7..0aea689460281 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/execution/operator/schema/SchemaFetchScanOperatorTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/execution/operator/schema/SchemaFetchScanOperatorTest.java @@ -59,8 +59,16 @@ public void testSchemaFetchResult() throws Exception { patternTree.constructTree(); SchemaFetchScanOperator schemaFetchScanOperator = - new SchemaFetchScanOperator( - null, null, patternTree, Collections.emptyMap(), schemaRegion, false, true); + SchemaFetchScanOperator.ofSeries( + null, + null, + patternTree, + Collections.emptyMap(), + schemaRegion, + false, + false, + true, + false); Assert.assertTrue(schemaFetchScanOperator.hasNext()); @@ -151,7 +159,9 @@ private ISchemaRegion mockSchemaRegion() throws Exception { patternTree.appendPathPattern(new PartialPath("root.**.status")); patternTree.appendPathPattern(new PartialPath("root.**.s1")); patternTree.constructTree(); - Mockito.when(schemaRegion.fetchSchema(patternTree, Collections.emptyMap(), false, true)) + Mockito.when( + schemaRegion.fetchSeriesSchema( + patternTree, Collections.emptyMap(), false, false, true, false)) .thenReturn(clusterSchemaTree); return schemaRegion; diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/FakeSchemaFetcherImpl.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/FakeSchemaFetcherImpl.java index 718d10ef8156a..1e6042e05dfee 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/FakeSchemaFetcherImpl.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/FakeSchemaFetcherImpl.java @@ -53,6 +53,20 @@ public ClusterSchemaTree fetchSchema( return schemaTree; } + @Override + public ISchemaTree fetchRawSchemaInDeviceLevel( + PathPatternTree patternTree, PathPatternTree authorityScope, MPPQueryContext context) { + schemaTree.setDatabases(Collections.singleton("root.sg")); + return schemaTree; + } + + @Override + public ISchemaTree fetchRawSchemaInMeasurementLevel( + PathPatternTree patternTree, PathPatternTree authorityScope, MPPQueryContext context) { + schemaTree.setDatabases(Collections.singleton("root.sg")); + return schemaTree; + } + @Override public ISchemaTree fetchSchemaWithTags( PathPatternTree patternTree, boolean withTemplate, MPPQueryContext context) { diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/QueryTimePartitionTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/QueryTimePartitionTest.java index 30338d0d7d9ab..1e85a1461ee87 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/QueryTimePartitionTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/analyze/QueryTimePartitionTest.java @@ -20,6 +20,8 @@ import org.apache.iotdb.common.rpc.thrift.TTimePartitionSlot; import org.apache.iotdb.commons.conf.CommonDescriptor; +import org.apache.iotdb.db.queryengine.common.MPPQueryContext; +import org.apache.iotdb.db.queryengine.common.QueryId; import org.apache.tsfile.read.common.TimeRange; import org.apache.tsfile.read.filter.basic.Filter; @@ -354,16 +356,17 @@ public void testTimeLtEqFilter() { @Test public void testGetTimePartitionSlotList() { - + MPPQueryContext context = new MPPQueryContext(new QueryId("time_partition_test")); // time >= 10 and time <= 9 Pair, Pair> res = - getTimePartitionSlotList(FilterFactory.and(TimeFilterApi.gtEq(10), TimeFilterApi.ltEq(9))); + getTimePartitionSlotList( + FilterFactory.and(TimeFilterApi.gtEq(10), TimeFilterApi.ltEq(9)), context); assertTrue(res.left.isEmpty()); assertFalse(res.right.left); assertFalse(res.right.right); // time >= 10 - res = getTimePartitionSlotList(TimeFilterApi.gtEq(10)); + res = getTimePartitionSlotList(TimeFilterApi.gtEq(10), context); assertEquals(1, res.left.size()); List expected = Collections.singletonList(new TTimePartitionSlot(0)); assertEquals(expected.size(), res.left.size()); @@ -374,7 +377,7 @@ public void testGetTimePartitionSlotList() { assertTrue(res.right.right); // time < 20 - res = getTimePartitionSlotList(TimeFilterApi.lt(20)); + res = getTimePartitionSlotList(TimeFilterApi.lt(20), context); assertEquals(1, res.left.size()); expected = Collections.singletonList(new TTimePartitionSlot(0)); assertEquals(expected.size(), res.left.size()); @@ -385,7 +388,9 @@ public void testGetTimePartitionSlotList() { assertFalse(res.right.right); // time > 10 and time <= 20 - res = getTimePartitionSlotList(FilterFactory.and(TimeFilterApi.gt(10), TimeFilterApi.ltEq(20))); + res = + getTimePartitionSlotList( + FilterFactory.and(TimeFilterApi.gt(10), TimeFilterApi.ltEq(20)), context); expected = Collections.singletonList(new TTimePartitionSlot(0)); assertEquals(expected.size(), res.left.size()); for (int i = 0; i < expected.size(); i++) { @@ -401,8 +406,8 @@ public void testGetTimePartitionSlotList() { FilterFactory.and( TimeFilterApi.gt(0), TimeFilterApi.ltEq( - CommonDescriptor.getInstance().getConfig().getTimePartitionInterval() * 3 - + 1))); + CommonDescriptor.getInstance().getConfig().getTimePartitionInterval() * 3 + 1)), + context); expected = Arrays.asList( new TTimePartitionSlot(0), @@ -427,7 +432,8 @@ public void testGetTimePartitionSlotList() { TimeFilterApi.gtEq( CommonDescriptor.getInstance().getConfig().getTimePartitionInterval() - 1), TimeFilterApi.lt( - CommonDescriptor.getInstance().getConfig().getTimePartitionInterval() + 1))); + CommonDescriptor.getInstance().getConfig().getTimePartitionInterval() + 1)), + context); expected = Arrays.asList( new TTimePartitionSlot(0), @@ -446,7 +452,8 @@ public void testGetTimePartitionSlotList() { getTimePartitionSlotList( TimeFilterApi.between( CommonDescriptor.getInstance().getConfig().getTimePartitionInterval() - 1, - CommonDescriptor.getInstance().getConfig().getTimePartitionInterval())); + CommonDescriptor.getInstance().getConfig().getTimePartitionInterval()), + context); expected = Arrays.asList( new TTimePartitionSlot(0), @@ -467,7 +474,8 @@ public void testGetTimePartitionSlotList() { TimeFilterApi.gtEq( CommonDescriptor.getInstance().getConfig().getTimePartitionInterval()), TimeFilterApi.ltEq( - CommonDescriptor.getInstance().getConfig().getTimePartitionInterval() + 1))); + CommonDescriptor.getInstance().getConfig().getTimePartitionInterval() + 1)), + context); expected = Collections.singletonList( new TTimePartitionSlot( @@ -485,7 +493,8 @@ public void testGetTimePartitionSlotList() { getTimePartitionSlotList( TimeFilterApi.between( CommonDescriptor.getInstance().getConfig().getTimePartitionInterval(), - CommonDescriptor.getInstance().getConfig().getTimePartitionInterval() + 1)); + CommonDescriptor.getInstance().getConfig().getTimePartitionInterval() + 1), + context); expected = Collections.singletonList( new TTimePartitionSlot( @@ -547,7 +556,7 @@ public void testGetTimePartitionSlotList() { CommonDescriptor.getInstance().getConfig().getTimePartitionInterval() * 5 + 10))); - res = getTimePartitionSlotList(orFilter4); + res = getTimePartitionSlotList(orFilter4, context); expected = Arrays.asList( new TTimePartitionSlot(0), diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/Util.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/Util.java index 764393b3714c1..22f6bc33581e6 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/Util.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/Util.java @@ -306,6 +306,18 @@ public ISchemaTree fetchSchema( return ANALYSIS.getSchemaTree(); } + @Override + public ISchemaTree fetchRawSchemaInDeviceLevel( + PathPatternTree patternTree, PathPatternTree authorityScope, MPPQueryContext context) { + return ANALYSIS.getSchemaTree(); + } + + @Override + public ISchemaTree fetchRawSchemaInMeasurementLevel( + PathPatternTree patternTree, PathPatternTree authorityScope, MPPQueryContext context) { + return ANALYSIS.getSchemaTree(); + } + @Override public ISchemaTree fetchSchemaWithTags( PathPatternTree patternTree, boolean withTemplate, MPPQueryContext context) { diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/Util2.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/Util2.java index 38158b402e548..57d986d92e51d 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/Util2.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/distribution/Util2.java @@ -200,6 +200,18 @@ public ISchemaTree fetchSchema( return ANALYSIS.getSchemaTree(); } + @Override + public ISchemaTree fetchRawSchemaInDeviceLevel( + PathPatternTree patternTree, PathPatternTree authorityScope, MPPQueryContext context) { + return ANALYSIS.getSchemaTree(); + } + + @Override + public ISchemaTree fetchRawSchemaInMeasurementLevel( + PathPatternTree patternTree, PathPatternTree authorityScope, MPPQueryContext context) { + return ANALYSIS.getSchemaTree(); + } + @Override public ISchemaTree fetchSchemaWithTags( PathPatternTree patternTree, boolean withTemplate, MPPQueryContext context) { diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/logical/RegionScanLogicalPlannerTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/logical/RegionScanLogicalPlannerTest.java index 372ebea4a8c76..c73e045b96269 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/logical/RegionScanLogicalPlannerTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/logical/RegionScanLogicalPlannerTest.java @@ -23,8 +23,10 @@ import org.apache.iotdb.commons.path.AlignedPath; import org.apache.iotdb.commons.path.MeasurementPath; import org.apache.iotdb.commons.path.PartialPath; +import org.apache.iotdb.commons.schema.SchemaConstant; +import org.apache.iotdb.db.queryengine.common.DeviceContext; import org.apache.iotdb.db.queryengine.common.QueryId; -import org.apache.iotdb.db.queryengine.common.TimeseriesSchemaInfo; +import org.apache.iotdb.db.queryengine.common.TimeseriesContext; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNode; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeType; @@ -48,10 +50,10 @@ public class RegionScanLogicalPlannerTest { - private static Map>> + private static Map>> deviceToTimeseriesSchemaInfoMap; - private static Map>> + private static Map>> getDeviceToTimeseriesSchemaInfoMap() throws IllegalPathException { if (deviceToTimeseriesSchemaInfoMap != null) { @@ -59,56 +61,55 @@ public class RegionScanLogicalPlannerTest { } deviceToTimeseriesSchemaInfoMap = new HashMap<>(); - Map> timeseriesSchemaInfoMap = new HashMap<>(); + Map> timeseriesSchemaInfoMap = new HashMap<>(); timeseriesSchemaInfoMap.put( new MeasurementPath("root.sg.d1.s1", TSDataType.INT32), Collections.singletonList( - new TimeseriesSchemaInfo( - "INT32", null, "PLAIN", "LZ4", "{\"key1\":\"value1\"}", null, null))); + new TimeseriesContext( + "INT32", null, "PLAIN", "LZ4", "{\"key1\":\"value1\"}", null, null, null))); timeseriesSchemaInfoMap.put( new MeasurementPath("root.sg.d1.s2", TSDataType.DOUBLE), Collections.singletonList( - new TimeseriesSchemaInfo( - "DOUBLE", "status", "PLAIN", "LZ4", "{\"key1\":\"value1\"}", null, null))); + new TimeseriesContext( + "DOUBLE", "status", "PLAIN", "LZ4", "{\"key1\":\"value1\"}", null, null, null))); timeseriesSchemaInfoMap.put( new MeasurementPath("root.sg.d1.s3", TSDataType.BOOLEAN), Collections.singletonList( - new TimeseriesSchemaInfo( - "BOOLEAN", null, "PLAIN", "LZ4", "{\"key1\":\"value2\"}", null, null))); + new TimeseriesContext( + "BOOLEAN", null, "PLAIN", "LZ4", "{\"key1\":\"value2\"}", null, null, null))); deviceToTimeseriesSchemaInfoMap.put(new PartialPath("root.sg.d1"), timeseriesSchemaInfoMap); - Map> timeseriesSchemaInfoMap2 = new HashMap<>(); + Map> timeseriesSchemaInfoMap2 = new HashMap<>(); timeseriesSchemaInfoMap2.put( new MeasurementPath("root.sg.d2.s1", TSDataType.INT32), Collections.singletonList( - new TimeseriesSchemaInfo( - "INT32", null, "PLAIN", "LZ4", "{\"key1\":\"value1\"}", null, null))); + new TimeseriesContext( + "INT32", null, "PLAIN", "LZ4", "{\"key1\":\"value1\"}", null, null, null))); timeseriesSchemaInfoMap2.put( new MeasurementPath("root.sg.d2.s2", TSDataType.DOUBLE), Collections.singletonList( - new TimeseriesSchemaInfo( - "DOUBLE", "status", "PLAIN", "LZ4", "{\"key1\":\"value1\"}", null, null))); + new TimeseriesContext( + "DOUBLE", "status", "PLAIN", "LZ4", "{\"key1\":\"value1\"}", null, null, null))); timeseriesSchemaInfoMap2.put( new MeasurementPath("root.sg.d2.s4", TSDataType.TEXT), Collections.singletonList( - new TimeseriesSchemaInfo( - "TEXT", null, "PLAIN", "LZ4", "{\"key2\":\"value1\"}", null, null))); + new TimeseriesContext( + "TEXT", null, "PLAIN", "LZ4", "{\"key2\":\"value1\"}", null, null, null))); deviceToTimeseriesSchemaInfoMap.put(new PartialPath("root.sg.d2"), timeseriesSchemaInfoMap2); List schemas = new ArrayList<>(); schemas.add("s1"); schemas.add("s2"); - List timeseriesSchemaInfoList = new ArrayList<>(); - Map> timeseriesSchemaInfoMap3 = new HashMap<>(); - timeseriesSchemaInfoList.add( - new TimeseriesSchemaInfo( - "INT32", null, "PLAIN", "LZ4", "{\"key1\":\"value1\"}", null, null)); - timeseriesSchemaInfoList.add( - new TimeseriesSchemaInfo( - "DOUBLE", "status", "PLAIN", "LZ4", "{\"key1\":\"value1\"}", null, null)); + List timeseriesContextList = new ArrayList<>(); + Map> timeseriesSchemaInfoMap3 = new HashMap<>(); + timeseriesContextList.add( + new TimeseriesContext( + "INT32", null, "PLAIN", "LZ4", "{\"key1\":\"value1\"}", null, null, null)); + timeseriesContextList.add( + new TimeseriesContext( + "DOUBLE", "status", "PLAIN", "LZ4", "{\"key1\":\"value1\"}", null, null, null)); timeseriesSchemaInfoMap3.put( - new AlignedPath("root.sg.d2.a", schemas, Collections.emptyList()), - timeseriesSchemaInfoList); + new AlignedPath("root.sg.d2.a", schemas, Collections.emptyList()), timeseriesContextList); deviceToTimeseriesSchemaInfoMap.put(new PartialPath("root.sg.d2.a"), timeseriesSchemaInfoMap3); return deviceToTimeseriesSchemaInfoMap; @@ -122,13 +123,16 @@ public void testShowDevicesWithTimeCondition() throws IllegalPathException { // fake initResultNodeContext() queryId.genPlanNodeId(); - Map devicePathsToAligned = new HashMap<>(); - devicePathsToAligned.put(new PartialPath("root.sg.d1"), false); - devicePathsToAligned.put(new PartialPath("root.sg.d2"), false); - devicePathsToAligned.put(new PartialPath("root.sg.d2.a"), true); + Map deviceContextMap = new HashMap<>(); + deviceContextMap.put( + new PartialPath("root.sg.d1"), new DeviceContext(false, SchemaConstant.NON_TEMPLATE)); + deviceContextMap.put( + new PartialPath("root.sg.d2"), new DeviceContext(false, SchemaConstant.NON_TEMPLATE)); + deviceContextMap.put( + new PartialPath("root.sg.d2.a"), new DeviceContext(true, SchemaConstant.NON_TEMPLATE)); DeviceRegionScanNode regionScanNode = - new DeviceRegionScanNode(queryId.genPlanNodeId(), devicePathsToAligned, false, null); + new DeviceRegionScanNode(queryId.genPlanNodeId(), deviceContextMap, false, null); PlanNode actualPlan = parseSQLToPlanNode(sql); Assert.assertEquals(actualPlan, regionScanNode); @@ -142,13 +146,16 @@ public void testShowDevicesWithTimeConditionWithLimitOffset() throws IllegalPath // fake initResultNodeContext() queryId.genPlanNodeId(); - Map devicePathsToAligned = new HashMap<>(); - devicePathsToAligned.put(new PartialPath("root.sg.d1"), false); - devicePathsToAligned.put(new PartialPath("root.sg.d2"), false); - devicePathsToAligned.put(new PartialPath("root.sg.d2.a"), true); + Map deviceContextMap = new HashMap<>(); + deviceContextMap.put( + new PartialPath("root.sg.d1"), new DeviceContext(false, SchemaConstant.NON_TEMPLATE)); + deviceContextMap.put( + new PartialPath("root.sg.d2"), new DeviceContext(false, SchemaConstant.NON_TEMPLATE)); + deviceContextMap.put( + new PartialPath("root.sg.d2.a"), new DeviceContext(true, SchemaConstant.NON_TEMPLATE)); DeviceRegionScanNode regionScanNode = - new DeviceRegionScanNode(queryId.genPlanNodeId(), devicePathsToAligned, false, null); + new DeviceRegionScanNode(queryId.genPlanNodeId(), deviceContextMap, false, null); LimitNode limitNode = new LimitNode(queryId.genPlanNodeId(), 20); limitNode.addChild(regionScanNode); @@ -167,13 +174,16 @@ public void testCountDevicesWithTimeConditionWithLimitOffset() throws IllegalPat // fake initResultNodeContext() queryId.genPlanNodeId(); - Map devicePathsToAligned = new HashMap<>(); - devicePathsToAligned.put(new PartialPath("root.sg.d1"), false); - devicePathsToAligned.put(new PartialPath("root.sg.d2"), false); - devicePathsToAligned.put(new PartialPath("root.sg.d2.a"), true); + Map deviceContextMap = new HashMap<>(); + deviceContextMap.put( + new PartialPath("root.sg.d1"), new DeviceContext(false, SchemaConstant.NON_TEMPLATE)); + deviceContextMap.put( + new PartialPath("root.sg.d2"), new DeviceContext(false, SchemaConstant.NON_TEMPLATE)); + deviceContextMap.put( + new PartialPath("root.sg.d2.a"), new DeviceContext(true, SchemaConstant.NON_TEMPLATE)); DeviceRegionScanNode regionScanNode = - new DeviceRegionScanNode(queryId.genPlanNodeId(), devicePathsToAligned, true, null); + new DeviceRegionScanNode(queryId.genPlanNodeId(), deviceContextMap, true, null); PlanNode actualPlan = parseSQLToPlanNode(sql); Assert.assertEquals(actualPlan, regionScanNode); diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/node/metadata/read/DeviceSchemaFetchScanNodeTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/node/metadata/read/DeviceSchemaFetchScanNodeTest.java new file mode 100644 index 0000000000000..ca52035bb5049 --- /dev/null +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/node/metadata/read/DeviceSchemaFetchScanNodeTest.java @@ -0,0 +1,55 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.db.queryengine.plan.planner.node.metadata.read; + +import org.apache.iotdb.commons.exception.IllegalPathException; +import org.apache.iotdb.commons.path.PartialPath; +import org.apache.iotdb.commons.path.PathPatternTree; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeType; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.DeviceSchemaFetchScanNode; + +import org.junit.Assert; +import org.junit.Test; + +import java.nio.ByteBuffer; + +public class DeviceSchemaFetchScanNodeTest { + + @Test + public void testSerialization() throws IllegalPathException { + PathPatternTree patternTree = new PathPatternTree(); + patternTree.appendPathPattern(new PartialPath("root.sg.**.*")); + DeviceSchemaFetchScanNode deviceSchemaFetchScanNodeTest = + new DeviceSchemaFetchScanNode( + new PlanNodeId("0"), new PartialPath("root.sg"), patternTree, patternTree); + ByteBuffer byteBuffer = ByteBuffer.allocate(1024 * 1024); + deviceSchemaFetchScanNodeTest.serialize(byteBuffer); + byteBuffer.flip(); + DeviceSchemaFetchScanNode recoveredNode = + (DeviceSchemaFetchScanNode) PlanNodeType.deserialize(byteBuffer); + Assert.assertEquals("root.sg", recoveredNode.getStorageGroup().getFullPath()); + Assert.assertEquals( + "root.sg.**.*", recoveredNode.getPatternTree().getAllPathPatterns().get(0).getFullPath()); + Assert.assertEquals( + "root.sg.**.*", + recoveredNode.getAuthorityScope().getAllPathPatterns().get(0).getFullPath()); + } +} diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/node/metadata/read/SchemaFetchMergeNodeTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/node/metadata/read/SchemaFetchMergeNodeTest.java index c242778efab67..e31d886a4f921 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/node/metadata/read/SchemaFetchMergeNodeTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/node/metadata/read/SchemaFetchMergeNodeTest.java @@ -25,7 +25,7 @@ import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeType; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaFetchMergeNode; -import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaFetchScanNode; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SeriesSchemaFetchScanNode; import org.junit.Assert; import org.junit.Test; @@ -42,15 +42,17 @@ public void testSerialization() throws IllegalPathException { new SchemaFetchMergeNode(new PlanNodeId("0"), Arrays.asList("root.db1", "root.db2")); PathPatternTree patternTree = new PathPatternTree(); patternTree.appendPathPattern(new PartialPath("root.sg.**.*")); - SchemaFetchScanNode schemaFetchScanNode = - new SchemaFetchScanNode( + SeriesSchemaFetchScanNode seriesSchemaFetchScanNode = + new SeriesSchemaFetchScanNode( new PlanNodeId("0"), new PartialPath("root.sg"), patternTree, Collections.emptyMap(), true, - true); - schemaFetchMergeNode.addChild(schemaFetchScanNode); + false, + true, + false); + schemaFetchMergeNode.addChild(seriesSchemaFetchScanNode); ByteBuffer byteBuffer = ByteBuffer.allocate(1024 * 1024); schemaFetchMergeNode.serialize(byteBuffer); byteBuffer.flip(); diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/node/metadata/read/SchemaFetchScanNodeTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/node/metadata/read/SeriesSchemaFetchScanNodeTest.java similarity index 83% rename from iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/node/metadata/read/SchemaFetchScanNodeTest.java rename to iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/node/metadata/read/SeriesSchemaFetchScanNodeTest.java index 0d45a127f1766..0ad52409c09da 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/node/metadata/read/SchemaFetchScanNodeTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/queryengine/plan/planner/node/metadata/read/SeriesSchemaFetchScanNodeTest.java @@ -24,7 +24,7 @@ import org.apache.iotdb.commons.path.PathPatternTree; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId; import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeType; -import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SchemaFetchScanNode; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.metedata.read.SeriesSchemaFetchScanNode; import org.junit.Assert; import org.junit.Test; @@ -32,24 +32,27 @@ import java.nio.ByteBuffer; import java.util.Collections; -public class SchemaFetchScanNodeTest { +public class SeriesSchemaFetchScanNodeTest { @Test public void testSerialization() throws IllegalPathException { PathPatternTree patternTree = new PathPatternTree(); patternTree.appendPathPattern(new PartialPath("root.sg.**.*")); - SchemaFetchScanNode schemaFetchScanNode = - new SchemaFetchScanNode( + SeriesSchemaFetchScanNode seriesSchemaFetchScanNode = + new SeriesSchemaFetchScanNode( new PlanNodeId("0"), new PartialPath("root.sg"), patternTree, Collections.emptyMap(), true, - true); + false, + true, + false); ByteBuffer byteBuffer = ByteBuffer.allocate(1024 * 1024); - schemaFetchScanNode.serialize(byteBuffer); + seriesSchemaFetchScanNode.serialize(byteBuffer); byteBuffer.flip(); - SchemaFetchScanNode recoveredNode = (SchemaFetchScanNode) PlanNodeType.deserialize(byteBuffer); + SeriesSchemaFetchScanNode recoveredNode = + (SeriesSchemaFetchScanNode) PlanNodeType.deserialize(byteBuffer); Assert.assertEquals("root.sg", recoveredNode.getStorageGroup().getFullPath()); Assert.assertEquals( "root.sg.**.*", recoveredNode.getPatternTree().getAllPathPatterns().get(0).getFullPath()); diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/TTLTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/TTLTest.java index 37fb0870328ec..3d6f49e672985 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/TTLTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/TTLTest.java @@ -400,7 +400,8 @@ public void testParseShowTTL() { ShowTTLStatement statement1 = (ShowTTLStatement) StatementGenerator.createStatement("SHOW ALL TTL", ZoneId.systemDefault()); - assertTrue(statement1.getPaths().isEmpty()); + assertEquals(1, statement1.getPaths().size()); + assertEquals("root.**", statement1.getPaths().get(0).getFullPath()); } @Test diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/compaction/repair/RepairUnsortedFileCompactionTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/compaction/repair/RepairUnsortedFileCompactionTest.java index 09924de54e7d1..ab709e34207cb 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/compaction/repair/RepairUnsortedFileCompactionTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/compaction/repair/RepairUnsortedFileCompactionTest.java @@ -996,4 +996,30 @@ public void testMergeAlignedSeriesPointWithSameTimestamp() throws IOException { } } } + + @Test + public void testSplitChunk() throws IOException { + TsFileResource resource = createEmptyFileAndResource(true); + try (CompactionTestFileWriter writer = new CompactionTestFileWriter(resource)) { + writer.startChunkGroup("d1"); + writer.generateSimpleAlignedSeriesToCurrentDeviceWithNullValue( + Arrays.asList("s1", "s2", "s3"), + new TimeRange[][] {new TimeRange[] {new TimeRange(100000, 300000)}}, + TSEncoding.PLAIN, + CompressionType.LZ4, + Arrays.asList(true, false, false)); + writer.endChunkGroup(); + writer.endFile(); + } + RepairUnsortedFileCompactionTask task = + new RepairUnsortedFileCompactionTask(0, tsFileManager, resource, true, true, 0); + Assert.assertTrue(task.start()); + TsFileResource target = tsFileManager.getTsFileList(false).get(0); + try (TsFileSequenceReader reader = new TsFileSequenceReader(target.getTsFilePath())) { + List chunkMetadataList = + reader.getAlignedChunkMetadata( + IDeviceID.Factory.DEFAULT_FACTORY.create("root.testsg.d1")); + Assert.assertEquals(3, chunkMetadataList.size()); + } + } } diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/WALTestUtils.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/WALTestUtils.java new file mode 100644 index 0000000000000..8f671eb3f03d1 --- /dev/null +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/WALTestUtils.java @@ -0,0 +1,90 @@ +/* + * 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.iotdb.db.storageengine.dataregion.wal; + +import org.apache.iotdb.commons.exception.IllegalPathException; +import org.apache.iotdb.commons.path.PartialPath; +import org.apache.iotdb.db.exception.query.QueryProcessException; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.PlanNodeId; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.write.InsertRowNode; + +import org.apache.tsfile.common.conf.TSFileConfig; +import org.apache.tsfile.enums.TSDataType; +import org.apache.tsfile.utils.Binary; +import org.apache.tsfile.write.schema.MeasurementSchema; + +import java.lang.reflect.Field; + +public class WALTestUtils { + public static void setMinCompressionSize(long size) + throws NoSuchFieldException, ClassNotFoundException, IllegalAccessException { + Class logWriterClass = + Class.forName("org.apache.iotdb.db.storageengine.dataregion.wal.io.LogWriter"); + Field minCompressionSizeField = logWriterClass.getDeclaredField("minCompressionSize"); + minCompressionSizeField.setAccessible(true); + minCompressionSizeField.setLong(null, size); + } + + public static long getMinCompressionSize() + throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException { + Class logWriterClass = + Class.forName("org.apache.iotdb.db.storageengine.dataregion.wal.io.LogWriter"); + Field minCompressionSizeField = logWriterClass.getDeclaredField("minCompressionSize"); + minCompressionSizeField.setAccessible(true); + return minCompressionSizeField.getLong(null); + } + + public static InsertRowNode getInsertRowNode(String devicePath, long time) + throws IllegalPathException, QueryProcessException { + TSDataType[] dataTypes = + new TSDataType[] { + TSDataType.DOUBLE, + TSDataType.FLOAT, + TSDataType.INT64, + TSDataType.INT32, + TSDataType.BOOLEAN, + TSDataType.TEXT + }; + + Object[] columns = new Object[6]; + columns[0] = 1.0d; + columns[1] = 2f; + columns[2] = 10000L; + columns[3] = 100; + columns[4] = false; + columns[5] = new Binary("hh" + 0, TSFileConfig.STRING_CHARSET); + + InsertRowNode node = + new InsertRowNode( + new PlanNodeId(""), + new PartialPath(devicePath), + false, + new String[] {"s1", "s2", "s3", "s4", "s5", "s6"}, + dataTypes, + time, + columns, + false); + MeasurementSchema[] schemas = new MeasurementSchema[6]; + for (int i = 0; i < 6; i++) { + schemas[i] = new MeasurementSchema("s" + (i + 1), dataTypes[i]); + } + node.setMeasurementSchemas(schemas); + return node; + } +} diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/compression/WALCompressionTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/compression/WALCompressionTest.java new file mode 100644 index 0000000000000..d187f6107b6b7 --- /dev/null +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/compression/WALCompressionTest.java @@ -0,0 +1,409 @@ +/* + * 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.iotdb.db.storageengine.dataregion.wal.compression; + +import org.apache.iotdb.commons.exception.IllegalPathException; +import org.apache.iotdb.db.conf.IoTDBDescriptor; +import org.apache.iotdb.db.exception.query.QueryProcessException; +import org.apache.iotdb.db.queryengine.plan.planner.plan.node.write.InsertRowNode; +import org.apache.iotdb.db.storageengine.dataregion.wal.WALTestUtils; +import org.apache.iotdb.db.storageengine.dataregion.wal.buffer.WALBuffer; +import org.apache.iotdb.db.storageengine.dataregion.wal.buffer.WALEntry; +import org.apache.iotdb.db.storageengine.dataregion.wal.buffer.WALEntryType; +import org.apache.iotdb.db.storageengine.dataregion.wal.buffer.WALInfoEntry; +import org.apache.iotdb.db.storageengine.dataregion.wal.buffer.WALSignalEntry; +import org.apache.iotdb.db.storageengine.dataregion.wal.io.LogWriter; +import org.apache.iotdb.db.storageengine.dataregion.wal.io.WALByteBufReader; +import org.apache.iotdb.db.storageengine.dataregion.wal.io.WALInputStream; +import org.apache.iotdb.db.storageengine.dataregion.wal.io.WALReader; +import org.apache.iotdb.db.storageengine.dataregion.wal.io.WALWriter; +import org.apache.iotdb.db.storageengine.dataregion.wal.utils.WALFileStatus; +import org.apache.iotdb.db.storageengine.dataregion.wal.utils.WALFileUtils; +import org.apache.iotdb.db.utils.constant.TestConstant; + +import org.apache.commons.io.FileUtils; +import org.apache.tsfile.compress.ICompressor; +import org.apache.tsfile.compress.IUnCompressor; +import org.apache.tsfile.file.metadata.enums.CompressionType; +import org.apache.tsfile.utils.Pair; +import org.apache.tsfile.utils.PublicBAOS; +import org.junit.After; +import org.junit.Assert; +import org.junit.Before; +import org.junit.Test; + +import java.io.BufferedInputStream; +import java.io.DataInputStream; +import java.io.DataOutputStream; +import java.io.File; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.file.Files; +import java.util.ArrayList; +import java.util.List; + +public class WALCompressionTest { + private final File walFile = + new File( + TestConstant.BASE_OUTPUT_PATH.concat( + WALFileUtils.getLogFileName(0, 0, WALFileStatus.CONTAINS_SEARCH_INDEX))); + + private final String compressionDir = + TestConstant.OUTPUT_DATA_DIR.concat(File.separator + "wal-compression"); + + private final String devicePath = "root.sg.d1"; + long originalMinCompressionSize; + CompressionType originCompressionType = + IoTDBDescriptor.getInstance().getConfig().getWALCompressionAlgorithm(); + + @Before + public void setUp() + throws IOException, NoSuchFieldException, ClassNotFoundException, IllegalAccessException { + if (walFile.exists()) { + FileUtils.delete(walFile); + } + originalMinCompressionSize = WALTestUtils.getMinCompressionSize(); + if (new File(compressionDir).exists()) { + FileUtils.forceDelete(new File(compressionDir)); + } + } + + @After + public void tearDown() + throws IOException, NoSuchFieldException, ClassNotFoundException, IllegalAccessException { + if (walFile.exists()) { + FileUtils.delete(walFile); + } + if (new File(compressionDir).exists()) { + FileUtils.forceDelete(new File(compressionDir)); + } + WALTestUtils.setMinCompressionSize(originalMinCompressionSize); + IoTDBDescriptor.getInstance().getConfig().setWALCompressionAlgorithm(originCompressionType); + } + + @Test + public void testSkipToGivenPositionWithCompression() + throws NoSuchFieldException, + ClassNotFoundException, + IllegalAccessException, + QueryProcessException, + IllegalPathException, + IOException { + WALTestUtils.setMinCompressionSize(0L); + IoTDBDescriptor.getInstance().getConfig().setWALCompressionAlgorithm(CompressionType.LZ4); + testSkipToGivenPosition(); + } + + @Test + public void testSkipToGivenPositionWithoutCompression() + throws NoSuchFieldException, + ClassNotFoundException, + IllegalAccessException, + QueryProcessException, + IllegalPathException, + IOException { + WALTestUtils.setMinCompressionSize(1024 * 32); + testSkipToGivenPosition(); + } + + public void testSkipToGivenPosition() + throws QueryProcessException, IllegalPathException, IOException { + LogWriter writer = new WALWriter(walFile); + ByteBuffer buffer = ByteBuffer.allocate(1024 * 4); + List> positionAndEntryPairList = new ArrayList<>(); + int memTableId = 0; + long fileOffset = 0; + for (int i = 0; i < 100; ) { + InsertRowNode insertRowNode = WALTestUtils.getInsertRowNode(devicePath + memTableId, i); + long serializedSize = insertRowNode.serializedSize(); + if (buffer.remaining() >= serializedSize) { + int pos = buffer.position(); + insertRowNode.serialize(buffer); + positionAndEntryPairList.add(new Pair<>(fileOffset, insertRowNode)); + fileOffset += buffer.position() - pos; + i++; + } else { + writer.write(buffer); + buffer.clear(); + } + } + if (buffer.position() != 0) { + writer.write(buffer); + } + writer.close(); + try (WALInputStream stream = new WALInputStream(walFile)) { + for (int i = 0; i < 100; ++i) { + Pair positionAndNodePair = positionAndEntryPairList.get(i); + stream.skipToGivenLogicalPosition(positionAndNodePair.left); + /* + Add the allocated buffer size by 2, because the actual serialized size + of InsertRowNode is larger than the estimated value got by serializedSize. + I don't know if this is a bug or not. + */ + ByteBuffer nodeBuffer1 = + ByteBuffer.allocate(positionAndNodePair.right.serializedSize() + 2); + stream.read(nodeBuffer1); + ByteBuffer nodeBuffer2 = + ByteBuffer.allocate(positionAndNodePair.right.serializedSize() + 2); + positionAndNodePair.right.serialize(nodeBuffer2); + nodeBuffer2.flip(); + Assert.assertArrayEquals(nodeBuffer1.array(), nodeBuffer2.array()); + } + } + } + + @Test + public void testUncompressedWALStructure() + throws QueryProcessException, IllegalPathException, IOException { + PublicBAOS baos = new PublicBAOS(); + DataOutputStream dataOutputStream = new DataOutputStream(baos); + List insertRowNodes = new ArrayList<>(); + for (int i = 0; i < 100; ++i) { + InsertRowNode node = WALTestUtils.getInsertRowNode(devicePath, i); + insertRowNodes.add(node); + node.serialize(dataOutputStream); + } + dataOutputStream.close(); + ByteBuffer buf = ByteBuffer.wrap(baos.toByteArray()); + // Do not compress it + IoTDBDescriptor.getInstance() + .getConfig() + .setWALCompressionAlgorithm(CompressionType.UNCOMPRESSED); + try (WALWriter writer = new WALWriter(walFile)) { + buf.position(buf.limit()); + writer.write(buf); + } + + try (DataInputStream dataInputStream = + new DataInputStream(new BufferedInputStream(Files.newInputStream(walFile.toPath())))) { + byte[] magicStringBytes = new byte[WALWriter.MAGIC_STRING_BYTES]; + // head magic string + dataInputStream.readFully(magicStringBytes); + Assert.assertEquals(WALWriter.MAGIC_STRING, new String(magicStringBytes)); + Assert.assertEquals( + CompressionType.UNCOMPRESSED, CompressionType.deserialize(dataInputStream.readByte())); + Assert.assertEquals(buf.array().length, dataInputStream.readInt()); + ByteBuffer dataBuf = ByteBuffer.allocate(buf.array().length); + dataInputStream.readFully(dataBuf.array()); + Assert.assertArrayEquals(buf.array(), dataBuf.array()); + Assert.assertEquals( + new WALSignalEntry(WALEntryType.WAL_FILE_INFO_END_MARKER), + WALEntry.deserialize(dataInputStream)); + ByteBuffer metadataBuf = ByteBuffer.allocate(12 + Integer.BYTES); + dataInputStream.readFully(metadataBuf.array()); + // Tail magic string + dataInputStream.readFully(magicStringBytes); + Assert.assertEquals(WALWriter.MAGIC_STRING, new String(magicStringBytes)); + } + } + + @Test + public void testCompressedWALStructure() + throws IOException, + QueryProcessException, + IllegalPathException, + NoSuchFieldException, + ClassNotFoundException, + IllegalAccessException { + PublicBAOS baos = new PublicBAOS(); + DataOutputStream dataOutputStream = new DataOutputStream(baos); + List insertRowNodes = new ArrayList<>(); + for (int i = 0; i < 100; ++i) { + InsertRowNode node = WALTestUtils.getInsertRowNode(devicePath, i); + insertRowNodes.add(node); + node.serialize(dataOutputStream); + } + dataOutputStream.close(); + ByteBuffer buf = ByteBuffer.wrap(baos.toByteArray()); + // Compress it + IoTDBDescriptor.getInstance().getConfig().setWALCompressionAlgorithm(CompressionType.LZ4); + WALTestUtils.setMinCompressionSize(0); + try (WALWriter writer = new WALWriter(walFile)) { + buf.position(buf.limit()); + writer.write(buf); + } + ICompressor compressor = ICompressor.getCompressor(CompressionType.LZ4); + byte[] compressed = compressor.compress(buf.array()); + + try (DataInputStream dataInputStream = + new DataInputStream(new BufferedInputStream(Files.newInputStream(walFile.toPath())))) { + byte[] magicStringBytes = new byte[WALWriter.MAGIC_STRING_BYTES]; + // head magic string + dataInputStream.readFully(magicStringBytes); + Assert.assertEquals(WALWriter.MAGIC_STRING, new String(magicStringBytes)); + Assert.assertEquals( + CompressionType.LZ4, CompressionType.deserialize(dataInputStream.readByte())); + Assert.assertEquals(compressed.length, dataInputStream.readInt()); + Assert.assertEquals(buf.array().length, dataInputStream.readInt()); + ByteBuffer dataBuf = ByteBuffer.allocate(compressed.length); + dataInputStream.readFully(dataBuf.array()); + Assert.assertArrayEquals(compressed, dataBuf.array()); + IUnCompressor unCompressor = IUnCompressor.getUnCompressor(CompressionType.LZ4); + Assert.assertArrayEquals(unCompressor.uncompress(compressed), buf.array()); + Assert.assertEquals( + new WALSignalEntry(WALEntryType.WAL_FILE_INFO_END_MARKER), + WALEntry.deserialize(dataInputStream)); + ByteBuffer metadataBuf = ByteBuffer.allocate(12 + Integer.BYTES); + dataInputStream.readFully(metadataBuf.array()); + // Tail magic string + dataInputStream.readFully(magicStringBytes); + Assert.assertEquals(WALWriter.MAGIC_STRING, new String(magicStringBytes)); + } + } + + @Test + public void testWALReaderWithoutCompression() + throws QueryProcessException, IllegalPathException, IOException, InterruptedException { + IoTDBDescriptor.getInstance() + .getConfig() + .setWALCompressionAlgorithm(CompressionType.UNCOMPRESSED); + testWALReader(); + } + + @Test + public void testWALReaderWithCompression() + throws QueryProcessException, + IllegalPathException, + IOException, + InterruptedException, + NoSuchFieldException, + ClassNotFoundException, + IllegalAccessException { + IoTDBDescriptor.getInstance().getConfig().setWALCompressionAlgorithm(CompressionType.LZ4); + WALTestUtils.setMinCompressionSize(0); + testWALReader(); + } + + public void testWALReader() + throws IOException, QueryProcessException, IllegalPathException, InterruptedException { + File dir = new File(compressionDir); + if (!dir.exists()) { + dir.mkdirs(); + } + WALBuffer walBuffer = new WALBuffer("", compressionDir); + List entryList = new ArrayList<>(); + for (int i = 0; i < 100; ++i) { + InsertRowNode node = WALTestUtils.getInsertRowNode(devicePath, i); + WALEntry entry = new WALInfoEntry(0, node); + walBuffer.write(entry); + entryList.add(entry); + } + long sleepTime = 0; + while (!walBuffer.isAllWALEntriesConsumed()) { + Thread.sleep(100); + sleepTime += 100; + if (sleepTime > 10_000) { + Assert.fail("It has been too long for all entries to be consumed"); + } + } + walBuffer.close(); + + File[] walFiles = WALFileUtils.listAllWALFiles(new File(compressionDir)); + Assert.assertNotNull(walFiles); + Assert.assertEquals(1, walFiles.length); + List readWALEntryList = new ArrayList<>(); + try (WALReader reader = new WALReader(walFiles[0])) { + while (reader.hasNext()) { + readWALEntryList.add(reader.next()); + } + } + Assert.assertEquals(entryList, readWALEntryList); + + try (WALByteBufReader reader = new WALByteBufReader(walFiles[0])) { + for (int i = 0; i < 100; ++i) { + Assert.assertTrue(reader.hasNext()); + ByteBuffer buffer = reader.next(); + Assert.assertEquals(entryList.get(i).serializedSize(), buffer.array().length); + } + } + } + + @Test + public void testHotLoad() + throws IOException, + QueryProcessException, + IllegalPathException, + InterruptedException, + NoSuchFieldException, + ClassNotFoundException, + IllegalAccessException { + File dir = new File(compressionDir); + if (!dir.exists()) { + dir.mkdirs(); + } + WALTestUtils.setMinCompressionSize(0); + IoTDBDescriptor.getInstance() + .getConfig() + .setWALCompressionAlgorithm(CompressionType.UNCOMPRESSED); + // Do not compress wal for these entries + WALBuffer walBuffer = new WALBuffer("", compressionDir); + List entryList = new ArrayList<>(); + for (int i = 0; i < 50; ++i) { + InsertRowNode node = WALTestUtils.getInsertRowNode(devicePath, i); + WALEntry entry = new WALInfoEntry(0, node); + walBuffer.write(entry); + entryList.add(entry); + } + long sleepTime = 0; + while (!walBuffer.isAllWALEntriesConsumed()) { + Thread.sleep(100); + sleepTime += 100; + if (sleepTime > 10_000) { + Assert.fail("It has been too long for all entries to be consumed"); + } + } + + // compress wal for these entries + IoTDBDescriptor.getInstance().getConfig().setWALCompressionAlgorithm(CompressionType.LZ4); + for (int i = 50; i < 100; ++i) { + InsertRowNode node = WALTestUtils.getInsertRowNode(devicePath, i); + WALEntry entry = new WALInfoEntry(0, node); + walBuffer.write(entry); + entryList.add(entry); + } + sleepTime = 0; + while (!walBuffer.isAllWALEntriesConsumed()) { + Thread.sleep(100); + sleepTime += 100; + if (sleepTime > 10_000) { + Assert.fail("It has been too long for all entries to be consumed"); + } + } + walBuffer.close(); + + File[] walFiles = WALFileUtils.listAllWALFiles(new File(compressionDir)); + Assert.assertNotNull(walFiles); + Assert.assertEquals(1, walFiles.length); + List readWALEntryList = new ArrayList<>(); + try (WALReader reader = new WALReader(walFiles[0])) { + while (reader.hasNext()) { + readWALEntryList.add(reader.next()); + } + } + Assert.assertEquals(entryList, readWALEntryList); + + try (WALByteBufReader reader = new WALByteBufReader(walFiles[0])) { + for (int i = 0; i < 100; ++i) { + Assert.assertTrue(reader.hasNext()); + ByteBuffer buffer = reader.next(); + Assert.assertEquals(entryList.get(i).serializedSize(), buffer.array().length); + } + } + } +} diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/node/WALNodeTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/node/WALNodeTest.java index 61f5e4150e535..a3c2e71e4d2ab 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/node/WALNodeTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/node/WALNodeTest.java @@ -80,9 +80,12 @@ public class WALNodeTest { private WALMode prevMode; private String prevConsensus; private WALNode walNode; + private long originWALThreshold = + IoTDBDescriptor.getInstance().getConfig().getWalFileSizeThresholdInByte(); @Before public void setUp() throws Exception { + IoTDBDescriptor.getInstance().getConfig().setWalFileSizeThresholdInByte(2 * 1024 * 1024); EnvironmentUtils.cleanDir(logDirectory); prevMode = config.getWalMode(); prevConsensus = config.getDataRegionConsensusProtocolClass(); @@ -93,6 +96,7 @@ public void setUp() throws Exception { @After public void tearDown() throws Exception { + IoTDBDescriptor.getInstance().getConfig().setWalFileSizeThresholdInByte(originWALThreshold); walNode.close(); config.setWalMode(prevMode); config.setDataRegionConsensusProtocolClass(prevConsensus); diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/WALRecoverManagerTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/WALRecoverManagerTest.java index 846ab90549d92..dace1a99ba627 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/WALRecoverManagerTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/WALRecoverManagerTest.java @@ -110,9 +110,12 @@ public class WALRecoverManagerTest { private CheckpointManager checkpointManager; private TsFileResource tsFileWithWALResource; private TsFileResource tsFileWithoutWALResource; + private long originWALThreshold = + IoTDBDescriptor.getInstance().getConfig().getWalFileSizeThresholdInByte(); @Before public void setUp() throws Exception { + IoTDBDescriptor.getInstance().getConfig().setWalFileSizeThresholdInByte(1 * 1024 * 1024); EnvironmentUtils.cleanDir(new File(FILE_WITH_WAL_NAME).getParent()); EnvironmentUtils.envSetUp(); prevMode = config.getWalMode(); @@ -123,6 +126,7 @@ public void setUp() throws Exception { @After public void tearDown() throws Exception { + IoTDBDescriptor.getInstance().getConfig().setWalFileSizeThresholdInByte(originWALThreshold); if (tsFileWithWALResource != null) { tsFileWithWALResource.close(); } diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/WALRecoverWriterTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/WALRecoverWriterTest.java index c22505ad1a342..97b00f379f237 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/WALRecoverWriterTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/recover/WALRecoverWriterTest.java @@ -71,9 +71,13 @@ public void testEmptyFile() throws IOException { // recover WALRecoverWriter walRecoverWriter = new WALRecoverWriter(logFile); walRecoverWriter.recover(walMetaData); - // verify file, marker + metadata(search index + size number) + metadata size + magic string + // verify file, marker + metadata(search index + size number) + metadata size + head magic + // string + tail magic string Assert.assertEquals( - Byte.BYTES + (Long.BYTES + Integer.BYTES) + Integer.BYTES + WALWriter.MAGIC_STRING_BYTES, + Byte.BYTES + + (Long.BYTES + Integer.BYTES) + + Integer.BYTES + + WALWriter.MAGIC_STRING_BYTES * 2, logFile.length()); try (WALByteBufReader reader = new WALByteBufReader(logFile)) { Assert.assertFalse(reader.hasNext()); @@ -95,7 +99,10 @@ public void testFileWithoutMagicString() throws IOException { walRecoverWriter.recover(walMetaData); // verify file, marker + metadata(search index + size number) + metadata size + magic string Assert.assertEquals( - Byte.BYTES + (Long.BYTES + Integer.BYTES) + Integer.BYTES + WALWriter.MAGIC_STRING_BYTES, + Byte.BYTES + + (Long.BYTES + Integer.BYTES) + + Integer.BYTES + + WALWriter.MAGIC_STRING_BYTES * 2, logFile.length()); try (WALByteBufReader reader = new WALByteBufReader(logFile)) { Assert.assertFalse(reader.hasNext()); @@ -162,6 +169,7 @@ public void testFileWithBrokenMagicString() throws IOException, IllegalPathExcep walMetaData.add(size, 1, walEntry.getMemTableId()); try (WALWriter walWriter = new WALWriter(logFile)) { walWriter.write(buffer.getBuffer(), walMetaData); + walMetaData.setTruncateOffSet(walWriter.getOffset()); } long len = logFile.length(); try (FileChannel channel = FileChannel.open(logFile.toPath(), StandardOpenOption.APPEND)) { diff --git a/iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/metricsets/system/SystemMetrics.java b/iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/metricsets/system/SystemMetrics.java index 27f31bf09aa19..1cacf2bf6f5f7 100644 --- a/iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/metricsets/system/SystemMetrics.java +++ b/iotdb-core/metrics/interface/src/main/java/org/apache/iotdb/metrics/metricsets/system/SystemMetrics.java @@ -227,11 +227,11 @@ private void updateLinuxSystemMemInfo() { result.append(line).append("\n"); } } - String[] lines = result.toString().split("\n"); + String[] lines = result.toString().trim().split("\n"); // if failed to get result if (lines.length >= 2) { String[] memParts = lines[1].trim().split("\\s+"); - if (memParts.length == linuxMemoryTitles.length) { + if (memParts.length >= linuxMemoryTitles.length) { usedMemory = Long.parseLong(memParts[2]) * 1024; sharedMemory = Long.parseLong(memParts[4]) * 1024; buffCacheMemory = Long.parseLong(memParts[5]) * 1024; diff --git a/iotdb-core/node-commons/pom.xml b/iotdb-core/node-commons/pom.xml index 5e5a1d251dc65..c44cd19ecd269 100644 --- a/iotdb-core/node-commons/pom.xml +++ b/iotdb-core/node-commons/pom.xml @@ -95,6 +95,10 @@ metrics-core 1.3.3-SNAPSHOT + + io.dropwizard.metrics + metrics-core + org.slf4j slf4j-api @@ -174,6 +178,10 @@ awaitility test + + org.apache.ratis + ratis-common + diff --git a/iotdb-core/node-commons/src/assembly/resources/conf/generate_properties.bat b/iotdb-core/node-commons/src/assembly/resources/conf/generate_properties.bat index f158d7fe6d2f6..e04e11cf70e26 100644 --- a/iotdb-core/node-commons/src/assembly/resources/conf/generate_properties.bat +++ b/iotdb-core/node-commons/src/assembly/resources/conf/generate_properties.bat @@ -61,4 +61,5 @@ for /f "usebackq tokens=*" %%i in ("%target_template_file%") do ( echo !line!>>"%target_properties_file%" ) endlocal -) \ No newline at end of file +) +powershell -Command "(Get-Content '%target_properties_file%') -join \"`n\" | Set-Content -NoNewline '%target_properties_file%'" diff --git a/iotdb-core/node-commons/src/assembly/resources/conf/iotdb-system.properties b/iotdb-core/node-commons/src/assembly/resources/conf/iotdb-system.properties index 9e32106da5271..7dbf5f5b7165c 100644 --- a/iotdb-core/node-commons/src/assembly/resources/conf/iotdb-system.properties +++ b/iotdb-core/node-commons/src/assembly/resources/conf/iotdb-system.properties @@ -257,6 +257,7 @@ dn_seed_config_node=127.0.0.1:10710 # dn_rpc_thrift_compression_enable=false # if true, a snappy based compression method will be called before sending data by the network +# effectiveMode: restart # Datatype: boolean # this feature is under development, set this as false before it is done. # dn_rpc_advanced_compression_enable=false @@ -431,6 +432,7 @@ dn_seed_config_node=127.0.0.1:10710 # If it is relative, system will save the data in the relative path directory it indicates under the IoTDB folder. # If there are more than one directory, please separate them by commas ",". # Note: If pipe_consensus_receiver_file_dirs is assigned an empty string(i.e.,zero-size), it will be handled as a relative path. +# effectiveMode: restart # For windows platform # If its prefix is a drive specifier followed by "\\", or if its prefix is "\\\\", then the path is absolute. Otherwise, it is relative. # pipe_consensus_receiver_file_dirs=data\\datanode\\system\\pipe\\consensus\\receiver @@ -537,6 +539,7 @@ dn_metric_prometheus_reporter_port=9092 #################### # Used for indicate cluster name and distinguish different cluster. +# effectiveMode: first_start # Datatype: string cluster_name=defaultCluster @@ -719,6 +722,7 @@ data_replication_factor=1 # primitive_array_size=64 # Ratio of compaction memory for chunk metadata maintains in memory when doing compaction +# effectiveMode: restart # Datatype: double # chunk_metadata_size_proportion=0.1 @@ -741,6 +745,7 @@ data_replication_factor=1 # reject_proportion=0.8 # Ratio of memory for the DevicePathCache. DevicePathCache is the deviceId cache, keep only one copy of the same deviceId in memory +# effectiveMode: restart # Datatype: double # device_path_cache_proportion=0.05 @@ -812,12 +817,15 @@ data_replication_factor=1 # Policy of DataNodeSchemaCache eviction. # Support FIFO and LRU policy. FIFO takes low cache update overhead. LRU takes high cache hit rate. +# effectiveMode: restart +# Datatype: int # datanode_schema_cache_eviction_policy=FIFO # This configuration parameter sets the maximum number of time series allowed in the cluster. # The value should be a positive integer representing the desired threshold. # When the threshold is reached, users will be prohibited from creating new time series. # -1 means unlimited +# effectiveMode: restart # Datatype: int # cluster_timeseries_limit_threshold=-1 @@ -825,6 +833,7 @@ data_replication_factor=1 # The value should be a positive integer representing the desired threshold. # When the threshold is reached, users will be prohibited from creating new time series. # -1 means unlimited +# effectiveMode: restart # Datatype: int # cluster_device_limit_threshold=-1 @@ -832,6 +841,7 @@ data_replication_factor=1 # The value should be a positive integer representing the desired threshold. # When the threshold is reached, users will be prohibited from creating new databases. # -1 means unlimited. +# effectiveMode: restart # Datatype: int # database_limit_threshold = -1 @@ -989,10 +999,12 @@ data_replication_factor=1 # query_thread_count=0 # How many pipeline drivers will be created for one fragment instance. When <= 0, use CPU core number / 2. +# effectiveMode: restart # Datatype: int # degree_of_query_parallelism=0 # The threshold of count map size when calculating the MODE aggregation function +# effectiveMode: restart # Datatype: int # mode_map_size_threshold=10000 @@ -1002,6 +1014,7 @@ data_replication_factor=1 # batch_size=100000 # The memory for external sort in sort operator, when the data size is smaller than sort_buffer_size_in_bytes, the sort operator will use in-memory sort. +# effectiveMode: restart # Datatype: long # sort_buffer_size_in_bytes=1048576 @@ -1021,6 +1034,7 @@ data_replication_factor=1 # timestamp_precision=ms # When the timestamp precision check is enabled, the timestamps those are over 13 digits for ms precision, or over 16 digits for us precision are not allowed to be inserted. +# effectiveMode: first_start # Datatype: Boolean # timestamp_precision_check_enabled=true @@ -1033,12 +1047,14 @@ data_replication_factor=1 # default_ttl_in_ms=-1 # The maximum number of TTL rules stored in the system, the default is 1000. +# effectiveMode: restart # Negative value means the threshold is unlimited. # Datatype: int # ttl_rule_capacity=1000 # The interval of TTL check task in each database. The TTL check task will inspect and select files with a higher volume of expired data for compaction. Default is 2 hours. # Notice: It is not recommended to change it too small, as it will affect the read and write performance of the system. +# effectiveMode: restart # Unit: ms # Datatype: int # ttl_check_interval=7200000 @@ -1046,11 +1062,13 @@ data_replication_factor=1 # The maximum expiring time of devices that have a ttl. Default is 1 month. # If the data elapsed time (current timestamp minus the maximum data timestamp of the device in the file) of such devices exceeds this value, then the file will be cleaned by compaction. # Notice: It is not recommended to change it too small, as it will affect the read and write performance of the system. +# effectiveMode: restart # Unit: ms # Datatype: int # max_expired_time=2592000000 # The expired device ratio. If the ratio of expired devices in one file exceeds this value, then expired data of this file will be cleaned by compaction. +# effectiveMode: restart # Datatype: float # expired_data_ratio=0.3 @@ -1062,6 +1080,7 @@ data_replication_factor=1 # Add a switch to enable separate sequence and unsequence data. # If it is true, then data will be separated into seq and unseq data dir. If it is false, then all data will be written into unseq data dir. +# effectiveMode: restart # Datatype: boolean # enable_separate_data=true @@ -1208,6 +1227,7 @@ data_replication_factor=1 # compaction_priority=BALANCE # The size of candidate compaction task queue. +# effectiveMode: restart # Datatype: int # candidate_compaction_task_queue_size=50 @@ -1263,13 +1283,6 @@ data_replication_factor=1 # Datatype: int # min_cross_compaction_unseq_file_level=1 -# If one merge file selection runs for more than this time, it will be ended and its current -# selection will be used as final selection. -# When < 0, it means time is unbounded. -# effectiveMode: restart -# Datatype: long, Unit: ms -# cross_compaction_file_selection_time_budget=30000 - # How many threads will be set up to perform compaction, 10 by default. # Set to 1 when less than or equal to 0. # effectiveMode: hot_reload @@ -1418,6 +1431,10 @@ data_replication_factor=1 # Datatype: long # iot_consensus_cache_window_time_in_ms=-1 +# Enable Write Ahead Log compression. +# Option: true, false +# enable_wal_compression=false + #################### ### IoTConsensus Configuration #################### @@ -1623,6 +1640,7 @@ data_replication_factor=1 # For Windows platform # If its prefix is a drive specifier followed by "\\", or if its prefix is "\\\\", then the path is # absolute. Otherwise, it is relative. +# effectiveMode: first_start # pipe_lib_dir=ext\\pipe # For Linux platform # If its prefix is "/", then the path is absolute. Otherwise, it is relative. @@ -1630,34 +1648,41 @@ data_replication_factor=1 # The maximum number of threads that can be used to execute the pipe subtasks in PipeSubtaskExecutor. # The actual value will be min(pipe_subtask_executor_max_thread_num, max(1, CPU core number / 2)). +# effectiveMode: restart # Datatype: int # pipe_subtask_executor_max_thread_num=5 # The connection timeout (in milliseconds) for the thrift client. +# effectiveMode: restart # Datatype: int # pipe_sink_timeout_ms=900000 # The maximum number of selectors that can be used in the sink. # Recommend to set this value to less than or equal to pipe_sink_max_client_number. +# effectiveMode: restart # Datatype: int # pipe_sink_selector_number=4 # The maximum number of clients that can be used in the sink. +# effectiveMode: restart # Datatype: int # pipe_sink_max_client_number=16 # Whether to enable receiving pipe data through air gap. # The receiver can only return 0 or 1 in tcp mode to indicate whether the data is received successfully. +# effectiveMode: restart # Datatype: Boolean # pipe_air_gap_receiver_enabled=false # The port for the server to receive pipe data through air gap. # Datatype: int +# effectiveMode: restart # pipe_air_gap_receiver_port=9780 # The total bytes that all pipe sinks can transfer per second. # When given a value less than or equal to 0, it means no limit. # default value is -1, which means no limit. +# effectiveMode: hot_reload # Datatype: double # pipe_all_sinks_rate_limit_bytes_per_second=-1 @@ -1755,12 +1780,14 @@ data_replication_factor=1 # data_region_ratis_preserve_logs_num_when_purge=1000 # Raft Log disk size control +# effectiveMode: restart # Datatype: int # config_node_ratis_log_max_size = 2147483648 # schema_region_ratis_log_max_size = 2147483648 # data_region_ratis_log_max_size = 21474836480 # Raft periodic snapshot interval, time unit is second +# effectiveMode: restart # Datatype: int # config_node_ratis_periodic_snapshot_interval=86400 # schema_region_ratis_periodic_snapshot_interval=86400 @@ -1770,6 +1797,7 @@ data_replication_factor=1 ### Fast IoTConsensus Configuration #################### # Default event buffer size for connector and receiver in pipe consensus +# effectiveMode: restart # DataType: int # fast_iot_consensus_pipeline_size=5 @@ -1831,6 +1859,7 @@ data_replication_factor=1 #################### # The thread count which can be used for model inference operation. +# effectiveMode: restart # Datatype: int # model_inference_execution_thread_count=5 @@ -1847,6 +1876,7 @@ data_replication_factor=1 # The maximum bytes per second of disk write throughput when loading tsfile. # When given a value less than or equal to 0, it means no limit. # Default value is -1, which means no limit. +# effectiveMode: hot_reload # Datatype: int # load_write_throughput_bytes_per_second=-1 diff --git a/iotdb-core/node-commons/src/assembly/resources/sbin/iotdb-common.sh b/iotdb-core/node-commons/src/assembly/resources/sbin/iotdb-common.sh index 753d1bccb0517..0236fef3f4139 100755 --- a/iotdb-core/node-commons/src/assembly/resources/sbin/iotdb-common.sh +++ b/iotdb-core/node-commons/src/assembly/resources/sbin/iotdb-common.sh @@ -150,6 +150,18 @@ checkAllConfigNodeVariables() fi } +check_config_unique() { + local key=$1 + local values=$2 + + line_count=$(echo "$values" | wc -l) + + if [ "$line_count" -gt 1 ]; then + echo "Error: Duplicate $key entries found" + exit 1 + fi +} + checkDataNodePortUsages () { echo "Checking whether the ports are already occupied..." if [ "$(id -u)" -ne 0 ]; then @@ -183,6 +195,13 @@ checkDataNodePortUsages () { else echo "Warning: cannot find iotdb-system.properties or iotdb-datanode.properties, check the default configuration" fi + + check_config_unique "dn_rpc_port" "$dn_rpc_port" + check_config_unique "dn_internal_port" "$dn_internal_port" + check_config_unique "dn_mpp_data_exchange_port" "$dn_mpp_data_exchange_port" + check_config_unique "dn_schema_region_consensus_port" "$dn_schema_region_consensus_port" + check_config_unique "dn_data_region_consensus_port" "$dn_data_region_consensus_port" + dn_rpc_port=${dn_rpc_port:-6667} dn_internal_port=${dn_internal_port:-10730} dn_mpp_data_exchange_port=${dn_mpp_data_exchange_port:-10740} @@ -271,6 +290,10 @@ checkConfigNodePortUsages () { else echo "Cannot find iotdb-system.properties or iotdb-confignode.properties, check the default configuration" fi + + check_config_unique "cn_internal_port" "$cn_internal_port" + check_config_unique "cn_consensus_port" "$cn_consensus_port" + cn_internal_port=${cn_internal_port:-10710} cn_consensus_port=${cn_consensus_port:-10720} if type lsof >/dev/null 2>&1; then diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/ClientPoolFactory.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/ClientPoolFactory.java index a157a9eaf63ac..ee550d09a74dd 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/ClientPoolFactory.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/ClientPoolFactory.java @@ -20,7 +20,8 @@ package org.apache.iotdb.commons.client; import org.apache.iotdb.common.rpc.thrift.TEndPoint; -import org.apache.iotdb.commons.client.async.AsyncConfigNodeIServiceClient; +import org.apache.iotdb.commons.client.async.AsyncConfigNodeInternalServiceClient; +import org.apache.iotdb.commons.client.async.AsyncDataNodeExternalServiceClient; import org.apache.iotdb.commons.client.async.AsyncDataNodeInternalServiceClient; import org.apache.iotdb.commons.client.async.AsyncDataNodeMPPDataExchangeServiceClient; import org.apache.iotdb.commons.client.async.AsyncPipeConsensusServiceClient; @@ -67,15 +68,15 @@ public KeyedObjectPool createClientPool } } - public static class AsyncConfigNodeIServiceClientPoolFactory - implements IClientPoolFactory { + public static class AsyncConfigNodeInternalServiceClientPoolFactory + implements IClientPoolFactory { @Override - public KeyedObjectPool createClientPool( - ClientManager manager) { - GenericKeyedObjectPool clientPool = + public KeyedObjectPool createClientPool( + ClientManager manager) { + GenericKeyedObjectPool clientPool = new GenericKeyedObjectPool<>( - new AsyncConfigNodeIServiceClient.Factory( + new AsyncConfigNodeInternalServiceClient.Factory( manager, new ThriftClientProperty.Builder() .setConnectionTimeoutMs(conf.getConnectionTimeoutInMS()) @@ -83,7 +84,9 @@ public KeyedObjectPool createClientPoo .setSelectorNumOfAsyncClientManager(conf.getSelectorNumOfClientManager()) .build(), ThreadName.ASYNC_CONFIGNODE_CLIENT_POOL.getName()), - new ClientPoolProperty.Builder().build().getConfig()); + new ClientPoolProperty.Builder() + .build() + .getConfig()); ClientManagerMetrics.getInstance() .registerClientManager(this.getClass().getSimpleName(), clientPool); return clientPool; @@ -138,16 +141,41 @@ public KeyedObjectPool createClie } } + public static class AsyncDataNodeExternalServiceClientPoolFactory + implements IClientPoolFactory { + + @Override + public KeyedObjectPool createClientPool( + ClientManager manager) { + GenericKeyedObjectPool clientPool = + new GenericKeyedObjectPool<>( + new AsyncDataNodeExternalServiceClient.Factory( + manager, + new ThriftClientProperty.Builder() + .setConnectionTimeoutMs(conf.getConnectionTimeoutInMS()) + .setRpcThriftCompressionEnabled(conf.isRpcThriftCompressionEnabled()) + .setSelectorNumOfAsyncClientManager(conf.getSelectorNumOfClientManager()) + .build(), + ThreadName.ASYNC_DATANODE_CLIENT_POOL.getName()), + new ClientPoolProperty.Builder() + .build() + .getConfig()); + ClientManagerMetrics.getInstance() + .registerClientManager(this.getClass().getSimpleName(), clientPool); + return clientPool; + } + } + public static class AsyncConfigNodeHeartbeatServiceClientPoolFactory - implements IClientPoolFactory { + implements IClientPoolFactory { @Override - public KeyedObjectPool createClientPool( - ClientManager manager) { + public KeyedObjectPool createClientPool( + ClientManager manager) { - GenericKeyedObjectPool clientPool = + GenericKeyedObjectPool clientPool = new GenericKeyedObjectPool<>( - new AsyncConfigNodeIServiceClient.Factory( + new AsyncConfigNodeInternalServiceClient.Factory( manager, new ThriftClientProperty.Builder() .setConnectionTimeoutMs(conf.getConnectionTimeoutInMS()) @@ -156,7 +184,9 @@ public KeyedObjectPool createClientPoo .setPrintLogWhenEncounterException(false) .build(), ThreadName.ASYNC_CONFIGNODE_HEARTBEAT_CLIENT_POOL.getName()), - new ClientPoolProperty.Builder().build().getConfig()); + new ClientPoolProperty.Builder() + .build() + .getConfig()); ClientManagerMetrics.getInstance() .registerClientManager(this.getClass().getSimpleName(), clientPool); return clientPool; diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/async/AsyncConfigNodeIServiceClient.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/async/AsyncConfigNodeInternalServiceClient.java similarity index 83% rename from iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/async/AsyncConfigNodeIServiceClient.java rename to iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/async/AsyncConfigNodeInternalServiceClient.java index 36d273c7b7826..b5adc96113609 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/async/AsyncConfigNodeIServiceClient.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/async/AsyncConfigNodeInternalServiceClient.java @@ -36,20 +36,21 @@ import java.io.IOException; -public class AsyncConfigNodeIServiceClient extends IConfigNodeRPCService.AsyncClient +public class AsyncConfigNodeInternalServiceClient extends IConfigNodeRPCService.AsyncClient implements ThriftClient { - private static final Logger logger = LoggerFactory.getLogger(AsyncConfigNodeIServiceClient.class); + private static final Logger logger = + LoggerFactory.getLogger(AsyncConfigNodeInternalServiceClient.class); private final boolean printLogWhenEncounterException; private final TEndPoint endpoint; - private final ClientManager clientManager; + private final ClientManager clientManager; - public AsyncConfigNodeIServiceClient( + public AsyncConfigNodeInternalServiceClient( ThriftClientProperty property, TEndPoint endpoint, TAsyncClientManager tClientManager, - ClientManager clientManager) + ClientManager clientManager) throws IOException { super( property.getProtocolFactory(), @@ -126,10 +127,10 @@ public String toString() { } public static class Factory - extends AsyncThriftClientFactory { + extends AsyncThriftClientFactory { public Factory( - ClientManager clientManager, + ClientManager clientManager, ThriftClientProperty thriftClientProperty, String threadName) { super(clientManager, thriftClientProperty, threadName); @@ -137,15 +138,15 @@ public Factory( @Override public void destroyObject( - TEndPoint endPoint, PooledObject pooledObject) { + TEndPoint endPoint, PooledObject pooledObject) { pooledObject.getObject().close(); } @Override - public PooledObject makeObject(TEndPoint endPoint) + public PooledObject makeObject(TEndPoint endPoint) throws Exception { return new DefaultPooledObject<>( - new AsyncConfigNodeIServiceClient( + new AsyncConfigNodeInternalServiceClient( thriftClientProperty, endPoint, tManagers[clientCnt.incrementAndGet() % tManagers.length], @@ -154,7 +155,7 @@ public PooledObject makeObject(TEndPoint endPoint @Override public boolean validateObject( - TEndPoint endPoint, PooledObject pooledObject) { + TEndPoint endPoint, PooledObject pooledObject) { return pooledObject.getObject().isReady(); } } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/async/AsyncDataNodeExternalServiceClient.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/async/AsyncDataNodeExternalServiceClient.java new file mode 100644 index 0000000000000..5de58b8eef14d --- /dev/null +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/async/AsyncDataNodeExternalServiceClient.java @@ -0,0 +1,174 @@ +/* + * 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.iotdb.commons.client.async; + +import org.apache.iotdb.common.rpc.thrift.TEndPoint; +import org.apache.iotdb.commons.client.ClientManager; +import org.apache.iotdb.commons.client.ThriftClient; +import org.apache.iotdb.commons.client.factory.AsyncThriftClientFactory; +import org.apache.iotdb.commons.client.property.ThriftClientProperty; +import org.apache.iotdb.commons.utils.TestOnly; +import org.apache.iotdb.mpp.rpc.thrift.IDataNodeRPCService; +import org.apache.iotdb.rpc.TNonblockingSocketWrapper; + +import org.apache.commons.lang3.exception.ExceptionUtils; +import org.apache.commons.pool2.PooledObject; +import org.apache.commons.pool2.impl.DefaultPooledObject; +import org.apache.thrift.async.TAsyncClientManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.IOException; + +public class AsyncDataNodeExternalServiceClient extends IDataNodeRPCService.AsyncClient + implements ThriftClient { + + private static final Logger logger = + LoggerFactory.getLogger(AsyncDataNodeExternalServiceClient.class); + + private final boolean printLogWhenEncounterException; + + private final TEndPoint endpoint; + private final ClientManager clientManager; + + public AsyncDataNodeExternalServiceClient( + ThriftClientProperty property, + TEndPoint endpoint, + TAsyncClientManager tClientManager, + ClientManager clientManager) + throws IOException { + super( + property.getProtocolFactory(), + tClientManager, + TNonblockingSocketWrapper.wrap( + endpoint.getIp(), endpoint.getPort(), property.getConnectionTimeoutMs())); + setTimeout(property.getConnectionTimeoutMs()); + this.printLogWhenEncounterException = property.isPrintLogWhenEncounterException(); + this.endpoint = endpoint; + this.clientManager = clientManager; + } + + @TestOnly + public TEndPoint getTEndpoint() { + return endpoint; + } + + @TestOnly + public ClientManager getClientManager() { + return clientManager; + } + + @Override + public void onComplete() { + super.onComplete(); + returnSelf(); + } + + @Override + public void onError(Exception e) { + super.onError(e); + ThriftClient.resolveException(e, this); + returnSelf(); + } + + @Override + public void invalidate() { + if (!hasError()) { + super.onError(new Exception("This client has been invalidated")); + } + } + + @Override + public void invalidateAll() { + clientManager.clear(endpoint); + } + + @Override + public boolean printLogWhenEncounterException() { + return printLogWhenEncounterException; + } + + /** + * return self, the method doesn't need to be called by the user and will be triggered after the + * RPC is finished. + */ + private void returnSelf() { + clientManager.returnClient(endpoint, this); + } + + private void close() { + ___transport.close(); + ___currentMethod = null; + } + + public boolean isReady() { + try { + checkReady(); + return true; + } catch (Exception e) { + if (printLogWhenEncounterException) { + logger.error( + "Unexpected exception occurs in {}, error msg is {}", + this, + ExceptionUtils.getRootCause(e).toString()); + } + return false; + } + } + + @Override + public String toString() { + return String.format("AsyncDataNodeInternalServiceClient{%s}", endpoint); + } + + public static class Factory + extends AsyncThriftClientFactory { + + public Factory( + ClientManager clientManager, + ThriftClientProperty thriftClientProperty, + String threadName) { + super(clientManager, thriftClientProperty, threadName); + } + + @Override + public void destroyObject( + TEndPoint endPoint, PooledObject pooledObject) { + pooledObject.getObject().close(); + } + + @Override + public PooledObject makeObject(TEndPoint endPoint) + throws Exception { + return new DefaultPooledObject<>( + new AsyncDataNodeExternalServiceClient( + thriftClientProperty, + endPoint, + tManagers[clientCnt.incrementAndGet() % tManagers.length], + clientManager)); + } + + @Override + public boolean validateObject( + TEndPoint endPoint, PooledObject pooledObject) { + return pooledObject.getObject().isReady(); + } + } +} diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/container/PipeConsensusClientMgrContainer.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/container/PipeConsensusClientMgrContainer.java index 5a52eb3440932..6fc041634331e 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/container/PipeConsensusClientMgrContainer.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/container/PipeConsensusClientMgrContainer.java @@ -42,7 +42,7 @@ public class PipeConsensusClientMgrContainer { private final IClientManager asyncClientManager; private final IClientManager syncClientManager; - public PipeConsensusClientMgrContainer() { + private PipeConsensusClientMgrContainer() { // load rpc client config PipeConsensusClientProperty config = PipeConsensusClientProperty.newBuilder() diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/request/AsyncRequestContext.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/request/AsyncRequestContext.java new file mode 100644 index 0000000000000..8b54072a4c40e --- /dev/null +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/request/AsyncRequestContext.java @@ -0,0 +1,138 @@ +/* + * 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.iotdb.commons.client.request; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.CountDownLatch; + +/** + * Asynchronous Client handler. + * + * @param ClassName of RPC request + * @param ClassName of RPC response + */ +public class AsyncRequestContext { + + // Type of RPC request + protected final RequestType requestType; + + /** + * Map key: The indices of asynchronous RPC requests. + * + *

Map value: The corresponding RPC request + */ + private final Map requestMap; + + /** + * Map key: The indices of asynchronous RPC requests. + * + *

Map value: The target Nodes of corresponding indices + * + *

All kinds of AsyncHandler will remove its targetNode from the nodeLocationMap only if its + * corresponding RPC request success + */ + private final Map nodeLocationMap; + + /** + * Map key: The indices(targetNode's ID) of asynchronous RPC requests. + * + *

Map value: The response of corresponding indices + * + *

All kinds of AsyncHandler will add response to the responseMap after its corresponding RPC + * request finished + */ + private final Map responseMap; + + private CountDownLatch countDownLatch; + + /** Custom constructor. */ + public AsyncRequestContext(RequestType requestType) { + this.requestType = requestType; + this.requestMap = new ConcurrentHashMap<>(); + this.nodeLocationMap = new ConcurrentHashMap<>(); + this.responseMap = new ConcurrentHashMap<>(); + } + + public void putRequest(int requestId, Request request) { + requestMap.put(requestId, request); + } + + public void putNodeLocation(int requestId, NodeLocation nodeLocation) { + nodeLocationMap.put(requestId, nodeLocation); + } + + /** Constructor for null requests. */ + public AsyncRequestContext(RequestType requestType, Map nodeLocationMap) { + this.requestType = requestType; + this.nodeLocationMap = nodeLocationMap; + this.requestMap = new ConcurrentHashMap<>(); + this.responseMap = new ConcurrentHashMap<>(); + } + + /** Constructor for unique request. */ + public AsyncRequestContext( + RequestType requestType, Request request, Map nodeLocationMap) { + this.requestType = requestType; + this.nodeLocationMap = nodeLocationMap; + this.requestMap = new ConcurrentHashMap<>(); + this.nodeLocationMap.keySet().forEach(nodeId -> this.requestMap.put(nodeId, request)); + this.responseMap = new ConcurrentHashMap<>(); + } + + public RequestType getRequestType() { + return requestType; + } + + public List getRequestIndices() { + return new ArrayList<>(nodeLocationMap.keySet()); + } + + public Request getRequest(int requestId) { + return requestMap.get(requestId); + } + + public NodeLocation getNodeLocation(int requestId) { + return nodeLocationMap.get(requestId); + } + + public Map getNodeLocationMap() { + return nodeLocationMap; + } + + public List getResponseList() { + return new ArrayList<>(responseMap.values()); + } + + public Map getResponseMap() { + return responseMap; + } + + /** Always reset CountDownLatch before retry. */ + public void resetCountDownLatch() { + countDownLatch = new CountDownLatch(nodeLocationMap.size()); + } + + public CountDownLatch getCountDownLatch() { + return countDownLatch; + } +} diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/request/AsyncRequestManager.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/request/AsyncRequestManager.java new file mode 100644 index 0000000000000..ed3feb6598b82 --- /dev/null +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/request/AsyncRequestManager.java @@ -0,0 +1,192 @@ +/* + * 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.iotdb.commons.client.request; + +import org.apache.iotdb.common.rpc.thrift.TEndPoint; +import org.apache.iotdb.commons.client.IClientManager; +import org.apache.iotdb.commons.client.exception.ClientManagerException; +import org.apache.iotdb.commons.utils.function.CheckedTriConsumer; + +import com.google.common.collect.ImmutableMap; +import org.apache.thrift.TException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Objects; +import java.util.concurrent.TimeUnit; + +/** Asynchronously send RPC requests to Nodes. See queryengine.thrift for more details. */ +public abstract class AsyncRequestManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(AsyncRequestManager.class); + + protected IClientManager clientManager; + + protected ImmutableMap< + RequestType, + CheckedTriConsumer< + Object, Client, AsyncRequestRPCHandler, TException>> + actionMap; + + protected ImmutableMap.Builder< + RequestType, + CheckedTriConsumer< + Object, Client, AsyncRequestRPCHandler, TException>> + actionMapBuilder; + + private static final int MAX_RETRY_NUM = 6; + + protected AsyncRequestManager() { + initClientManager(); + actionMapBuilder = ImmutableMap.builder(); + initActionMapBuilder(); + this.actionMap = this.actionMapBuilder.build(); + } + + protected abstract void initClientManager(); + + protected abstract void initActionMapBuilder(); + + /** + * Send asynchronous requests to the specified Nodes with default retry num + * + *

Notice: The Nodes that failed to receive the requests will be reconnected + * + * @param requestContext which will also contain the result + * @param timeoutInMs timeout in milliseconds + */ + public void sendAsyncRequestToNodeWithRetryAndTimeoutInMs( + AsyncRequestContext requestContext, long timeoutInMs) { + sendAsyncRequest(requestContext, MAX_RETRY_NUM, timeoutInMs); + } + + /** + * Send asynchronous requests to the specified Nodes with default retry num + * + *

Notice: The Nodes that failed to receive the requests will be reconnected + * + * @param requestContext which will also contain the result + */ + public final void sendAsyncRequestWithRetry( + AsyncRequestContext requestContext) { + sendAsyncRequest(requestContext, MAX_RETRY_NUM, null); + } + + public final void sendAsyncRequest( + AsyncRequestContext requestContext) { + sendAsyncRequest(requestContext, 1, null); + } + + private void sendAsyncRequest( + AsyncRequestContext requestContext, + int retryNum, + Long timeoutInMs) { + if (requestContext.getRequestIndices().isEmpty()) { + return; + } + + RequestType requestType = requestContext.getRequestType(); + for (int retry = 0; retry < retryNum; retry++) { + // Always Reset CountDownLatch first + requestContext.resetCountDownLatch(); + + // Send requests to all targetNodes + for (int requestId : requestContext.getRequestIndices()) { + NodeLocation targetNode = requestContext.getNodeLocation(requestId); + sendAsyncRequest(requestContext, requestId, targetNode, retry); + } + + // Wait for this batch of asynchronous RPC requests finish + try { + if (timeoutInMs == null) { + requestContext.getCountDownLatch().await(); + } else { + if (!requestContext.getCountDownLatch().await(timeoutInMs, TimeUnit.MILLISECONDS)) { + LOGGER.warn( + "Timeout during {} on ConfigNode. Retry: {}/{}", requestType, retry, retryNum); + } + } + } catch (InterruptedException e) { + LOGGER.error( + "Interrupted during {} on ConfigNode. Retry: {}/{}", requestType, retry, retryNum); + Thread.currentThread().interrupt(); + } + + // Check if there is a Node that fails to execute the request, and retry if there exists + if (requestContext.getRequestIndices().isEmpty()) { + return; + } + } + + if (!requestContext.getRequestIndices().isEmpty()) { + LOGGER.warn( + "Failed to {} on ConfigNode after {} retries, requestIndices: {}", + requestType, + retryNum, + requestContext.getRequestIndices()); + } + } + + protected void sendAsyncRequest( + AsyncRequestContext requestContext, + int requestId, + NodeLocation targetNode, + int retryCount) { + try { + if (!actionMap.containsKey(requestContext.getRequestType())) { + throw new UnsupportedOperationException( + "unsupported request type: " + requestContext.getRequestType()); + } + Client client = clientManager.borrowClient(nodeLocationToEndPoint(targetNode)); + Object req = requestContext.getRequest(requestId); + AsyncRequestRPCHandler handler = + buildHandler(requestContext, requestId, targetNode); + Objects.requireNonNull(actionMap.get(requestContext.getRequestType())) + .accept(req, client, handler); + } catch (Exception e) { + LOGGER.warn( + "{} failed on Node {}, because {}, retrying {}...", + requestContext.getRequestType(), + nodeLocationToEndPoint(targetNode), + e.getMessage(), + retryCount); + } + } + + protected abstract TEndPoint nodeLocationToEndPoint(NodeLocation location); + + protected abstract AsyncRequestRPCHandler buildHandler( + AsyncRequestContext requestContext, + int requestId, + NodeLocation targetNode); + + /** + * Always call this interface when a Node is restarted or removed. + * + * @param endPoint The specific Node + */ + public void resetClient(TEndPoint endPoint) { + clientManager.clear(endPoint); + } + + public Client getAsyncClient(NodeLocation targetNode) throws ClientManagerException { + return clientManager.borrowClient(nodeLocationToEndPoint(targetNode)); + } +} diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/AbstractAsyncRPCHandler.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/request/AsyncRequestRPCHandler.java similarity index 56% rename from iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/AbstractAsyncRPCHandler.java rename to iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/request/AsyncRequestRPCHandler.java index 387359d7ee292..136f4e126f221 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/client/async/handlers/rpc/AbstractAsyncRPCHandler.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/request/AsyncRequestRPCHandler.java @@ -17,69 +17,64 @@ * under the License. */ -package org.apache.iotdb.confignode.client.async.handlers.rpc; - -import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; -import org.apache.iotdb.confignode.client.DataNodeRequestType; +package org.apache.iotdb.commons.client.request; import org.apache.thrift.async.AsyncMethodCallback; import java.util.Map; import java.util.concurrent.CountDownLatch; -public abstract class AbstractAsyncRPCHandler implements AsyncMethodCallback { +public abstract class AsyncRequestRPCHandler + implements AsyncMethodCallback { // Type of RPC request - protected final DataNodeRequestType requestType; + protected final RequestType requestType; // Index of request protected final int requestId; - // Target DataNode - protected final TDataNodeLocation targetDataNode; + // Target Node + protected final NodeLocation targetNode; /** * Map key: The indices of asynchronous RPC requests. * - *

Map value: The target DataNodes of corresponding indices + *

Map value: The target Nodes of corresponding indices * - *

All kinds of AsyncHandler will remove its targetDataNode from the dataNodeLocationMap only - * if its corresponding RPC request success + *

All kinds of AsyncHandler will remove its targetNode from the nodeLocationMap only if its + * corresponding RPC request success */ - protected final Map dataNodeLocationMap; + protected final Map nodeLocationMap; /** - * Map key: The indices(targetDataNode's ID) of asynchronous RPC requests. + * Map key: The indices(targetNode's ID) of asynchronous RPC requests. * *

Map value: The response of corresponding indices * *

All kinds of AsyncHandler will add response to the responseMap after its corresponding RPC * request finished */ - protected final Map responseMap; + protected final Map responseMap; // All kinds of AsyncHandler will invoke countDown after its corresponding RPC request finished protected final CountDownLatch countDownLatch; protected final String formattedTargetLocation; - protected AbstractAsyncRPCHandler( - DataNodeRequestType requestType, + protected AsyncRequestRPCHandler( + RequestType requestType, int requestId, - TDataNodeLocation targetDataNode, - Map dataNodeLocationMap, - Map responseMap, + NodeLocation targetNode, + Map nodeLocationMap, + Map responseMap, CountDownLatch countDownLatch) { this.requestType = requestType; this.requestId = requestId; - this.targetDataNode = targetDataNode; - this.formattedTargetLocation = - "{id=" - + targetDataNode.getDataNodeId() - + ", internalEndPoint=" - + targetDataNode.getInternalEndPoint() - + "}"; + this.targetNode = targetNode; + this.formattedTargetLocation = generateFormattedTargetLocation(targetNode); - this.dataNodeLocationMap = dataNodeLocationMap; + this.nodeLocationMap = nodeLocationMap; this.responseMap = responseMap; this.countDownLatch = countDownLatch; } + + protected abstract String generateFormattedTargetLocation(NodeLocation location); } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/request/ConfigNodeInternalServiceAsyncRequestManager.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/request/ConfigNodeInternalServiceAsyncRequestManager.java new file mode 100644 index 0000000000000..791a1e5df0e96 --- /dev/null +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/request/ConfigNodeInternalServiceAsyncRequestManager.java @@ -0,0 +1,43 @@ +/* + * 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.iotdb.commons.client.request; + +import org.apache.iotdb.common.rpc.thrift.TConfigNodeLocation; +import org.apache.iotdb.common.rpc.thrift.TEndPoint; +import org.apache.iotdb.commons.client.ClientPoolFactory; +import org.apache.iotdb.commons.client.IClientManager; +import org.apache.iotdb.commons.client.async.AsyncConfigNodeInternalServiceClient; + +public abstract class ConfigNodeInternalServiceAsyncRequestManager + extends AsyncRequestManager< + RequestType, TConfigNodeLocation, AsyncConfigNodeInternalServiceClient> { + @Override + protected void initClientManager() { + clientManager = + new IClientManager.Factory() + .createClientManager( + new ClientPoolFactory.AsyncConfigNodeInternalServiceClientPoolFactory()); + } + + @Override + protected TEndPoint nodeLocationToEndPoint(TConfigNodeLocation configNodeLocation) { + return configNodeLocation.getInternalEndPoint(); + } +} diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/request/DataNodeInternalServiceRequestManager.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/request/DataNodeInternalServiceRequestManager.java new file mode 100644 index 0000000000000..fcb1b01857df8 --- /dev/null +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/request/DataNodeInternalServiceRequestManager.java @@ -0,0 +1,43 @@ +/* + * 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.iotdb.commons.client.request; + +import org.apache.iotdb.common.rpc.thrift.TDataNodeLocation; +import org.apache.iotdb.common.rpc.thrift.TEndPoint; +import org.apache.iotdb.commons.client.ClientPoolFactory; +import org.apache.iotdb.commons.client.IClientManager; +import org.apache.iotdb.commons.client.async.AsyncDataNodeInternalServiceClient; + +public abstract class DataNodeInternalServiceRequestManager + extends AsyncRequestManager< + RequestType, TDataNodeLocation, AsyncDataNodeInternalServiceClient> { + @Override + protected void initClientManager() { + clientManager = + new IClientManager.Factory() + .createClientManager( + new ClientPoolFactory.AsyncDataNodeInternalServiceClientPoolFactory()); + } + + @Override + protected TEndPoint nodeLocationToEndPoint(TDataNodeLocation dataNodeLocation) { + return dataNodeLocation.getInternalEndPoint(); + } +} diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/request/Utils.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/request/Utils.java new file mode 100644 index 0000000000000..6d4704f059b8f --- /dev/null +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/client/request/Utils.java @@ -0,0 +1,78 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.commons.client.request; + +import org.apache.iotdb.common.rpc.thrift.TEndPoint; +import org.apache.iotdb.common.rpc.thrift.TSStatus; +import org.apache.iotdb.common.rpc.thrift.TSender; +import org.apache.iotdb.common.rpc.thrift.TServiceProvider; +import org.apache.iotdb.common.rpc.thrift.TServiceType; +import org.apache.iotdb.common.rpc.thrift.TTestConnectionResult; +import org.apache.iotdb.rpc.TSStatusCode; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Function; +import java.util.stream.Collectors; + +public class Utils { + public static + List testConnectionsImpl( + List nodeLocations, + TSender sender, + Function getId, + Function getEndPoint, + TServiceType serviceType, + RequestType requestType, + Consumer> + sendRequest) { + // prepare request context + Map nodeLocationMap = + nodeLocations.stream().collect(Collectors.toMap(getId, location -> location)); + AsyncRequestContext requestContext = + new AsyncRequestContext<>(requestType, new Object(), nodeLocationMap); + // do the test + sendRequest.accept(requestContext); + // collect result + Map anotherNodeLocationMap = + nodeLocations.stream().collect(Collectors.toMap(getId, location -> location)); + List results = new ArrayList<>(); + requestContext + .getResponseMap() + .forEach( + (nodeId, status) -> { + TEndPoint endPoint = getEndPoint.apply(anotherNodeLocationMap.get(nodeId)); + TServiceProvider serviceProvider = new TServiceProvider(endPoint, serviceType); + TTestConnectionResult result = new TTestConnectionResult(); + result.setSender(sender); + result.setServiceProvider(serviceProvider); + if (status.getCode() == TSStatusCode.SUCCESS_STATUS.getStatusCode()) { + result.setSuccess(true); + } else { + result.setSuccess(false); + result.setReason(status.getMessage()); + } + results.add(result); + }); + return results; + } +} diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/concurrent/threadpool/WrappedThreadPoolExecutor.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/concurrent/threadpool/WrappedThreadPoolExecutor.java index f35eba3e7bbe2..2c24f045ca533 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/concurrent/threadpool/WrappedThreadPoolExecutor.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/concurrent/threadpool/WrappedThreadPoolExecutor.java @@ -41,6 +41,7 @@ public class WrappedThreadPoolExecutor extends ThreadPoolExecutor implements WrappedThreadPoolExecutorMBean { private static final Logger logger = LoggerFactory.getLogger(WrappedThreadPoolExecutor.class); private final String mbeanName; + private volatile boolean disableErrorLog = false; public WrappedThreadPoolExecutor( int corePoolSize, @@ -125,8 +126,12 @@ protected void afterExecute(Runnable r, Throwable t) { Thread.currentThread().interrupt(); } } - if (t != null) { + if (t != null && !disableErrorLog) { logger.error("Exception in thread pool {}", mbeanName, t); } } + + public void disableErrorLog() { + disableErrorLog = true; + } } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonConfig.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonConfig.java index 1de7f33df3a83..6c2157a70c2db 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonConfig.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonConfig.java @@ -22,6 +22,7 @@ import org.apache.iotdb.commons.client.property.ClientPoolProperty.DefaultProperty; import org.apache.iotdb.commons.cluster.NodeStatus; import org.apache.iotdb.commons.enums.HandleSystemErrorStrategy; +import org.apache.iotdb.commons.enums.PipeRemainingTimeRateAverageTime; import org.apache.iotdb.commons.utils.FileUtils; import org.apache.iotdb.commons.utils.KillPoint.KillPoint; @@ -201,6 +202,7 @@ public class CommonConfig { private int pipeAsyncConnectorMaxClientNumber = 16; private double pipeAllSinksRateLimitBytesPerSecond = -1; + private int pipeEndPointRateLimiterDropCheckIntervalMs = 1000; private boolean isSeperatedPipeHeartbeatEnabled = true; private int pipeHeartbeatIntervalSecondsForCollectingPipeMeta = 100; @@ -235,7 +237,9 @@ public class CommonConfig { private float pipeLeaderCacheMemoryUsagePercentage = 0.1F; private long pipeListeningQueueTransferSnapshotThreshold = 1000; private int pipeSnapshotExecutionMaxBatchSize = 1000; - private double pipeRemainingTimeCommitRateSmoothingFactor = 0.5; + private long pipeRemainingTimeCommitRateAutoSwitchSeconds = 30; + private PipeRemainingTimeRateAverageTime pipeRemainingTimeCommitRateAverageTime = + PipeRemainingTimeRateAverageTime.MEAN; private long twoStageAggregateMaxCombinerLiveTimeInMs = 8 * 60 * 1000L; // 8 minutes private long twoStageAggregateDataRegionInfoCacheTimeInMs = 3 * 60 * 1000L; // 3 minutes @@ -1020,13 +1024,23 @@ public void setPipeSnapshotExecutionMaxBatchSize(int pipeSnapshotExecutionMaxBat this.pipeSnapshotExecutionMaxBatchSize = pipeSnapshotExecutionMaxBatchSize; } - public double getPipeRemainingTimeCommitRateSmoothingFactor() { - return pipeRemainingTimeCommitRateSmoothingFactor; + public long getPipeRemainingTimeCommitRateAutoSwitchSeconds() { + return pipeRemainingTimeCommitRateAutoSwitchSeconds; } - public void setPipeRemainingTimeCommitRateSmoothingFactor( - double pipeRemainingTimeCommitRateSmoothingFactor) { - this.pipeRemainingTimeCommitRateSmoothingFactor = pipeRemainingTimeCommitRateSmoothingFactor; + public void setPipeRemainingTimeCommitRateAutoSwitchSeconds( + long pipeRemainingTimeCommitRateAutoSwitchSeconds) { + this.pipeRemainingTimeCommitRateAutoSwitchSeconds = + pipeRemainingTimeCommitRateAutoSwitchSeconds; + } + + public PipeRemainingTimeRateAverageTime getPipeRemainingTimeCommitRateAverageTime() { + return pipeRemainingTimeCommitRateAverageTime; + } + + public void setPipeRemainingTimeCommitRateAverageTime( + PipeRemainingTimeRateAverageTime pipeRemainingTimeCommitRateAverageTime) { + this.pipeRemainingTimeCommitRateAverageTime = pipeRemainingTimeCommitRateAverageTime; } public double getPipeAllSinksRateLimitBytesPerSecond() { @@ -1037,6 +1051,15 @@ public void setPipeAllSinksRateLimitBytesPerSecond(double pipeAllSinksRateLimitB this.pipeAllSinksRateLimitBytesPerSecond = pipeAllSinksRateLimitBytesPerSecond; } + public int getPipeEndPointRateLimiterDropCheckIntervalMs() { + return pipeEndPointRateLimiterDropCheckIntervalMs; + } + + public void setPipeEndPointRateLimiterDropCheckIntervalMs( + int pipeEndPointRateLimiterDropCheckIntervalMs) { + this.pipeEndPointRateLimiterDropCheckIntervalMs = pipeEndPointRateLimiterDropCheckIntervalMs; + } + public long getTwoStageAggregateMaxCombinerLiveTimeInMs() { return twoStageAggregateMaxCombinerLiveTimeInMs; } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonDescriptor.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonDescriptor.java index f72ea5e528d15..b989e8e505552 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonDescriptor.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonDescriptor.java @@ -20,6 +20,7 @@ package org.apache.iotdb.commons.conf; import org.apache.iotdb.commons.enums.HandleSystemErrorStrategy; +import org.apache.iotdb.commons.enums.PipeRemainingTimeRateAverageTime; import org.apache.iotdb.commons.utils.CommonDateTimeUtils; import org.apache.iotdb.confignode.rpc.thrift.TGlobalConfig; @@ -391,6 +392,11 @@ private void loadPipeProps(Properties properties) { properties.getProperty( "pipe_all_sinks_rate_limit_bytes_per_second", String.valueOf(config.getPipeAllSinksRateLimitBytesPerSecond())))); + config.setPipeEndPointRateLimiterDropCheckIntervalMs( + Integer.parseInt( + properties.getProperty( + "pipe_end_point_rate_limiter_drop_check_interval_ms", + String.valueOf(config.getPipeEndPointRateLimiterDropCheckIntervalMs())))); config.setSeperatedPipeHeartbeatEnabled( Boolean.parseBoolean( @@ -541,11 +547,18 @@ private void loadPipeProps(Properties properties) { properties.getProperty( "pipe_snapshot_execution_max_batch_size", String.valueOf(config.getPipeSnapshotExecutionMaxBatchSize())))); - config.setPipeRemainingTimeCommitRateSmoothingFactor( - Double.parseDouble( + config.setPipeRemainingTimeCommitRateAutoSwitchSeconds( + Long.parseLong( properties.getProperty( - "pipe_remaining_time_commit_rate_smoothing_factor", - String.valueOf(config.getPipeRemainingTimeCommitRateSmoothingFactor())))); + "pipe_remaining_time_commit_rate_auto_switch_seconds", + String.valueOf(config.getPipeRemainingTimeCommitRateAutoSwitchSeconds())))); + config.setPipeRemainingTimeCommitRateAverageTime( + PipeRemainingTimeRateAverageTime.valueOf( + properties + .getProperty( + "pipe_remaining_time_commit_rate_average_time", + String.valueOf(config.getPipeRemainingTimeCommitRateAverageTime())) + .trim())); config.setTwoStageAggregateMaxCombinerLiveTimeInMs( Long.parseLong( diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/ConfigurationFileUtils.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/ConfigurationFileUtils.java index 0bd422d462021..d4c50a92abf8e 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/ConfigurationFileUtils.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/ConfigurationFileUtils.java @@ -23,6 +23,7 @@ import org.slf4j.LoggerFactory; import java.io.BufferedReader; +import java.io.BufferedWriter; import java.io.File; import java.io.FileReader; import java.io.FileWriter; @@ -35,11 +36,13 @@ import java.nio.file.StandardCopyOption; import java.util.ArrayList; import java.util.Arrays; +import java.util.Date; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Properties; import java.util.Set; +import java.util.StringJoiner; import java.util.concurrent.TimeUnit; public class ConfigurationFileUtils { @@ -48,24 +51,27 @@ public class ConfigurationFileUtils { private static final long maxTimeMillsToAcquireLock = TimeUnit.SECONDS.toMillis(20); private static final long waitTimeMillsPerCheck = TimeUnit.MILLISECONDS.toMillis(100); private static Logger logger = LoggerFactory.getLogger(ConfigurationFileUtils.class); - private static String license = - "#\n" - + "# Licensed to the Apache Software Foundation (ASF) under one\n" - + "# or more contributor license agreements. See the NOTICE file\n" - + "# distributed with this work for additional information\n" - + "# regarding copyright ownership. The ASF licenses this file\n" - + "# to you under the Apache License, Version 2.0 (the\n" - + "# \"License\"); you may not use this file except in compliance\n" - + "# with the License. You may obtain a copy of the License at\n" - + "#\n" - + "# http://www.apache.org/licenses/LICENSE-2.0\n" - + "#\n" - + "# Unless required by applicable law or agreed to in writing,\n" - + "# software distributed under the License is distributed on an\n" - + "# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY\n" - + "# KIND, either express or implied. See the License for the\n" - + "# specific language governing permissions and limitations\n" - + "# under the License."; + private static final String lineSeparator = "\n"; + private static final String license = + new StringJoiner(lineSeparator) + .add("# Licensed to the Apache Software Foundation (ASF) under one") + .add("# or more contributor license agreements. See the NOTICE file") + .add("# distributed with this work for additional information") + .add("# regarding copyright ownership. The ASF licenses this file") + .add("# to you under the Apache License, Version 2.0 (the") + .add("# \"License\"); you may not use this file except in compliance") + .add("# with the License. You may obtain a copy of the License at") + .add("#") + .add("# http://www.apache.org/licenses/LICENSE-2.0") + .add("#") + .add("# Unless required by applicable law or agreed to in writing,") + .add("# software distributed under the License is distributed on an") + .add("# \"AS IS\" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY") + .add("# KIND, either express or implied. See the License for the") + .add("# specific language governing permissions and limitations") + .add("# under the License.") + .toString(); + ; // This is a temporary implementations private static final Set ignoreConfigKeys = @@ -82,6 +88,7 @@ public class ConfigurationFileUtils { "dn_data_region_consensus_port", "dn_seed_config_node", "dn_session_timeout_threshold", + "cluster_name", "config_node_consensus_protocol_class", "schema_replication_factor", "data_replication_factor", @@ -94,7 +101,8 @@ public class ConfigurationFileUtils { "tag_attribute_total_size", "timestamp_precision", "iotdb_server_encrypt_decrypt_provider", - "iotdb_server_encrypt_decrypt_provider_parameter")); + "iotdb_server_encrypt_decrypt_provider_parameter", + "pipe_lib_dir")); public static void checkAndMayUpdate( URL systemUrl, URL configNodeUrl, URL dataNodeUrl, URL commonUrl) @@ -158,7 +166,7 @@ public static String readConfigurationTemplateFile() throws IOException { BufferedReader reader = new BufferedReader(isr)) { String line; while ((line = reader.readLine()) != null) { - content.append(line).append(System.lineSeparator()); + content.append(line).append(lineSeparator); } } catch (IOException e) { logger.warn("Failed to read configuration template", e); @@ -192,7 +200,7 @@ public static void updateConfigurationFile(File file, Properties newConfigItems) StringBuilder contentsOfNewConfigurationFile = new StringBuilder(); for (String currentLine : lines) { if (currentLine.trim().isEmpty() || currentLine.trim().startsWith("#")) { - contentsOfNewConfigurationFile.append(currentLine).append(System.lineSeparator()); + contentsOfNewConfigurationFile.append(currentLine).append(lineSeparator); continue; } int equalsIndex = currentLine.indexOf('='); @@ -201,17 +209,14 @@ public static void updateConfigurationFile(File file, Properties newConfigItems) String key = currentLine.substring(0, equalsIndex).trim(); String value = currentLine.substring(equalsIndex + 1).trim(); if (!newConfigItems.containsKey(key)) { - contentsOfNewConfigurationFile.append(currentLine).append(System.lineSeparator()); + contentsOfNewConfigurationFile.append(currentLine).append(lineSeparator); continue; } if (newConfigItems.getProperty(key).equals(value)) { - contentsOfNewConfigurationFile.append(currentLine).append(System.lineSeparator()); + contentsOfNewConfigurationFile.append(currentLine).append(lineSeparator); newConfigItems.remove(key); } else { - contentsOfNewConfigurationFile - .append("#") - .append(currentLine) - .append(System.lineSeparator()); + contentsOfNewConfigurationFile.append("#").append(currentLine).append(lineSeparator); } } } @@ -223,10 +228,13 @@ public static void updateConfigurationFile(File file, Properties newConfigItems) acquireTargetFileLock(lockFile); logger.info("Updating configuration file {}", file.getAbsolutePath()); try { - try (FileWriter writer = new FileWriter(lockFile)) { + try (BufferedWriter writer = new BufferedWriter(new FileWriter(lockFile))) { writer.write(contentsOfNewConfigurationFile.toString()); - // add new config items - newConfigItems.store(writer, null); + // Properties.store is not used as Properties.store may generate '\' automatically + writer.write("#" + new Date().toString() + lineSeparator); + for (String key : newConfigItems.stringPropertyNames()) { + writer.write(key + "=" + newConfigItems.get(key) + lineSeparator); + } writer.flush(); } Files.move(lockFile.toPath(), file.toPath(), StandardCopyOption.REPLACE_EXISTING); diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/enums/PipeRemainingTimeRateAverageTime.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/enums/PipeRemainingTimeRateAverageTime.java new file mode 100644 index 0000000000000..25f799d09f691 --- /dev/null +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/enums/PipeRemainingTimeRateAverageTime.java @@ -0,0 +1,49 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.commons.enums; + +import org.apache.iotdb.commons.pipe.config.PipeConfig; + +import com.codahale.metrics.Meter; + +public enum PipeRemainingTimeRateAverageTime { + ONE_MINUTE, + FIVE_MINUTES, + FIFTEEN_MINUTES, + MEAN; + + public double getMeterRate(final Meter meter) { + switch (this) { + case ONE_MINUTE: + return meter.getOneMinuteRate(); + case FIVE_MINUTES: + return meter.getFiveMinuteRate(); + case FIFTEEN_MINUTES: + return meter.getFifteenMinuteRate(); + case MEAN: + return meter.getMeanRate(); + default: + throw new UnsupportedOperationException( + String.format( + "The type %s is not supported in average time of pipe remaining time.", + PipeConfig.getInstance().getPipeRemainingTimeCommitRateAverageTime())); + } + } +} diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/file/SystemFileFactory.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/file/SystemFileFactory.java index fe7973bff960a..f9d2a3bb56770 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/file/SystemFileFactory.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/file/SystemFileFactory.java @@ -38,7 +38,6 @@ public enum SystemFileFactory { public File getFile(String pathname) { if (fsType.equals(FSType.HDFS)) { throw new UnsupportedOperationException(UNSUPPORTED_FILE_SYSTEM + fsType.name()); - // return new HDFSFile(pathname); } else { return new File(pathname); } @@ -47,7 +46,6 @@ public File getFile(String pathname) { public File getFile(String parent, String child) { if (fsType.equals(FSType.HDFS)) { throw new UnsupportedOperationException(UNSUPPORTED_FILE_SYSTEM + fsType.name()); - // return new HDFSFile(parent, child); } else { return new File(parent, child); } @@ -56,7 +54,6 @@ public File getFile(String parent, String child) { public File getFile(File parent, String child) { if (fsType.equals(FSType.HDFS)) { throw new UnsupportedOperationException(UNSUPPORTED_FILE_SYSTEM + fsType.name()); - // return new HDFSFile(parent, child); } else { return new File(parent, child); } @@ -65,7 +62,6 @@ public File getFile(File parent, String child) { public File getFile(URI uri) { if (fsType.equals(FSType.HDFS)) { throw new UnsupportedOperationException(UNSUPPORTED_FILE_SYSTEM + fsType.name()); - // return new HDFSFile(uri); } else { return new File(uri); } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/file/SystemPropertiesHandler.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/file/SystemPropertiesHandler.java new file mode 100644 index 0000000000000..39de4da3a3565 --- /dev/null +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/file/SystemPropertiesHandler.java @@ -0,0 +1,180 @@ +/* + * 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.iotdb.commons.file; + +import org.apache.ratis.util.AutoCloseableLock; +import org.apache.ratis.util.FileUtils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.io.Reader; +import java.io.Writer; +import java.nio.charset.StandardCharsets; +import java.util.Arrays; +import java.util.Properties; +import java.util.concurrent.locks.ReadWriteLock; +import java.util.concurrent.locks.ReentrantReadWriteLock; + +public abstract class SystemPropertiesHandler { + private static final Logger LOGGER = LoggerFactory.getLogger(SystemPropertiesHandler.class); + + private File formalFile; + private File tmpFile; + ReadWriteLock lock = new ReentrantReadWriteLock(); + + public SystemPropertiesHandler(String filePath) { + this.formalFile = SystemFileFactory.INSTANCE.getFile(filePath); + this.tmpFile = SystemFileFactory.INSTANCE.getFile(filePath + ".tmp"); + } + + /** + * Put key and value into properties + * + * @param keyOrValue [key0, value0, key1, value1, ... ] + */ + public void put(Object... keyOrValue) throws IOException { + if (keyOrValue.length % 2 != 0) { + throw new IllegalArgumentException( + "Length of parameters should be evenly divided by 2, but the actual length is " + + keyOrValue.length + + " : " + + Arrays.toString(keyOrValue)); + } + try (AutoCloseableLock ignore = AutoCloseableLock.acquire(lock.writeLock())) { + // read old properties + Properties properties = readWithoutLock(formalFile); + // store new properties + for (int i = 0; i < keyOrValue.length; i += 2) { + properties.put(keyOrValue[i], keyOrValue[i + 1]); + } + writeWithoutLock(properties, tmpFile); + // replace file + replaceFormalFile(); + } + } + + public void overwrite(Properties properties) throws IOException { + try (AutoCloseableLock ignore = AutoCloseableLock.acquire(lock.writeLock())) { + if (!formalFile.exists()) { + writeWithoutLock(properties, formalFile); + return; + } + writeWithoutLock(properties, tmpFile); + replaceFormalFile(); + } + } + + public Properties read() throws IOException { + try (AutoCloseableLock ignore = AutoCloseableLock.acquire(lock.readLock())) { + return readWithoutLock(formalFile); + } + } + + private void writeWithoutLock(Properties properties, File file) throws IOException { + try (FileOutputStream fileOutputStream = new FileOutputStream(file); + Writer writer = new OutputStreamWriter(fileOutputStream, StandardCharsets.UTF_8)) { + properties.store(writer, ""); + fileOutputStream.getFD().sync(); + } + } + + private Properties readWithoutLock(File file) throws IOException { + Properties properties = new Properties(); + if (file.exists()) { + try (FileInputStream inputStream = new FileInputStream(formalFile); + Reader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8)) { + properties.load(reader); + } + } + return properties; + } + + public boolean fileExist() { + try (AutoCloseableLock ignore = AutoCloseableLock.acquire(lock.readLock())) { + return formalFile.exists() || tmpFile.exists(); + } + } + + public boolean isFirstStart() { + return !fileExist(); + } + + protected void recover() { + try (AutoCloseableLock ignore = AutoCloseableLock.acquire(lock.writeLock())) { + if (formalFile.exists() && !tmpFile.exists()) { + // No need to recover + return; + } + if (!formalFile.exists() && !tmpFile.exists()) { + // First start + return; + } + if (formalFile.exists() && tmpFile.exists()) { + if (!tmpFile.delete()) { + LOGGER.warn( + "Delete system.properties tmp file fail, you may manually delete it: {}", + tmpFile.getAbsoluteFile()); + } + return; + } + if (!formalFile.exists() && tmpFile.exists()) { + replaceFormalFile(); + return; + } + } catch (IOException e) { + throw new RuntimeException(e); + } + throw new UnsupportedOperationException("Should never touch here"); + } + + private void replaceFormalFile() throws IOException { + if (!tmpFile.exists()) { + throw new FileNotFoundException( + "Tmp system properties file must exist when call replaceFormalFile"); + } + if (formalFile.exists() && !formalFile.delete()) { + String msg = + String.format( + "Delete formal system properties file fail: %s", formalFile.getAbsoluteFile()); + throw new IOException(msg); + } + try { + FileUtils.move(tmpFile.toPath(), formalFile.toPath()); + } catch (IOException e) { + String msg = + String.format( + "Failed to replace formal system properties file, you may manually rename it: %s -> %s", + tmpFile.getAbsolutePath(), formalFile.getAbsolutePath()); + throw new IOException(msg, e); + } + } + + public void resetFilePath(String filePath) { + this.formalFile = SystemFileFactory.INSTANCE.getFile(filePath); + this.tmpFile = SystemFileFactory.INSTANCE.getFile(filePath + ".tmp"); + } +} diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/path/PartialPath.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/path/PartialPath.java index d5ba3c159bd0b..d68d4bb7c886a 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/path/PartialPath.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/path/PartialPath.java @@ -335,6 +335,19 @@ public boolean matchFullPath(IDeviceID deviceID, String measurement) { return matchPath(devicePath.concatNode(measurement).getNodes(), 0, 0, false, false); } + /** + * Test if current PartialPath matches a full path. Current partialPath acts as a full path + * pattern. rPath is supposed to be a full timeseries path without wildcards. e.g. + * "root.sg.device.*" matches path "root.sg.device.s1" whereas it does not match "root.sg.device" + * and "root.sg.vehicle.s1" + * + * @param rPath a plain full path of a timeseries + * @return true if a successful match, otherwise return false + */ + public boolean matchFullPath(String[] rPath) { + return matchPath(rPath, 0, 0, false, false); + } + /** * Check if current pattern PartialPath can match 1 prefix path. * diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/path/PathPatternTreeUtils.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/path/PathPatternTreeUtils.java index 2fa1b16f2663b..ac124fe67ccf9 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/path/PathPatternTreeUtils.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/path/PathPatternTreeUtils.java @@ -22,6 +22,11 @@ import org.apache.iotdb.commons.schema.SchemaConstant; public class PathPatternTreeUtils { + + private PathPatternTreeUtils() { + // hidden constructor + } + /** * Intersect the pattern tree with the full path prefix tree, and return the intersected pattern * tree. diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/agent/task/PipeTaskAgent.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/agent/task/PipeTaskAgent.java index a1844bef5722e..67a224694f2c8 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/agent/task/PipeTaskAgent.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/agent/task/PipeTaskAgent.java @@ -23,6 +23,7 @@ import org.apache.iotdb.commons.exception.pipe.PipeRuntimeConnectorCriticalException; import org.apache.iotdb.commons.exception.pipe.PipeRuntimeCriticalException; import org.apache.iotdb.commons.exception.pipe.PipeRuntimeException; +import org.apache.iotdb.commons.pipe.connector.limiter.PipeEndPointRateLimiter; import org.apache.iotdb.commons.pipe.task.PipeTask; import org.apache.iotdb.commons.pipe.task.PipeTaskManager; import org.apache.iotdb.commons.pipe.task.meta.PipeMeta; @@ -77,6 +78,9 @@ public abstract class PipeTaskAgent { protected PipeTaskAgent() { pipeMetaKeeper = new PipeMetaKeeper(); pipeTaskManager = new PipeTaskManager(); + + // Help PipeEndPointRateLimiter to check if the pipe is still alive + PipeEndPointRateLimiter.setTaskAgent(this); } ////////////////////////// PipeMeta Lock Control ////////////////////////// @@ -103,7 +107,7 @@ protected void acquireWriteLock() { pipeMetaKeeper.acquireWriteLock(); } - protected boolean tryWriteLockWithTimeOut(long timeOutInSeconds) { + protected boolean tryWriteLockWithTimeOut(final long timeOutInSeconds) { try { return pipeMetaKeeper.tryWriteLock(timeOutInSeconds); } catch (final InterruptedException e) { @@ -272,6 +276,9 @@ private void executeSinglePipeRuntimeMetaChanges( break; case STOPPED: if (Objects.requireNonNull(statusInAgent) == PipeStatus.RUNNING) { + // Only freeze rate for user stopped pipes + // Freeze first to get better results in calculation + freezeRate(pipeStaticMeta.getPipeName(), pipeStaticMeta.getCreationTime()); stopPipe(pipeStaticMeta.getPipeName(), pipeStaticMeta.getCreationTime()); } else { throw new IllegalStateException( @@ -290,6 +297,10 @@ private void executeSinglePipeRuntimeMetaChanges( } } + protected abstract void thawRate(final String pipeName, final long creationTime); + + protected abstract void freezeRate(final String pipeName, final long creationTime); + public TPushPipeMetaRespExceptionMessage handleDropPipe(final String pipeName) { acquireWriteLock(); try { @@ -462,11 +473,14 @@ private boolean createPipe(final PipeMeta pipeMetaFromCoordinator) throws Illega protected abstract Map buildPipeTasks(final PipeMeta pipeMetaFromCoordinator) throws IllegalPathException; - protected void dropPipe(final String pipeName, final long creationTime) { + /** + * @return {@code true} if a pipe has indeed been dropped, otherwise {@code false}. + */ + protected boolean dropPipe(final String pipeName, final long creationTime) { final PipeMeta existedPipeMeta = pipeMetaKeeper.getPipeMeta(pipeName); if (!checkBeforeDropPipe(existedPipeMeta, pipeName, creationTime)) { - return; + return false; } // Mark pipe meta as dropped first. This will help us detect if the pipe meta has been dropped @@ -483,7 +497,7 @@ protected void dropPipe(final String pipeName, final long creationTime) { + "Skip dropping.", pipeName, creationTime); - return; + return false; } // Trigger drop() method for each pipe task by parallel stream @@ -496,13 +510,18 @@ protected void dropPipe(final String pipeName, final long creationTime) { // Remove pipe meta from pipe meta keeper pipeMetaKeeper.removePipeMeta(pipeName); + + return true; } - protected void dropPipe(final String pipeName) { + /** + * @return {@code true} if a pipe has indeed been dropped, otherwise {@code false}. + */ + protected boolean dropPipe(final String pipeName) { final PipeMeta existedPipeMeta = pipeMetaKeeper.getPipeMeta(pipeName); if (!checkBeforeDropPipe(existedPipeMeta, pipeName)) { - return; + return false; } // Mark pipe meta as dropped first. This will help us detect if the pipe meta has been dropped @@ -516,7 +535,7 @@ protected void dropPipe(final String pipeName) { if (pipeTasks == null) { LOGGER.info( "Pipe {} has already been dropped or has not been created. Skip dropping.", pipeName); - return; + return false; } // Trigger drop() method for each pipe task by parallel stream @@ -529,6 +548,8 @@ protected void dropPipe(final String pipeName) { // Remove pipe meta from pipe meta keeper pipeMetaKeeper.removePipeMeta(pipeName); + + return true; } private void startPipe(final String pipeName, final long creationTime) { @@ -566,9 +587,11 @@ private void startPipe(final String pipeName, final long creationTime) { .getConsensusGroupId2TaskMetaMap() .values() .forEach(PipeTaskMeta::clearExceptionMessages); + + thawRate(pipeName, creationTime); } - protected void stopPipe(final String pipeName, final long creationTime) { + private void stopPipe(final String pipeName, final long creationTime) { final PipeMeta existedPipeMeta = pipeMetaKeeper.getPipeMeta(pipeName); if (!checkBeforeStopPipe(existedPipeMeta, pipeName, creationTime)) { @@ -846,6 +869,7 @@ private void startPipeTask(final int consensusGroupId, final PipeStaticMeta pipe final PipeTask pipeTask = pipeTaskManager.getPipeTask(pipeStaticMeta, consensusGroupId); if (pipeTask != null) { pipeTask.start(); + thawRate(pipeStaticMeta.getPipeName(), pipeStaticMeta.getCreationTime()); } } @@ -997,4 +1021,9 @@ public void collectPipeMetaList(final TPipeHeartbeatReq req, final TPipeHeartbea protected abstract void collectPipeMetaListInternal( final TPipeHeartbeatReq req, final TPipeHeartbeatResp resp) throws TException; + + public long getPipeCreationTime(final String pipeName) { + final PipeMeta pipeMeta = pipeMetaKeeper.getPipeMeta(pipeName); + return pipeMeta == null ? 0 : pipeMeta.getStaticMeta().getCreationTime(); + } } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/config/PipeConfig.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/config/PipeConfig.java index 48debcce40816..818ef38dd84e3 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/config/PipeConfig.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/config/PipeConfig.java @@ -21,6 +21,7 @@ import org.apache.iotdb.commons.conf.CommonConfig; import org.apache.iotdb.commons.conf.CommonDescriptor; +import org.apache.iotdb.commons.enums.PipeRemainingTimeRateAverageTime; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -127,6 +128,10 @@ public double getPipeAllConnectorsRateLimitBytesPerSecond() { return COMMON_CONFIG.getPipeAllSinksRateLimitBytesPerSecond(); } + public int getPipeEndPointRateLimiterDropCheckIntervalMs() { + return COMMON_CONFIG.getPipeEndPointRateLimiterDropCheckIntervalMs(); + } + public float getPipeLeaderCacheMemoryUsagePercentage() { return COMMON_CONFIG.getPipeLeaderCacheMemoryUsagePercentage(); } @@ -139,8 +144,12 @@ public int getPipeSnapshotExecutionMaxBatchSize() { return COMMON_CONFIG.getPipeSnapshotExecutionMaxBatchSize(); } - public double getPipeRemainingTimeCommitRateSmoothingFactor() { - return COMMON_CONFIG.getPipeRemainingTimeCommitRateSmoothingFactor(); + public long getPipeRemainingTimeCommitAutoSwitchSeconds() { + return COMMON_CONFIG.getPipeRemainingTimeCommitRateAutoSwitchSeconds(); + } + + public PipeRemainingTimeRateAverageTime getPipeRemainingTimeCommitRateAverageTime() { + return COMMON_CONFIG.getPipeRemainingTimeCommitRateAverageTime(); } /////////////////////////////// Meta Consistency /////////////////////////////// @@ -328,8 +337,10 @@ public void printAllConfigs() { getPipeListeningQueueTransferSnapshotThreshold()); LOGGER.info("PipeSnapshotExecutionMaxBatchSize: {}", getPipeSnapshotExecutionMaxBatchSize()); LOGGER.info( - "PipeRemainingTimeCommitRateSmoothingFactor: {}", - getPipeRemainingTimeCommitRateSmoothingFactor()); + "PipeRemainingTimeCommitAutoSwitchSeconds: {}", + getPipeRemainingTimeCommitAutoSwitchSeconds()); + LOGGER.info( + "PipeRemainingTimeCommitRateAverageTime: {}", getPipeRemainingTimeCommitRateAverageTime()); LOGGER.info("PipeAsyncConnectorSelectorNumber: {}", getPipeAsyncConnectorSelectorNumber()); LOGGER.info("PipeAsyncConnectorMaxClientNumber: {}", getPipeAsyncConnectorMaxClientNumber()); @@ -337,6 +348,9 @@ public void printAllConfigs() { LOGGER.info( "PipeAllConnectorsRateLimitBytesPerSecond: {}", getPipeAllConnectorsRateLimitBytesPerSecond()); + LOGGER.info( + "PipeEndPointRateLimiterDropCheckIntervalMs: {}", + getPipeEndPointRateLimiterDropCheckIntervalMs()); LOGGER.info("SeperatedPipeHeartbeatEnabled: {}", isSeperatedPipeHeartbeatEnabled()); LOGGER.info( diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/config/constant/PipeConnectorConstant.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/config/constant/PipeConnectorConstant.java index 8d6879ae8c23b..dfcf35c03cabe 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/config/constant/PipeConnectorConstant.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/config/constant/PipeConnectorConstant.java @@ -195,6 +195,7 @@ public class PipeConnectorConstant { public static final String SINK_CONSUMER_GROUP_KEY = "sink.consumer-group"; public static final String CONNECTOR_CONSENSUS_GROUP_ID_KEY = "connector.consensus.group-id"; + public static final String CONNECTOR_CONSENSUS_PIPE_NAME = "connector.consensus.pipe-name"; private PipeConnectorConstant() { throw new IllegalStateException("Utility class"); diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/config/constant/PipeExtractorConstant.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/config/constant/PipeExtractorConstant.java index a67b594d361da..1bf147e998b15 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/config/constant/PipeExtractorConstant.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/config/constant/PipeExtractorConstant.java @@ -64,6 +64,9 @@ public class PipeExtractorConstant { public static final String SOURCE_HISTORY_END_TIME_KEY = "source.history.end-time"; public static final String EXTRACTOR_HISTORY_LOOSE_RANGE_KEY = "extractor.history.loose-range"; public static final String SOURCE_HISTORY_LOOSE_RANGE_KEY = "source.history.loose-range"; + public static final String EXTRACTOR_HISTORY_LOOSE_RANGE_TIME_VALUE = "time"; + public static final String EXTRACTOR_HISTORY_LOOSE_RANGE_PATH_VALUE = "path"; + public static final String EXTRACTOR_HISTORY_LOOSE_RANGE_DEFAULT_VALUE = ""; public static final String EXTRACTOR_MODS_ENABLE_KEY = "extractor.mods.enable"; public static final String SOURCE_MODS_ENABLE_KEY = "source.mods.enable"; public static final boolean EXTRACTOR_MODS_ENABLE_DEFAULT_VALUE = false; @@ -81,6 +84,9 @@ public class PipeExtractorConstant { public static final String EXTRACTOR_REALTIME_MODE_BATCH_MODE_VALUE = "batch"; public static final String EXTRACTOR_REALTIME_LOOSE_RANGE_KEY = "extractor.realtime.loose-range"; public static final String SOURCE_REALTIME_LOOSE_RANGE_KEY = "source.realtime.loose-range"; + public static final String EXTRACTOR_REALTIME_LOOSE_RANGE_TIME_VALUE = "time"; + public static final String EXTRACTOR_REALTIME_LOOSE_RANGE_PATH_VALUE = "path"; + public static final String EXTRACTOR_REALTIME_LOOSE_RANGE_DEFAULT_VALUE = ""; public static final String EXTRACTOR_START_TIME_KEY = "extractor.start-time"; public static final String SOURCE_START_TIME_KEY = "source.start-time"; diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/compressor/PipeCompressor.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/compressor/PipeCompressor.java index 4d5113e4c20e0..a7f8405f7015a 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/compressor/PipeCompressor.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/compressor/PipeCompressor.java @@ -49,8 +49,27 @@ protected PipeCompressor(PipeCompressionType compressionType) { public abstract byte[] compress(byte[] data) throws IOException; + /** + * Decompress the byte array to a byte array. NOTE: the length of the decompressed byte array is + * not provided in this method, and some decompressors (LZ4) may construct large byte arrays, + * leading to potential OOM. + * + * @param byteArray the byte array to be decompressed + * @return the decompressed byte array + * @throws IOException + */ public abstract byte[] decompress(byte[] byteArray) throws IOException; + /** + * Decompress the byte array to a byte array with a known length. + * + * @param byteArray the byte array to be decompressed + * @param decompressedLength the length of the decompressed byte array + * @return the decompressed byte array + * @throws IOException + */ + public abstract byte[] decompress(byte[] byteArray, int decompressedLength) throws IOException; + public byte serialize() { return compressionType.getIndex(); } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/compressor/PipeGZIPCompressor.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/compressor/PipeGZIPCompressor.java index 2cc1887555cd7..568122d7035b5 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/compressor/PipeGZIPCompressor.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/compressor/PipeGZIPCompressor.java @@ -44,4 +44,11 @@ public byte[] compress(byte[] data) throws IOException { public byte[] decompress(byte[] byteArray) throws IOException { return DECOMPRESSOR.uncompress(byteArray); } + + @Override + public byte[] decompress(byte[] byteArray, int decompressedLength) throws IOException { + byte[] uncompressed = new byte[decompressedLength]; + DECOMPRESSOR.uncompress(byteArray, 0, byteArray.length, uncompressed, 0); + return uncompressed; + } } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/compressor/PipeLZ4Compressor.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/compressor/PipeLZ4Compressor.java index 5d6db90e66100..52a2412a30f39 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/compressor/PipeLZ4Compressor.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/compressor/PipeLZ4Compressor.java @@ -44,4 +44,11 @@ public byte[] compress(byte[] data) throws IOException { public byte[] decompress(byte[] byteArray) throws IOException { return DECOMPRESSOR.uncompress(byteArray); } + + @Override + public byte[] decompress(byte[] byteArray, int decompressedLength) throws IOException { + byte[] uncompressed = new byte[decompressedLength]; + DECOMPRESSOR.uncompress(byteArray, 0, byteArray.length, uncompressed, 0); + return uncompressed; + } } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/compressor/PipeLZMA2Compressor.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/compressor/PipeLZMA2Compressor.java index 9e7c0a8b8d372..eebb703f9bed4 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/compressor/PipeLZMA2Compressor.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/compressor/PipeLZMA2Compressor.java @@ -44,4 +44,11 @@ public byte[] compress(byte[] data) throws IOException { public byte[] decompress(byte[] byteArray) throws IOException { return DECOMPRESSOR.uncompress(byteArray); } + + @Override + public byte[] decompress(byte[] byteArray, int decompressedLength) throws IOException { + byte[] uncompressed = new byte[decompressedLength]; + DECOMPRESSOR.uncompress(byteArray, 0, byteArray.length, uncompressed, 0); + return uncompressed; + } } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/compressor/PipeSnappyCompressor.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/compressor/PipeSnappyCompressor.java index 72333c1e929bd..284b29610a44a 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/compressor/PipeSnappyCompressor.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/compressor/PipeSnappyCompressor.java @@ -44,4 +44,11 @@ public byte[] compress(byte[] data) throws IOException { public byte[] decompress(byte[] byteArray) throws IOException { return DECOMPRESSOR.uncompress(byteArray); } + + @Override + public byte[] decompress(byte[] byteArray, int decompressedLength) throws IOException { + byte[] uncompressed = new byte[decompressedLength]; + DECOMPRESSOR.uncompress(byteArray, 0, byteArray.length, uncompressed, 0); + return uncompressed; + } } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/compressor/PipeZSTDCompressor.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/compressor/PipeZSTDCompressor.java index 50e2e1f845cf7..f5e4d6476e844 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/compressor/PipeZSTDCompressor.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/compressor/PipeZSTDCompressor.java @@ -41,4 +41,9 @@ public byte[] compress(byte[] data) throws IOException { public byte[] decompress(byte[] byteArray) { return Zstd.decompress(byteArray, (int) Zstd.decompressedSize(byteArray, 0, byteArray.length)); } + + @Override + public byte[] decompress(byte[] byteArray, int decompressedLength) { + return Zstd.decompress(byteArray, decompressedLength); + } } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/limiter/GlobalRateLimiter.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/limiter/GlobalRateLimiter.java index 575731d04a5ec..fbabb60fa8d36 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/limiter/GlobalRateLimiter.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/limiter/GlobalRateLimiter.java @@ -24,6 +24,8 @@ import com.google.common.util.concurrent.AtomicDouble; import com.google.common.util.concurrent.RateLimiter; +import java.util.concurrent.TimeUnit; + /** This is a global rate limiter for all connectors. */ public class GlobalRateLimiter { @@ -42,6 +44,33 @@ public GlobalRateLimiter() { } public void acquire(long bytes) { + if (reloadParams()) { + return; + } + + while (bytes > 0) { + if (bytes > Integer.MAX_VALUE) { + tryAcquireWithRateCheck(Integer.MAX_VALUE); + bytes -= Integer.MAX_VALUE; + } else { + tryAcquireWithRateCheck((int) bytes); + return; + } + } + } + + private void tryAcquireWithRateCheck(final int bytes) { + while (!rateLimiter.tryAcquire( + bytes, + PipeConfig.getInstance().getPipeEndPointRateLimiterDropCheckIntervalMs(), + TimeUnit.MILLISECONDS)) { + if (reloadParams()) { + return; + } + } + } + + private boolean reloadParams() { final double throughputBytesPerSecondLimit = CONFIG.getPipeAllConnectorsRateLimitBytesPerSecond(); @@ -53,18 +82,6 @@ public void acquire(long bytes) { } // For performance, we don't need to acquire rate limiter if throughput <= 0 - if (throughputBytesPerSecondLimit <= 0) { - return; - } - - while (bytes > 0) { - if (bytes > Integer.MAX_VALUE) { - rateLimiter.acquire(Integer.MAX_VALUE); - bytes -= Integer.MAX_VALUE; - } else { - rateLimiter.acquire((int) bytes); - return; - } - } + return throughputBytesPerSecondLimit <= 0; } } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/limiter/PipeEndPointRateLimiter.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/limiter/PipeEndPointRateLimiter.java index 8b15164457667..46f16a8eb11c1 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/limiter/PipeEndPointRateLimiter.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/limiter/PipeEndPointRateLimiter.java @@ -20,23 +20,40 @@ package org.apache.iotdb.commons.pipe.connector.limiter; import org.apache.iotdb.common.rpc.thrift.TEndPoint; +import org.apache.iotdb.commons.pipe.agent.task.PipeTaskAgent; +import org.apache.iotdb.commons.pipe.config.PipeConfig; import com.google.common.util.concurrent.RateLimiter; +import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ConcurrentMap; +import java.util.concurrent.TimeUnit; public class PipeEndPointRateLimiter { + // The task agent is used to check if the pipe is still alive + private static volatile PipeTaskAgent taskAgent; + + private final String pipeName; + private final long creationTime; + private final double bytesPerSecondLimit; private final ConcurrentMap endPointRateLimiterMap; - public PipeEndPointRateLimiter(double bytesPerSecondLimit) { + public PipeEndPointRateLimiter( + final String pipeName, final long creationTime, final double bytesPerSecondLimit) { + this.pipeName = pipeName; + this.creationTime = creationTime; this.bytesPerSecondLimit = bytesPerSecondLimit; endPointRateLimiterMap = new ConcurrentHashMap<>(); } + public static void setTaskAgent(final PipeTaskAgent taskAgent) { + PipeEndPointRateLimiter.taskAgent = taskAgent; + } + public void acquire(final TEndPoint endPoint, long bytes) { if (endPoint == null) { return; @@ -48,12 +65,28 @@ public void acquire(final TEndPoint endPoint, long bytes) { while (bytes > 0) { if (bytes > Integer.MAX_VALUE) { - rateLimiter.acquire(Integer.MAX_VALUE); + if (!tryAcquireWithPipeCheck(rateLimiter, Integer.MAX_VALUE)) { + return; + } bytes -= Integer.MAX_VALUE; } else { - rateLimiter.acquire((int) bytes); + tryAcquireWithPipeCheck(rateLimiter, (int) bytes); return; } } } + + private boolean tryAcquireWithPipeCheck(final RateLimiter rateLimiter, final int bytes) { + while (!rateLimiter.tryAcquire( + bytes, + PipeConfig.getInstance().getPipeEndPointRateLimiterDropCheckIntervalMs(), + TimeUnit.MILLISECONDS)) { + final PipeTaskAgent finalTaskAgent = taskAgent; + if (Objects.nonNull(finalTaskAgent) + && finalTaskAgent.getPipeCreationTime(pipeName) != creationTime) { + return false; + } + } + return true; + } } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/payload/thrift/request/PipeTransferCompressedReq.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/payload/thrift/request/PipeTransferCompressedReq.java index f5e114949bd75..b92b2d4256a93 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/payload/thrift/request/PipeTransferCompressedReq.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/payload/thrift/request/PipeTransferCompressedReq.java @@ -44,8 +44,10 @@ public static TPipeTransferReq toTPipeTransferReq( // version // type: TRANSFER_COMPRESSED // body: - // (byte) count of compressors - // (bytes) 1 byte for each compressor + // (byte) count of compressors (n) + // (n*3 bytes) for each compressor: + // (byte) compressor type + // (int) length of uncompressed bytes // compressed req: // (byte) version // (2 bytes) type @@ -56,18 +58,17 @@ public static TPipeTransferReq toTPipeTransferReq( try (final PublicBAOS byteArrayOutputStream = new PublicBAOS(); final DataOutputStream outputStream = new DataOutputStream(byteArrayOutputStream)) { - ReadWriteIOUtils.write((byte) compressors.size(), outputStream); - for (final PipeCompressor compressor : compressors) { - ReadWriteIOUtils.write(compressor.serialize(), outputStream); - } - byte[] body = BytesUtils.concatByteArrayList( Arrays.asList( new byte[] {originalReq.version}, BytesUtils.shortToBytes(originalReq.type), originalReq.getBody())); + + ReadWriteIOUtils.write((byte) compressors.size(), outputStream); for (final PipeCompressor compressor : compressors) { + ReadWriteIOUtils.write(compressor.serialize(), outputStream); + ReadWriteIOUtils.write(body.length, outputStream); body = compressor.compress(body); } outputStream.write(body); @@ -84,17 +85,19 @@ public static TPipeTransferReq fromTPipeTransferReq(final TPipeTransferReq trans final ByteBuffer compressedBuffer = transferReq.body; final List compressors = new ArrayList<>(); + final List uncompressedLengths = new ArrayList<>(); final int compressorsSize = ReadWriteIOUtils.readByte(compressedBuffer); for (int i = 0; i < compressorsSize; ++i) { compressors.add( PipeCompressorFactory.getCompressor(ReadWriteIOUtils.readByte(compressedBuffer))); + uncompressedLengths.add(ReadWriteIOUtils.readInt(compressedBuffer)); } byte[] body = new byte[compressedBuffer.remaining()]; compressedBuffer.get(body); for (int i = compressors.size() - 1; i >= 0; --i) { - body = compressors.get(i).decompress(body); + body = compressors.get(i).decompress(body, uncompressedLengths.get(i)); } final ByteBuffer decompressedBuffer = ByteBuffer.wrap(body); @@ -115,26 +118,27 @@ public static byte[] toTPipeTransferReqBytes( // The generated bytes consists of: // (byte) version // (2 bytes) type: TRANSFER_COMPRESSED - // (byte) count of compressors - // (bytes) 1 byte for each compressor + // (byte) count of compressors (n) + // (n*3 bytes) for each compressor: + // (byte) compressor type + // (int) length of uncompressed bytes // compressed req: // (byte) version // (2 bytes) type // (bytes) body try (final PublicBAOS byteArrayOutputStream = new PublicBAOS(); final DataOutputStream outputStream = new DataOutputStream(byteArrayOutputStream)) { + byte[] body = rawReqInBytes; + ReadWriteIOUtils.write(IoTDBConnectorRequestVersion.VERSION_1.getVersion(), outputStream); ReadWriteIOUtils.write(PipeRequestType.TRANSFER_COMPRESSED.getType(), outputStream); ReadWriteIOUtils.write((byte) compressors.size(), outputStream); for (final PipeCompressor compressor : compressors) { ReadWriteIOUtils.write(compressor.serialize(), outputStream); + ReadWriteIOUtils.write(body.length, outputStream); + body = compressor.compress(body); } - - byte[] compressedReq = rawReqInBytes; - for (final PipeCompressor compressor : compressors) { - compressedReq = compressor.compress(compressedReq); - } - outputStream.write(compressedReq); + outputStream.write(body); return byteArrayOutputStream.toByteArray(); } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/protocol/IoTDBAirGapConnector.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/protocol/IoTDBAirGapConnector.java index 7aac1ffc90df1..5d8e87fbd8784 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/protocol/IoTDBAirGapConnector.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/protocol/IoTDBAirGapConnector.java @@ -94,7 +94,8 @@ public String toString() { protected boolean supportModsIfIsDataNodeReceiver = true; @Override - public void customize(PipeParameters parameters, PipeConnectorRuntimeConfiguration configuration) + public void customize( + final PipeParameters parameters, final PipeConnectorRuntimeConfiguration configuration) throws Exception { super.customize(parameters, configuration); @@ -157,7 +158,7 @@ public void handshake() throws Exception { if (sockets.get(i) != null) { try { sockets.set(i, null).close(); - } catch (Exception e) { + } catch (final Exception e) { LOGGER.warn( "Failed to close socket with target server ip: {}, port: {}, because: {}. Ignore it.", ip, @@ -173,7 +174,7 @@ public void handshake() throws Exception { socket.setKeepAlive(true); sockets.set(i, socket); LOGGER.info("Successfully connected to target server ip: {}, port: {}.", ip, port); - } catch (Exception e) { + } catch (final Exception e) { LOGGER.warn( "Failed to connect to target server ip: {}, port: {}, because: {}. Ignore it.", ip, @@ -195,7 +196,7 @@ public void handshake() throws Exception { String.format("All target servers %s are not available.", nodeUrls)); } - protected void sendHandshakeReq(AirGapSocket socket) throws IOException { + protected void sendHandshakeReq(final AirGapSocket socket) throws IOException { socket.setSoTimeout(handshakeTimeoutMs); // Try to handshake by PipeTransferHandshakeV2Req. If failed, retry to handshake by // PipeTransferHandshakeV1Req. If failed again, throw PipeConnectionException. @@ -219,7 +220,7 @@ protected void sendHandshakeReq(AirGapSocket socket) throws IOException { public void heartbeat() { try { handshake(); - } catch (Exception e) { + } catch (final Exception e) { LOGGER.warn( "Failed to reconnect to target server, because: {}. Try to reconnect later.", e.getMessage(), @@ -228,7 +229,11 @@ public void heartbeat() { } protected void transferFilePieces( - String pipeName, File file, AirGapSocket socket, boolean isMultiFile) + final String pipeName, + final long creationTime, + final File file, + final AirGapSocket socket, + final boolean isMultiFile) throws PipeException, IOException { final int readFileBufferSize = PipeConfig.getInstance().getPipeConnectorReadFileBufferSize(); final byte[] readBuffer = new byte[readFileBufferSize]; @@ -246,6 +251,7 @@ protected void transferFilePieces( : Arrays.copyOfRange(readBuffer, 0, readLength); if (!send( pipeName, + creationTime, socket, isMultiFile ? getTransferMultiFilePieceBytes(file.getName(), position, payload) @@ -272,23 +278,25 @@ protected void transferFilePieces( protected abstract boolean mayNeedHandshakeWhenFail(); protected abstract byte[] getTransferSingleFilePieceBytes( - String fileName, long position, byte[] payLoad) throws IOException; + final String fileName, final long position, final byte[] payLoad) throws IOException; protected abstract byte[] getTransferMultiFilePieceBytes( - String fileName, long position, byte[] payLoad) throws IOException; + final String fileName, final long position, final byte[] payLoad) throws IOException; protected int nextSocketIndex() { return loadBalancer.nextSocketIndex(); } - protected boolean send(String pipeName, AirGapSocket socket, byte[] bytes) throws IOException { + protected boolean send( + final String pipeName, final long creationTime, final AirGapSocket socket, byte[] bytes) + throws IOException { if (!socket.isConnected()) { return false; } bytes = compressIfNeeded(bytes); - rateLimitIfNeeded(pipeName, socket.getEndPoint(), bytes.length); + rateLimitIfNeeded(pipeName, creationTime, socket.getEndPoint(), bytes.length); final BufferedOutputStream outputStream = new BufferedOutputStream(socket.getOutputStream()); bytes = enrichWithLengthAndChecksum(bytes); @@ -300,11 +308,11 @@ protected boolean send(String pipeName, AirGapSocket socket, byte[] bytes) throw return size > 0 && Arrays.equals(AirGapOneByteResponse.OK, response); } - protected boolean send(AirGapSocket socket, byte[] bytes) throws IOException { - return send(null, socket, bytes); + protected boolean send(final AirGapSocket socket, final byte[] bytes) throws IOException { + return send(null, 0, socket, bytes); } - private byte[] enrichWithLengthAndChecksum(byte[] bytes) { + private byte[] enrichWithLengthAndChecksum(final byte[] bytes) { // Length of checksum and bytes payload final byte[] length = BytesUtils.intToBytes(bytes.length + LONG_LEN); @@ -316,7 +324,7 @@ private byte[] enrichWithLengthAndChecksum(byte[] bytes) { Arrays.asList(length, length, BytesUtils.longToBytes(crc32.getValue()), bytes)); } - private byte[] enrichWithELanguage(byte[] bytes) { + private byte[] enrichWithELanguage(final byte[] bytes) { return BytesUtils.concatByteArrayList( Arrays.asList( AirGapELanguageConstant.E_LANGUAGE_PREFIX, @@ -331,7 +339,7 @@ public void close() { if (sockets.get(i) != null) { sockets.set(i, null).close(); } - } catch (Exception e) { + } catch (final Exception e) { LOGGER.warn("Failed to close client {}.", i, e); } finally { isSocketAlive.set(i, false); diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/protocol/IoTDBConnector.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/protocol/IoTDBConnector.java index d81292e34d542..aa398d6e9ff9c 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/protocol/IoTDBConnector.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/protocol/IoTDBConnector.java @@ -35,6 +35,7 @@ import org.apache.iotdb.pipe.api.exception.PipeParameterNotValidException; import org.apache.iotdb.service.rpc.thrift.TPipeTransferReq; +import org.apache.tsfile.utils.Pair; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -107,8 +108,8 @@ public abstract class IoTDBConnector implements PipeConnector { private boolean isRpcCompressionEnabled; private final List compressors = new ArrayList<>(); - private static final Map PIPE_END_POINT_RATE_LIMITER_MAP = - new ConcurrentHashMap<>(); + private static final Map, PipeEndPointRateLimiter> + PIPE_END_POINT_RATE_LIMITER_MAP = new ConcurrentHashMap<>(); private double endPointRateLimitBytesPerSecond = -1; private static final GlobalRateLimiter GLOBAL_RATE_LIMITER = new GlobalRateLimiter(); @@ -383,11 +384,17 @@ public List getCompressors() { } public void rateLimitIfNeeded( - final String pipeName, final TEndPoint endPoint, final long bytesLength) { + final String pipeName, + final long creationTime, + final TEndPoint endPoint, + final long bytesLength) { if (pipeName != null && endPointRateLimitBytesPerSecond > 0) { PIPE_END_POINT_RATE_LIMITER_MAP .computeIfAbsent( - pipeName, endpoint -> new PipeEndPointRateLimiter(endPointRateLimitBytesPerSecond)) + new Pair<>(pipeName, creationTime), + endpoint -> + new PipeEndPointRateLimiter( + pipeName, creationTime, endPointRateLimitBytesPerSecond)) .acquire(endPoint, bytesLength); } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/protocol/IoTDBSslSyncConnector.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/protocol/IoTDBSslSyncConnector.java index 713f25df29ef0..a51edf46cd4c3 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/protocol/IoTDBSslSyncConnector.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/connector/protocol/IoTDBSslSyncConnector.java @@ -144,10 +144,11 @@ public void heartbeat() { } protected void transferFilePieces( - String pipeName, - File file, - Pair clientAndStatus, - boolean isMultiFile) + final String pipeName, + final long creationTime, + final File file, + final Pair clientAndStatus, + final boolean isMultiFile) throws PipeException, IOException { final int readFileBufferSize = PipeConfig.getInstance().getPipeConnectorReadFileBufferSize(); final byte[] readBuffer = new byte[readFileBufferSize]; @@ -171,7 +172,10 @@ protected void transferFilePieces( ? getTransferMultiFilePieceReq(file.getName(), position, payLoad) : getTransferSingleFilePieceReq(file.getName(), position, payLoad)); rateLimitIfNeeded( - pipeName, clientAndStatus.getLeft().getEndPoint(), req.getBody().length); + pipeName, + creationTime, + clientAndStatus.getLeft().getEndPoint(), + req.getBody().length); resp = PipeTransferFilePieceResp.fromTPipeTransferResp( clientAndStatus.getLeft().pipeTransfer(req)); diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/datastructure/queue/ConcurrentIterableLinkedQueue.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/datastructure/queue/ConcurrentIterableLinkedQueue.java index 78a8c1a75faa9..306b5491f32ee 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/datastructure/queue/ConcurrentIterableLinkedQueue.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/datastructure/queue/ConcurrentIterableLinkedQueue.java @@ -24,9 +24,10 @@ import org.slf4j.LoggerFactory; import java.io.Closeable; +import java.util.Collections; import java.util.Iterator; +import java.util.Set; import java.util.concurrent.ConcurrentHashMap; -import java.util.concurrent.ConcurrentMap; import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.Condition; import java.util.concurrent.locks.ReentrantReadWriteLock; @@ -57,8 +58,8 @@ private LinkedListNode(final E data) { private final ReentrantReadWriteLock lock = new ReentrantReadWriteLock(); private final Condition hasNextCondition = lock.writeLock().newCondition(); - private final ConcurrentMap iteratorSet = - new ConcurrentHashMap<>(); + private final Set iteratorSet = + Collections.newSetFromMap(new ConcurrentHashMap<>()); /** * Add an element to the tail of the queue. @@ -110,7 +111,7 @@ public long tryRemoveBefore(long newFirstIndex) { lock.writeLock().lock(); try { // Iterate over iterators to find the minimum valid newFirstIndex - for (final DynamicIterator iterator : iteratorSet.keySet()) { + for (final DynamicIterator iterator : iteratorSet) { newFirstIndex = Math.min(newFirstIndex, iterator.getNextIndex()); } newFirstIndex = Math.max(newFirstIndex, firstIndex); @@ -138,14 +139,12 @@ public long tryRemoveBefore(long newFirstIndex) { } // Update iterators if necessary - iteratorSet - .keySet() - .forEach( - iterator -> { - if (iterator.nextIndex == firstIndex) { - iterator.currentNode = pilotNode; - } - }); + iteratorSet.forEach( + iterator -> { + if (iterator.nextIndex == firstIndex) { + iterator.currentNode = pilotNode; + } + }); hasNextCondition.signalAll(); @@ -160,7 +159,7 @@ public void clear() { lock.writeLock().lock(); try { // Use a new set to avoid ConcurrentModificationException - ImmutableSet.copyOf(iteratorSet.keySet()).forEach(DynamicIterator::close); + ImmutableSet.copyOf(iteratorSet).forEach(DynamicIterator::close); tryRemoveBefore(tailIndex); } finally { @@ -237,7 +236,7 @@ public boolean hasAnyIterators() { public DynamicIterator iterateFrom(final long offset) { final DynamicIterator iterator = new DynamicIterator(offset); - iteratorSet.put(iterator, iterator); + iteratorSet.add(iterator); return iterator; } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/event/EnrichedEvent.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/event/EnrichedEvent.java index 3742c3c60288c..6d68b6072941c 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/event/EnrichedEvent.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/event/EnrichedEvent.java @@ -48,6 +48,7 @@ public abstract class EnrichedEvent implements Event { protected final AtomicBoolean isReleased; protected final String pipeName; + protected final long creationTime; protected final PipeTaskMeta pipeTaskMeta; protected String committerKey; @@ -67,6 +68,7 @@ public abstract class EnrichedEvent implements Event { protected EnrichedEvent( final String pipeName, + final long creationTime, final PipeTaskMeta pipeTaskMeta, final PipePattern pipePattern, final long startTime, @@ -74,6 +76,7 @@ protected EnrichedEvent( referenceCount = new AtomicInteger(0); isReleased = new AtomicBoolean(false); this.pipeName = pipeName; + this.creationTime = creationTime; this.pipeTaskMeta = pipeTaskMeta; this.pipePattern = pipePattern; this.startTime = startTime; @@ -129,7 +132,7 @@ public boolean increaseReferenceCount(final String holderMessage) { * {@code false} if the {@link EnrichedEvent} is not controlled by the invoker, which means * the data stored in the event is not safe to use */ - public abstract boolean internallyIncreaseResourceReferenceCount(String holderMessage); + public abstract boolean internallyIncreaseResourceReferenceCount(final String holderMessage); /** * Decrease the {@link EnrichedEvent#referenceCount} of this {@link EnrichedEvent} by 1. If the @@ -208,7 +211,7 @@ public boolean clearReferenceCount(final String holderMessage) { * @return {@code true} if the {@link EnrichedEvent#referenceCount} is decreased successfully, * {@code true} otherwise */ - public abstract boolean internallyDecreaseResourceReferenceCount(String holderMessage); + public abstract boolean internallyDecreaseResourceReferenceCount(final String holderMessage); protected void reportProgress() { if (pipeTaskMeta != null) { @@ -245,6 +248,14 @@ public final String getPipeName() { return pipeName; } + public final long getCreationTime() { + return creationTime; + } + + public final boolean isDataRegionEvent() { + return !(this instanceof PipeWritePlanEvent) && !(this instanceof PipeSnapshotEvent); + } + /** * Get the pattern string of this {@link EnrichedEvent}. * @@ -291,11 +302,12 @@ public boolean shouldParseTime() { } public abstract EnrichedEvent shallowCopySelfAndBindPipeTaskMetaForProgressReport( - String pipeName, - PipeTaskMeta pipeTaskMeta, - PipePattern pattern, - long startTime, - long endTime); + final String pipeName, + final long creationTime, + final PipeTaskMeta pipeTaskMeta, + final PipePattern pattern, + final long startTime, + final long endTime); public PipeTaskMeta getPipeTaskMeta() { return pipeTaskMeta; @@ -310,12 +322,14 @@ public boolean needToCommit() { public abstract boolean mayEventTimeOverlappedWithTimeRange(); + public abstract boolean mayEventPathsOverlappedWithPattern(); + public void setCommitterKeyAndCommitId(final String committerKey, final long commitId) { this.committerKey = committerKey; this.commitId = commitId; } - public void setRebootTimes(int rebootTimes) { + public void setRebootTimes(final int rebootTimes) { this.rebootTimes = rebootTimes; } @@ -342,17 +356,17 @@ public boolean isReleased() { } /** - * Used for pipeConsensus. In PipeConsensus, we only need commiterKey, commitId and rebootTimes to - * uniquely identify an event + * Used for pipeConsensus. In PipeConsensus, we only need committerKey, commitId and rebootTimes + * to uniquely identify an event */ - public boolean equalsInPipeConsensus(Object o) { + public boolean equalsInPipeConsensus(final Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } - EnrichedEvent otherEvent = (EnrichedEvent) o; + final EnrichedEvent otherEvent = (EnrichedEvent) o; return Objects.equals(committerKey, otherEvent.committerKey) && commitId == otherEvent.commitId && rebootTimes == otherEvent.rebootTimes; diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/event/PipeSnapshotEvent.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/event/PipeSnapshotEvent.java index fa26319e6dc00..1c6dd689e648c 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/event/PipeSnapshotEvent.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/event/PipeSnapshotEvent.java @@ -35,10 +35,11 @@ public abstract class PipeSnapshotEvent extends EnrichedEvent implements Seriali protected PipeSnapshotEvent( final String pipeName, + final long creationTime, final PipeTaskMeta pipeTaskMeta, final PipePattern pattern, final PipeSnapshotResourceManager resourceManager) { - super(pipeName, pipeTaskMeta, pattern, Long.MIN_VALUE, Long.MAX_VALUE); + super(pipeName, creationTime, pipeTaskMeta, pattern, Long.MIN_VALUE, Long.MAX_VALUE); this.resourceManager = resourceManager; } @@ -62,6 +63,11 @@ public boolean mayEventTimeOverlappedWithTimeRange() { return true; } + @Override + public boolean mayEventPathsOverlappedWithPattern() { + return true; + } + /////////////////////////////// Type parsing /////////////////////////////// public String toSealTypeString() { diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/event/PipeWritePlanEvent.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/event/PipeWritePlanEvent.java index d37aee82aaad8..4a7a25dbd23ac 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/event/PipeWritePlanEvent.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/event/PipeWritePlanEvent.java @@ -31,10 +31,11 @@ public abstract class PipeWritePlanEvent extends EnrichedEvent implements Serial protected PipeWritePlanEvent( final String pipeName, + final long creationTime, final PipeTaskMeta pipeTaskMeta, final PipePattern pattern, final boolean isGeneratedByPipe) { - super(pipeName, pipeTaskMeta, pattern, Long.MIN_VALUE, Long.MAX_VALUE); + super(pipeName, creationTime, pipeTaskMeta, pattern, Long.MIN_VALUE, Long.MAX_VALUE); this.isGeneratedByPipe = isGeneratedByPipe; } @@ -70,6 +71,11 @@ public boolean mayEventTimeOverlappedWithTimeRange() { return true; } + @Override + public boolean mayEventPathsOverlappedWithPattern() { + return true; + } + /////////////////////////// Object /////////////////////////// @Override diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/event/ProgressReportEvent.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/event/ProgressReportEvent.java index 2851b03593c15..700f8f1638748 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/event/ProgressReportEvent.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/event/ProgressReportEvent.java @@ -34,11 +34,12 @@ public class ProgressReportEvent extends EnrichedEvent { public ProgressReportEvent( final String pipeName, + final long creationTime, final PipeTaskMeta pipeTaskMeta, final PipePattern pipePattern, final long startTime, final long endTime) { - super(pipeName, pipeTaskMeta, pipePattern, startTime, endTime); + super(pipeName, creationTime, pipeTaskMeta, pipePattern, startTime, endTime); } @Override @@ -64,11 +65,13 @@ public ProgressIndex getProgressIndex() { @Override public EnrichedEvent shallowCopySelfAndBindPipeTaskMetaForProgressReport( final String pipeName, + final long creationTime, final PipeTaskMeta pipeTaskMeta, final PipePattern pattern, final long startTime, final long endTime) { - return new ProgressReportEvent(pipeName, pipeTaskMeta, pattern, startTime, endTime); + return new ProgressReportEvent( + pipeName, creationTime, pipeTaskMeta, pattern, startTime, endTime); } @Override @@ -80,4 +83,9 @@ public boolean isGeneratedByPipe() { public boolean mayEventTimeOverlappedWithTimeRange() { return true; } + + @Override + public boolean mayEventPathsOverlappedWithPattern() { + return true; + } } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/execution/executor/PipeSubtaskExecutor.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/execution/executor/PipeSubtaskExecutor.java index e990318660b30..886538050673e 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/execution/executor/PipeSubtaskExecutor.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/execution/executor/PipeSubtaskExecutor.java @@ -21,6 +21,7 @@ import org.apache.iotdb.commons.concurrent.IoTDBThreadPoolFactory; import org.apache.iotdb.commons.concurrent.ThreadName; +import org.apache.iotdb.commons.concurrent.threadpool.WrappedThreadPoolExecutor; import org.apache.iotdb.commons.pipe.execution.scheduler.PipeSubtaskScheduler; import org.apache.iotdb.commons.pipe.task.subtask.PipeSubtask; import org.apache.iotdb.commons.utils.TestOnly; @@ -41,17 +42,22 @@ public abstract class PipeSubtaskExecutor { private static final ExecutorService subtaskCallbackListeningExecutor = IoTDBThreadPoolFactory.newSingleThreadExecutor( ThreadName.PIPE_SUBTASK_CALLBACK_EXECUTOR_POOL.getName()); - private final ListeningExecutorService subtaskWorkerThreadPoolExecutor; + protected final ListeningExecutorService subtaskWorkerThreadPoolExecutor; private final Map registeredIdSubtaskMapper; private final int corePoolSize; private int runningSubtaskNumber; - protected PipeSubtaskExecutor(int corePoolSize, ThreadName threadName) { - subtaskWorkerThreadPoolExecutor = - MoreExecutors.listeningDecorator( - IoTDBThreadPoolFactory.newFixedThreadPool(corePoolSize, threadName.getName())); + protected PipeSubtaskExecutor( + final int corePoolSize, final ThreadName threadName, final boolean disableLogInThreadPool) { + final WrappedThreadPoolExecutor executor = + (WrappedThreadPoolExecutor) + IoTDBThreadPoolFactory.newFixedThreadPool(corePoolSize, threadName.getName()); + if (disableLogInThreadPool) { + executor.disableErrorLog(); + } + subtaskWorkerThreadPoolExecutor = MoreExecutors.listeningDecorator(executor); registeredIdSubtaskMapper = new ConcurrentHashMap<>(); @@ -61,7 +67,7 @@ protected PipeSubtaskExecutor(int corePoolSize, ThreadName threadName) { /////////////////////// Subtask management /////////////////////// - public final synchronized void register(PipeSubtask subtask) { + public final synchronized void register(final PipeSubtask subtask) { if (registeredIdSubtaskMapper.containsKey(subtask.getTaskID())) { LOGGER.warn("The subtask {} is already registered.", subtask.getTaskID()); return; @@ -74,7 +80,7 @@ public final synchronized void register(PipeSubtask subtask) { new PipeSubtaskScheduler(this)); } - public final synchronized void start(String subTaskID) { + public final synchronized void start(final String subTaskID) { if (!registeredIdSubtaskMapper.containsKey(subTaskID)) { LOGGER.warn("The subtask {} is not registered.", subTaskID); return; @@ -93,7 +99,7 @@ public final synchronized void start(String subTaskID) { } } - public final synchronized void stop(String subTaskID) { + public final synchronized void stop(final String subTaskID) { if (!registeredIdSubtaskMapper.containsKey(subTaskID)) { LOGGER.warn("The subtask {} is not registered.", subTaskID); return; @@ -104,7 +110,7 @@ public final synchronized void stop(String subTaskID) { } } - public final synchronized void deregister(String subTaskID) { + public final synchronized void deregister(final String subTaskID) { stop(subTaskID); final PipeSubtask subtask = registeredIdSubtaskMapper.remove(subTaskID); @@ -113,14 +119,14 @@ public final synchronized void deregister(String subTaskID) { try { subtask.close(); LOGGER.info("The subtask {} is closed successfully.", subTaskID); - } catch (Exception e) { + } catch (final Exception e) { LOGGER.error("Failed to close the subtask {}.", subTaskID, e); } } } @TestOnly - public final boolean isRegistered(String subTaskID) { + public final boolean isRegistered(final String subTaskID) { return registeredIdSubtaskMapper.containsKey(subTaskID); } @@ -137,7 +143,7 @@ public final synchronized void shutdown() { } // stop all subtasks before shutting down the executor - for (PipeSubtask subtask : registeredIdSubtaskMapper.values()) { + for (final PipeSubtask subtask : registeredIdSubtaskMapper.values()) { subtask.disallowSubmittingSelf(); } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/extractor/IoTDBNonDataRegionExtractor.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/extractor/IoTDBNonDataRegionExtractor.java index 9d6ce0ffde813..a67e818be983a 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/extractor/IoTDBNonDataRegionExtractor.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/extractor/IoTDBNonDataRegionExtractor.java @@ -154,7 +154,12 @@ public EnrichedEvent supply() throws Exception { historicalEvents .remove(0) .shallowCopySelfAndBindPipeTaskMetaForProgressReport( - pipeName, pipeTaskMeta, pipePattern, Long.MIN_VALUE, Long.MAX_VALUE); + pipeName, + creationTime, + pipeTaskMeta, + pipePattern, + Long.MIN_VALUE, + Long.MAX_VALUE); if (historicalEvents.isEmpty()) { // We only report progress for the last snapshot event. @@ -180,7 +185,7 @@ public EnrichedEvent supply() throws Exception { || (!isForwardingPipeRequests && realtimeEvent.isGeneratedByPipe())) { final ProgressReportEvent event = new ProgressReportEvent( - pipeName, pipeTaskMeta, pipePattern, Long.MIN_VALUE, Long.MAX_VALUE); + pipeName, creationTime, pipeTaskMeta, pipePattern, Long.MIN_VALUE, Long.MAX_VALUE); event.bindProgressIndex(new MetaProgressIndex(iterator.getNextIndex() - 1)); event.increaseReferenceCount(IoTDBNonDataRegionExtractor.class.getName()); return event; @@ -189,7 +194,7 @@ public EnrichedEvent supply() throws Exception { realtimeEvent = (PipeWritePlanEvent) realtimeEvent.shallowCopySelfAndBindPipeTaskMetaForProgressReport( - pipeName, pipeTaskMeta, pipePattern, Long.MIN_VALUE, Long.MAX_VALUE); + pipeName, creationTime, pipeTaskMeta, pipePattern, Long.MIN_VALUE, Long.MAX_VALUE); realtimeEvent.bindProgressIndex(new MetaProgressIndex(iterator.getNextIndex() - 1)); realtimeEvent.increaseReferenceCount(IoTDBNonDataRegionExtractor.class.getName()); return realtimeEvent; diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/metric/PipeRemainingOperator.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/metric/PipeRemainingOperator.java new file mode 100644 index 0000000000000..97f80e5d98533 --- /dev/null +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/metric/PipeRemainingOperator.java @@ -0,0 +1,87 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +package org.apache.iotdb.commons.pipe.metric; + +import org.apache.iotdb.commons.pipe.config.PipeConfig; + +public abstract class PipeRemainingOperator { + + protected static final long REMAINING_MAX_SECONDS = 365 * 24 * 60 * 60L; // 1 year + + protected String pipeName; + protected long creationTime = 0; + + private long lastEmptyTimeStamp = System.currentTimeMillis(); + private long lastNonEmptyTimeStamp = System.currentTimeMillis(); + protected boolean isStopped = true; + + //////////////////////////// Tags //////////////////////////// + + public String getPipeName() { + return pipeName; + } + + public long getCreationTime() { + return creationTime; + } + + //////////////////////////// Register & deregister (pipe integration) //////////////////////////// + + protected void setNameAndCreationTime(final String pipeName, final long creationTime) { + this.pipeName = pipeName; + this.creationTime = creationTime; + } + + //////////////////////////// Switch //////////////////////////// + + protected void notifyNonEmpty() { + final long pipeRemainingTimeCommitAutoSwitchSeconds = + PipeConfig.getInstance().getPipeRemainingTimeCommitAutoSwitchSeconds(); + + lastNonEmptyTimeStamp = System.currentTimeMillis(); + if (lastNonEmptyTimeStamp - lastEmptyTimeStamp + >= pipeRemainingTimeCommitAutoSwitchSeconds * 1000) { + thawRate(false); + } + } + + protected void notifyEmpty() { + final long pipeRemainingTimeCommitAutoSwitchSeconds = + PipeConfig.getInstance().getPipeRemainingTimeCommitAutoSwitchSeconds(); + + lastEmptyTimeStamp = System.currentTimeMillis(); + if (lastEmptyTimeStamp - lastNonEmptyTimeStamp + >= pipeRemainingTimeCommitAutoSwitchSeconds * 1000) { + freezeRate(false); + } + } + + public synchronized void thawRate(final boolean isStartPipe) { + if (isStartPipe) { + isStopped = false; + } + } + + public synchronized void freezeRate(final boolean isStopPipe) { + if (isStopPipe) { + isStopped = true; + } + } +} diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/pattern/IoTDBPipePattern.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/pattern/IoTDBPipePattern.java index b270a2b070017..adbc2cd30f5c3 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/pattern/IoTDBPipePattern.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/pattern/IoTDBPipePattern.java @@ -52,7 +52,9 @@ public IoTDBPipePattern(final String pattern) { public static List applyIndexesOnList( final int[] filteredIndexes, final List originalList) { - return Arrays.stream(filteredIndexes).mapToObj(originalList::get).collect(Collectors.toList()); + return Objects.nonNull(originalList) + ? Arrays.stream(filteredIndexes).mapToObj(originalList::get).collect(Collectors.toList()) + : null; } @Override diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/progress/PipeEventCommitManager.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/progress/PipeEventCommitManager.java index 9f9369ae56b63..d51f012661261 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/progress/PipeEventCommitManager.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/progress/PipeEventCommitManager.java @@ -19,7 +19,6 @@ package org.apache.iotdb.commons.pipe.progress; -import org.apache.iotdb.commons.pipe.config.plugin.env.PipeTaskRuntimeEnvironment; import org.apache.iotdb.commons.pipe.event.EnrichedEvent; import org.apache.iotdb.commons.pipe.metric.PipeEventCommitMetrics; @@ -29,7 +28,7 @@ import java.util.Map; import java.util.Objects; import java.util.concurrent.ConcurrentHashMap; -import java.util.function.Consumer; +import java.util.function.BiConsumer; public class PipeEventCommitManager { @@ -38,7 +37,7 @@ public class PipeEventCommitManager { // key: pipeName_regionId private final Map eventCommitterMap = new ConcurrentHashMap<>(); - private Consumer commitRateMarker; + private BiConsumer commitRateMarker; public void register( final String pipeName, @@ -88,10 +87,26 @@ public void enrichWithCommitterKeyAndCommitId( } public void commit(final EnrichedEvent event, final String committerKey) { - if (committerKey == null - || event == null + if (event == null || !event.needToCommit() - || event.getCommitId() <= EnrichedEvent.NO_COMMIT_ID) { + || Objects.isNull(event.getPipeName()) + || event.getCreationTime() == 0) { + return; + } + if (Objects.nonNull(commitRateMarker)) { + try { + commitRateMarker.accept( + event.getPipeName() + '_' + event.getCreationTime(), event.isDataRegionEvent()); + } catch (final Exception e) { + if (LOGGER.isDebugEnabled()) { + LOGGER.debug( + "Failed to mark commit rate for pipe task: {}, stack trace: {}", + committerKey, + Thread.currentThread().getStackTrace()); + } + } + } + if (committerKey == null || event.getCommitId() <= EnrichedEvent.NO_COMMIT_ID) { return; } final PipeEventCommitter committer = eventCommitterMap.get(committerKey); @@ -108,20 +123,6 @@ public void commit(final EnrichedEvent event, final String committerKey) { } committer.commit(event); - if (Objects.nonNull(commitRateMarker)) { - try { - commitRateMarker.accept( - new PipeTaskRuntimeEnvironment( - committer.getPipeName(), committer.getCreationTime(), committer.getRegionId())); - } catch (Exception e) { - if (LOGGER.isDebugEnabled()) { - LOGGER.debug( - "Failed to mark commit rate for pipe: {}, stack trace: {}", - committerKey, - Thread.currentThread().getStackTrace()); - } - } - } } private static String generateCommitterKey( @@ -129,7 +130,7 @@ private static String generateCommitterKey( return String.format("%s_%s_%s", pipeName, regionId, creationTime); } - public void setCommitRateMarker(final Consumer commitRateMarker) { + public void setCommitRateMarker(final BiConsumer commitRateMarker) { this.commitRateMarker = commitRateMarker; } @@ -137,6 +138,14 @@ private PipeEventCommitManager() { // Do nothing but make it private. } + public long getGivenConsensusPipeCommitId(String committerKey) { + final PipeEventCommitter committer = eventCommitterMap.get(committerKey); + if (committer == null) { + return 0; + } + return committer.getCurrentCommitId(); + } + private static class PipeEventCommitManagerHolder { private static final PipeEventCommitManager INSTANCE = new PipeEventCommitManager(); } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/progress/PipeEventCommitter.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/progress/PipeEventCommitter.java index 04502441daf13..559e53ee15b9f 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/progress/PipeEventCommitter.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/progress/PipeEventCommitter.java @@ -136,4 +136,8 @@ public int getRegionId() { public long commitQueueSize() { return commitQueue.size(); } + + public long getCurrentCommitId() { + return commitIdGenerator.get(); + } } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/task/meta/PipeTemporaryMeta.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/task/meta/PipeTemporaryMeta.java index 7a028f4b0e214..f444e6943b621 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/task/meta/PipeTemporaryMeta.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/task/meta/PipeTemporaryMeta.java @@ -19,6 +19,7 @@ package org.apache.iotdb.commons.pipe.task.meta; +import java.util.Collections; import java.util.Objects; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -26,12 +27,13 @@ public class PipeTemporaryMeta { - private final ConcurrentMap completedDataNodeIds = new ConcurrentHashMap<>(); + private final Set completedDataNodeIds = + Collections.newSetFromMap(new ConcurrentHashMap<>()); private final ConcurrentMap nodeId2RemainingEventMap = new ConcurrentHashMap<>(); private final ConcurrentMap nodeId2RemainingTimeMap = new ConcurrentHashMap<>(); public void markDataNodeCompleted(final int dataNodeId) { - completedDataNodeIds.put(dataNodeId, dataNodeId); + completedDataNodeIds.add(dataNodeId); } public void markDataNodeUncompleted(final int dataNodeId) { @@ -47,7 +49,7 @@ public void setRemainingTime(final int dataNodeId, final double remainingTime) { } public Set getCompletedDataNodeIds() { - return completedDataNodeIds.keySet(); + return completedDataNodeIds; } public long getGlobalRemainingEvents() { diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/task/subtask/PipeAbstractConnectorSubtask.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/task/subtask/PipeAbstractConnectorSubtask.java index f5bfe36c6c732..78e913d65757c 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/task/subtask/PipeAbstractConnectorSubtask.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/task/subtask/PipeAbstractConnectorSubtask.java @@ -23,7 +23,6 @@ import org.apache.iotdb.commons.pipe.config.PipeConfig; import org.apache.iotdb.commons.pipe.event.EnrichedEvent; import org.apache.iotdb.commons.pipe.execution.scheduler.PipeSubtaskScheduler; -import org.apache.iotdb.commons.pipe.task.DecoratingLock; import org.apache.iotdb.pipe.api.PipeConnector; import org.apache.iotdb.pipe.api.exception.PipeConnectionException; @@ -43,7 +42,6 @@ public abstract class PipeAbstractConnectorSubtask extends PipeReportableSubtask protected PipeConnector outputPipeConnector; // For thread pool to execute callbacks - protected final DecoratingLock callbackDecoratingLock = new DecoratingLock(); protected ExecutorService subtaskCallbackListeningExecutor; // For controlling subtask submitting, making sure that @@ -51,41 +49,30 @@ public abstract class PipeAbstractConnectorSubtask extends PipeReportableSubtask protected volatile boolean isSubmitted = false; protected PipeAbstractConnectorSubtask( - String taskID, long creationTime, PipeConnector outputPipeConnector) { + final String taskID, final long creationTime, final PipeConnector outputPipeConnector) { super(taskID, creationTime); this.outputPipeConnector = outputPipeConnector; } @Override public void bindExecutors( - ListeningExecutorService subtaskWorkerThreadPoolExecutor, - ExecutorService subtaskCallbackListeningExecutor, - PipeSubtaskScheduler subtaskScheduler) { + final ListeningExecutorService subtaskWorkerThreadPoolExecutor, + final ExecutorService subtaskCallbackListeningExecutor, + final PipeSubtaskScheduler subtaskScheduler) { this.subtaskWorkerThreadPoolExecutor = subtaskWorkerThreadPoolExecutor; this.subtaskCallbackListeningExecutor = subtaskCallbackListeningExecutor; this.subtaskScheduler = subtaskScheduler; } @Override - public Boolean call() throws Exception { - final boolean hasAtLeastOneEventProcessed = super.call(); - - // Wait for the callable to be decorated by Futures.addCallback in the executorService - // to make sure that the callback can be submitted again on success or failure. - callbackDecoratingLock.waitForDecorated(); - - return hasAtLeastOneEventProcessed; - } - - @Override - public synchronized void onSuccess(Boolean hasAtLeastOneEventProcessed) { + public synchronized void onSuccess(final Boolean hasAtLeastOneEventProcessed) { isSubmitted = false; super.onSuccess(hasAtLeastOneEventProcessed); } @Override - public synchronized void onFailure(Throwable throwable) { + public synchronized void onFailure(final Throwable throwable) { isSubmitted = false; if (isClosed.get()) { @@ -116,7 +103,7 @@ public synchronized void onFailure(Throwable throwable) { /** * @return {@code true} if the {@link PipeSubtask} should be stopped, {@code false} otherwise */ - private boolean onPipeConnectionException(Throwable throwable) { + private boolean onPipeConnectionException(final Throwable throwable) { LOGGER.warn( "PipeConnectionException occurred, {} retries to handshake with the target system.", outputPipeConnector.getClass().getName(), @@ -130,7 +117,7 @@ private boolean onPipeConnectionException(Throwable throwable) { "{} handshakes with the target system successfully.", outputPipeConnector.getClass().getName()); break; - } catch (Exception e) { + } catch (final Exception e) { retry++; LOGGER.warn( "{} failed to handshake with the target system for {} times, " @@ -141,7 +128,7 @@ private boolean onPipeConnectionException(Throwable throwable) { e); try { Thread.sleep(retry * PipeConfig.getInstance().getPipeConnectorRetryIntervalMs()); - } catch (InterruptedException interruptedException) { + } catch (final InterruptedException interruptedException) { LOGGER.info( "Interrupted while sleeping, will retry to handshake with the target system.", interruptedException); @@ -195,13 +182,8 @@ public synchronized void submitSelf() { return; } - callbackDecoratingLock.markAsDecorating(); - try { - final ListenableFuture nextFuture = subtaskWorkerThreadPoolExecutor.submit(this); - Futures.addCallback(nextFuture, this, subtaskCallbackListeningExecutor); - isSubmitted = true; - } finally { - callbackDecoratingLock.markAsDecorated(); - } + final ListenableFuture nextFuture = subtaskWorkerThreadPoolExecutor.submit(this); + Futures.addCallback(nextFuture, this, subtaskCallbackListeningExecutor); + isSubmitted = true; } } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/task/subtask/PipeReportableSubtask.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/task/subtask/PipeReportableSubtask.java index 327152dd0c37e..462644db4df02 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/task/subtask/PipeReportableSubtask.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/task/subtask/PipeReportableSubtask.java @@ -31,12 +31,12 @@ public abstract class PipeReportableSubtask extends PipeSubtask { private static final Logger LOGGER = LoggerFactory.getLogger(PipeReportableSubtask.class); - protected PipeReportableSubtask(String taskID, long creationTime) { + protected PipeReportableSubtask(final String taskID, final long creationTime) { super(taskID, creationTime); } @Override - public synchronized void onFailure(Throwable throwable) { + public synchronized void onFailure(final Throwable throwable) { if (isClosed.get()) { LOGGER.info("onFailure in pipe subtask, ignored because pipe is dropped.", throwable); clearReferenceCountAndReleaseLastEvent(); @@ -55,7 +55,7 @@ public synchronized void onFailure(Throwable throwable) { // is dropped or the process is running normally. } - private void onEnrichedEventFailure(Throwable throwable) { + private void onEnrichedEventFailure(final Throwable throwable) { final int maxRetryTimes = throwable instanceof PipeRuntimeConnectorRetryTimesConfigurableException ? ((PipeRuntimeConnectorRetryTimesConfigurableException) throwable).getRetryTimes() @@ -75,15 +75,17 @@ private void onEnrichedEventFailure(Throwable throwable) { retryCount.incrementAndGet(); if (retryCount.get() <= MAX_RETRY_TIMES) { LOGGER.warn( - "Retry executing subtask {} (creation time: {}, simple class: {}), retry count [{}/{}]", + "Retry executing subtask {} (creation time: {}, simple class: {}), retry count [{}/{}], last exception: {}", taskID, creationTime, this.getClass().getSimpleName(), retryCount.get(), - maxRetryTimes); + maxRetryTimes, + throwable.getMessage(), + throwable); try { Thread.sleep(Math.min(1000L * retryCount.get(), 10000)); - } catch (InterruptedException e) { + } catch (final InterruptedException e) { LOGGER.warn( "Interrupted when retrying to execute subtask {} (creation time: {}, simple class: {})", taskID, @@ -123,11 +125,11 @@ private void onEnrichedEventFailure(Throwable throwable) { } } - protected abstract String getRootCause(Throwable throwable); + protected abstract String getRootCause(final Throwable throwable); - protected abstract void report(EnrichedEvent event, PipeRuntimeException exception); + protected abstract void report(final EnrichedEvent event, final PipeRuntimeException exception); - private void onNonEnrichedEventFailure(Throwable throwable) { + private void onNonEnrichedEventFailure(final Throwable throwable) { if (retryCount.get() == 0) { LOGGER.warn( "Failed to execute subtask {} (creation time: {}, simple class: {}), " @@ -141,14 +143,16 @@ private void onNonEnrichedEventFailure(Throwable throwable) { retryCount.incrementAndGet(); LOGGER.warn( - "Retry executing subtask {} (creation time: {}, simple class: {}), retry count {}", + "Retry executing subtask {} (creation time: {}, simple class: {}), retry count {}, last exception: {}", taskID, creationTime, this.getClass().getSimpleName(), - retryCount.get()); + retryCount.get(), + throwable.getMessage(), + throwable); try { Thread.sleep(Math.min(1000L * retryCount.get(), 10000)); - } catch (InterruptedException e) { + } catch (final InterruptedException e) { LOGGER.warn( "Interrupted when retrying to execute subtask {} (creation time: {}, simple class: {})", taskID, diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/ttl/TTLCache.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/ttl/TTLCache.java index 081f009b5bbac..8e1f99e69a7f4 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/ttl/TTLCache.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/ttl/TTLCache.java @@ -20,9 +20,10 @@ import org.apache.iotdb.commons.conf.CommonDescriptor; import org.apache.iotdb.commons.conf.IoTDBConstant; +import org.apache.iotdb.commons.exception.IllegalPathException; import org.apache.iotdb.commons.utils.CommonDateTimeUtils; +import org.apache.iotdb.commons.utils.PathUtils; -import org.apache.tsfile.common.constant.TsFileConstant; import org.apache.tsfile.utils.ReadWriteIOUtils; import javax.annotation.concurrent.NotThreadSafe; @@ -30,9 +31,10 @@ import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; +import java.util.ArrayList; import java.util.HashMap; +import java.util.List; import java.util.Map; -import java.util.Objects; /** TTL Cache Tree, which is a prefix B+ tree with each node storing TTL. */ @NotThreadSafe @@ -152,24 +154,6 @@ public long getClosestTTL(String[] nodes) { return ttl; } - public Map getAllTTLUnderOneNode(String[] nodes) { - Map pathTTLMap = new HashMap<>(); - CacheNode current = ttlCacheTree; - for (int i = 1; i < nodes.length; i++) { - current = current.getChild(nodes[i]); - if (current == null) { - return pathTTLMap; - } - } - - // get all ttl under current node - dfsCacheTree( - pathTTLMap, - new StringBuilder(String.join(String.valueOf(IoTDBConstant.PATH_SEPARATOR), nodes)), - current); - return pathTTLMap; - } - /** * Return the ttl of path. If the path does not exist, it means that the TTL is not set, and * return NULL_TTL. @@ -185,23 +169,36 @@ public long getLastNodeTTL(String[] nodes) { return node.ttl; } + /** + * @return key is path contains wildcard between each node + */ public Map getAllPathTTL() { Map result = new HashMap<>(); - dfsCacheTree(result, new StringBuilder(IoTDBConstant.PATH_ROOT), ttlCacheTree); + for (Map.Entry entry : getAllTTLs().entrySet()) { + result.put( + String.join(String.valueOf(IoTDBConstant.PATH_SEPARATOR), entry.getKey()), + entry.getValue()); + } return result; } - private void dfsCacheTree(Map pathTTLMap, StringBuilder path, CacheNode node) { + public Map getAllTTLs() { + Map result = new HashMap<>(); + List pathNodes = new ArrayList<>(); + pathNodes.add(IoTDBConstant.PATH_ROOT); + dfsCacheTree(result, pathNodes, ttlCacheTree); + return result; + } + + private void dfsCacheTree( + Map pathTTLMap, List pathNodes, CacheNode node) { if (node.ttl != NULL_TTL) { - pathTTLMap.put(path.toString(), node.ttl); + pathTTLMap.put(pathNodes.toArray(new String[0]), node.ttl); } - int idx = path.length(); for (Map.Entry entry : node.getChildren().entrySet()) { - dfsCacheTree( - pathTTLMap, - path.append(IoTDBConstant.PATH_SEPARATOR).append(entry.getValue().name), - entry.getValue()); - path.delete(idx, path.length()); + pathNodes.add(entry.getKey()); + dfsCacheTree(pathTTLMap, pathNodes, entry.getValue()); + pathNodes.remove(pathNodes.size() - 1); } } @@ -219,12 +216,13 @@ public void serialize(OutputStream outputStream) throws IOException { outputStream.flush(); } - public void deserialize(InputStream bufferedInputStream) throws IOException { + public void deserialize(InputStream bufferedInputStream) + throws IOException, IllegalPathException { int size = ReadWriteIOUtils.readInt(bufferedInputStream); while (size > 0) { String path = ReadWriteIOUtils.readString(bufferedInputStream); long ttl = ReadWriteIOUtils.readLong(bufferedInputStream); - setTTL(Objects.requireNonNull(path).split(TsFileConstant.PATH_SEPARATER_NO_REGEX), ttl); + setTTL(PathUtils.splitPathToDetachedNodes(path), ttl); size--; } } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/service/metric/enums/Metric.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/service/metric/enums/Metric.java index c207435d3f191..219ead6945182 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/service/metric/enums/Metric.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/service/metric/enums/Metric.java @@ -55,6 +55,11 @@ public enum Metric { IOT_CONSENSUS("iot_consensus"), IOT_SEND_LOG("iot_send_log"), IOT_RECEIVE_LOG("iot_receive_log"), + PIPE_CONSENSUS("pipe_consensus"), + PIPE_CONSENSUS_MODE("pipe_consensus_mode"), + PIPE_SEND_EVENT("pipe_send_event"), + PIPE_RETRY_SEND_EVENT("pipe_retry_send_event"), + PIPE_RECEIVE_EVENT("pipe_receive_event"), RATIS_CONSENSUS_WRITE("ratis_consensus_write"), RATIS_CONSENSUS_READ("ratis_consensus_read"), // storage engine related @@ -171,7 +176,11 @@ public enum Metric { SUBSCRIPTION_CURRENT_COMMIT_ID("subscription_current_commit_id"), SUBSCRIPTION_EVENT_TRANSFER("subscription_event_transfer"), // load related - LOAD_MEM("load_mem"); + LOAD_MEM("load_mem"), + LOAD_DISK_IO("load_disk_io"), + LOAD_TIME_COST("load_time_cost"), + LOAD_POINT_COUNT("load_point_count"), + ; final String value; diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/subscription/meta/consumer/ConsumerGroupMeta.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/subscription/meta/consumer/ConsumerGroupMeta.java index d53868208bf5e..764fbfca50121 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/subscription/meta/consumer/ConsumerGroupMeta.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/subscription/meta/consumer/ConsumerGroupMeta.java @@ -48,7 +48,7 @@ public ConsumerGroupMeta() { } public ConsumerGroupMeta( - String consumerGroupId, long creationTime, ConsumerMeta firstConsumerMeta) { + final String consumerGroupId, final long creationTime, final ConsumerMeta firstConsumerMeta) { this.consumerGroupId = consumerGroupId; this.creationTime = creationTime; this.topicNameToSubscribedConsumerIdSet = new HashMap<>(); @@ -74,20 +74,48 @@ public long getCreationTime() { return creationTime; } + public static /* @NonNull */ Set getTopicsUnsubByGroup( + final ConsumerGroupMeta currentMeta, final ConsumerGroupMeta updatedMeta) { + if (!Objects.equals(currentMeta.consumerGroupId, updatedMeta.consumerGroupId)) { + return Collections.emptySet(); + } + if (!Objects.equals(currentMeta.creationTime, updatedMeta.creationTime)) { + return Collections.emptySet(); + } + + // no need to check consumerIdToConsumerMeta here to avoid potential inconsistent meta + + final Set unsubscribedTopicNames = new HashSet<>(); + currentMeta + .topicNameToSubscribedConsumerIdSet + .keySet() + .forEach( + (topicName) -> { + if (!updatedMeta.topicNameToSubscribedConsumerIdSet.containsKey(topicName)) { + unsubscribedTopicNames.add(topicName); + } + }); + return unsubscribedTopicNames; + } + /////////////////////////////// consumer /////////////////////////////// - public void addConsumer(ConsumerMeta consumerMeta) { + public void addConsumer(final ConsumerMeta consumerMeta) { consumerIdToConsumerMeta.put(consumerMeta.getConsumerId(), consumerMeta); } - public void removeConsumer(String consumerId) { + public void removeConsumer(final String consumerId) { consumerIdToConsumerMeta.remove(consumerId); - for (Set subscribedConsumers : topicNameToSubscribedConsumerIdSet.values()) { - subscribedConsumers.remove(consumerId); + for (final Map.Entry> entry : + topicNameToSubscribedConsumerIdSet.entrySet()) { + entry.getValue().remove(consumerId); + if (entry.getValue().isEmpty()) { + topicNameToSubscribedConsumerIdSet.remove(entry.getKey()); + } } } - public boolean containsConsumer(String consumerId) { + public boolean containsConsumer(final String consumerId) { return consumerIdToConsumerMeta.containsKey(consumerId); } @@ -106,13 +134,13 @@ public boolean isEmpty() { * @return The set of consumer IDs subscribing the given topic in this group. If no consumer is * subscribing the topic, return an empty set. */ - public Set getConsumersSubscribingTopic(String topic) { + public Set getConsumersSubscribingTopic(final String topic) { return topicNameToSubscribedConsumerIdSet.getOrDefault(topic, Collections.emptySet()); } - public Set getTopicsSubscribedByConsumer(String consumerId) { - Set topics = new HashSet<>(); - for (Map.Entry> topicNameToSubscribedConsumerId : + public Set getTopicsSubscribedByConsumer(final String consumerId) { + final Set topics = new HashSet<>(); + for (final Map.Entry> topicNameToSubscribedConsumerId : topicNameToSubscribedConsumerIdSet.entrySet()) { if (topicNameToSubscribedConsumerId.getValue().contains(consumerId)) { topics.add(topicNameToSubscribedConsumerId.getKey()); @@ -121,7 +149,7 @@ public Set getTopicsSubscribedByConsumer(String consumerId) { return topics; } - public void addSubscription(String consumerId, Set topics) { + public void addSubscription(final String consumerId, final Set topics) { if (!consumerIdToConsumerMeta.containsKey(consumerId)) { throw new SubscriptionException( String.format( @@ -129,7 +157,7 @@ public void addSubscription(String consumerId, Set topics) { consumerId, consumerGroupId)); } - for (String topic : topics) { + for (final String topic : topics) { topicNameToSubscribedConsumerIdSet .computeIfAbsent(topic, k -> new HashSet<>()) .add(consumerId); @@ -139,7 +167,7 @@ public void addSubscription(String consumerId, Set topics) { /** * @return topics subscribed by no consumers in this group after this removal. */ - public Set removeSubscription(String consumerId, Set topics) { + public Set removeSubscription(final String consumerId, final Set topics) { if (!consumerIdToConsumerMeta.containsKey(consumerId)) { throw new SubscriptionException( String.format( @@ -147,8 +175,8 @@ public Set removeSubscription(String consumerId, Set topics) { consumerId, consumerGroupId)); } - Set noSubscriptionTopicAfterRemoval = new HashSet<>(); - for (String topic : topics) { + final Set noSubscriptionTopicAfterRemoval = new HashSet<>(); + for (final String topic : topics) { if (topicNameToSubscribedConsumerIdSet.containsKey(topic)) { topicNameToSubscribedConsumerIdSet.get(topic).remove(consumerId); if (topicNameToSubscribedConsumerIdSet.get(topic).isEmpty()) { @@ -163,33 +191,34 @@ public Set removeSubscription(String consumerId, Set topics) { /////////////////////////////// de/ser /////////////////////////////// public ByteBuffer serialize() throws IOException { - PublicBAOS byteArrayOutputStream = new PublicBAOS(); - DataOutputStream outputStream = new DataOutputStream(byteArrayOutputStream); + final PublicBAOS byteArrayOutputStream = new PublicBAOS(); + final DataOutputStream outputStream = new DataOutputStream(byteArrayOutputStream); serialize(outputStream); return ByteBuffer.wrap(byteArrayOutputStream.getBuf(), 0, byteArrayOutputStream.size()); } - public void serialize(OutputStream outputStream) throws IOException { + public void serialize(final OutputStream outputStream) throws IOException { ReadWriteIOUtils.write(consumerGroupId, outputStream); ReadWriteIOUtils.write(creationTime, outputStream); ReadWriteIOUtils.write(topicNameToSubscribedConsumerIdSet.size(), outputStream); - for (Map.Entry> entry : topicNameToSubscribedConsumerIdSet.entrySet()) { + for (final Map.Entry> entry : + topicNameToSubscribedConsumerIdSet.entrySet()) { ReadWriteIOUtils.write(entry.getKey(), outputStream); ReadWriteIOUtils.write(entry.getValue().size(), outputStream); - for (String id : entry.getValue()) { + for (final String id : entry.getValue()) { ReadWriteIOUtils.write(id, outputStream); } } ReadWriteIOUtils.write(consumerIdToConsumerMeta.size(), outputStream); - for (Map.Entry entry : consumerIdToConsumerMeta.entrySet()) { + for (final Map.Entry entry : consumerIdToConsumerMeta.entrySet()) { ReadWriteIOUtils.write(entry.getKey(), outputStream); entry.getValue().serialize(outputStream); } } - public static ConsumerGroupMeta deserialize(InputStream inputStream) throws IOException { + public static ConsumerGroupMeta deserialize(final InputStream inputStream) throws IOException { final ConsumerGroupMeta consumerGroupMeta = new ConsumerGroupMeta(); consumerGroupMeta.consumerGroupId = ReadWriteIOUtils.readString(inputStream); @@ -220,7 +249,7 @@ public static ConsumerGroupMeta deserialize(InputStream inputStream) throws IOEx return consumerGroupMeta; } - public static ConsumerGroupMeta deserialize(ByteBuffer byteBuffer) { + public static ConsumerGroupMeta deserialize(final ByteBuffer byteBuffer) { final ConsumerGroupMeta consumerGroupMeta = new ConsumerGroupMeta(); consumerGroupMeta.consumerGroupId = ReadWriteIOUtils.readString(byteBuffer); @@ -254,14 +283,14 @@ public static ConsumerGroupMeta deserialize(ByteBuffer byteBuffer) { /////////////////////////////// Object /////////////////////////////// @Override - public boolean equals(Object obj) { + public boolean equals(final Object obj) { if (this == obj) { return true; } if (obj == null || getClass() != obj.getClass()) { return false; } - ConsumerGroupMeta that = (ConsumerGroupMeta) obj; + final ConsumerGroupMeta that = (ConsumerGroupMeta) obj; return Objects.equals(consumerGroupId, that.consumerGroupId) && creationTime == that.creationTime && Objects.equals( diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/subscription/meta/topic/TopicMeta.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/subscription/meta/topic/TopicMeta.java index a0e80db04e068..14c48c85da33b 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/subscription/meta/topic/TopicMeta.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/subscription/meta/topic/TopicMeta.java @@ -185,6 +185,10 @@ public Map generateExtractorAttributes() { extractorAttributes.putAll(config.getAttributesWithTimeRange(creationTime)); // realtime mode extractorAttributes.putAll(config.getAttributesWithRealtimeMode()); + // source mode + extractorAttributes.putAll(config.getAttributesWithSourceMode()); + // loose range + extractorAttributes.putAll(config.getAttributesWithSourceLooseRange()); return extractorAttributes; } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/TimePartitionUtils.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/TimePartitionUtils.java index fe20e6ba15507..b0339cb68220b 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/TimePartitionUtils.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/TimePartitionUtils.java @@ -82,4 +82,8 @@ public static boolean satisfyTimePartition(Filter timeFilter, long partitionId) public static void setTimePartitionInterval(long timePartitionInterval) { TimePartitionUtils.timePartitionInterval = timePartitionInterval; } + + public static long getEstimateTimePartitionSize(long startTime, long endTime) { + return (endTime - startTime) / timePartitionInterval + 1; + } } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/function/CheckedTriConsumer.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/function/CheckedTriConsumer.java new file mode 100644 index 0000000000000..bb9a5ebaaab18 --- /dev/null +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/utils/function/CheckedTriConsumer.java @@ -0,0 +1,25 @@ +/* + * 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.iotdb.commons.utils.function; + +@FunctionalInterface +public interface CheckedTriConsumer { + void accept(INPUT1 var1, INPUT2 var2, INPUT3 var3) throws THROWABLE; +} diff --git a/iotdb-protocol/thrift-commons/src/main/thrift/common.thrift b/iotdb-protocol/thrift-commons/src/main/thrift/common.thrift index 49dc50d94c476..6df74bc73e9de 100644 --- a/iotdb-protocol/thrift-commons/src/main/thrift/common.thrift +++ b/iotdb-protocol/thrift-commons/src/main/thrift/common.thrift @@ -121,15 +121,20 @@ struct TSchemaNode { 2: required byte nodeType } +struct TSetConfigurationReq { + 1: required map configs + 2: required i32 nodeId +} + +// for TTL struct TSetTTLReq { 1: required list pathPattern 2: required i64 TTL 3: required bool isDataBase } -struct TSetConfigurationReq { - 1: required map configs - 2: required i32 nodeId +struct TShowTTLReq { + 1: required list pathPattern } // for File @@ -191,6 +196,40 @@ struct TLicense { 9: required i16 mlNodeNumLimit } +enum TServiceType { + ConfigNodeInternalService, + DataNodeInternalService, + DataNodeMPPService, + DataNodeExternalService, +} + +struct TServiceProvider { + 1: required TEndPoint endPoint + 2: required TServiceType serviceType +} + +struct TSender { + 1: optional TDataNodeLocation dataNodeLocation + 2: optional TConfigNodeLocation configNodeLocation +} + +struct TTestConnectionResult { + 1: required TServiceProvider serviceProvider + 2: required TSender sender + 3: required bool success + 4: optional string reason +} + +struct TTestConnectionResp { + 1: required TSStatus status + 2: required list resultList +} + +struct TNodeLocations { + 1: optional list configNodeLocations + 2: optional list dataNodeLocations +} + enum TAggregationType { COUNT, AVG, diff --git a/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift b/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift index 1328d651961e4..16c728caf81a2 100644 --- a/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift +++ b/iotdb-protocol/thrift-confignode/src/main/thrift/confignode.thrift @@ -112,6 +112,7 @@ struct TDataNodeRegisterReq { 1: required string clusterName 2: required common.TDataNodeConfiguration dataNodeConfiguration 3: optional TNodeVersionInfo versionInfo + 4: optional bool preCheck } struct TDataNodeRegisterResp { @@ -1319,8 +1320,8 @@ service IConfigNodeRPCService { // ====================================================== // TTL // ====================================================== - /** Show all ttl */ - TShowTTLResp showAllTTL() + /** Show ttl */ + TShowTTLResp showTTL(common.TShowTTLReq req) /** Update the specific device's TTL */ common.TSStatus setTTL(common.TSetTTLReq req) @@ -1387,6 +1388,14 @@ service IConfigNodeRPCService { /** Show cluster Databases' information */ TShowDatabaseResp showDatabase(TGetDatabaseReq req) + /** Test connection of every node in the cluster */ + common.TTestConnectionResp submitTestConnectionTask(common.TNodeLocations nodeLocations) + + common.TTestConnectionResp submitTestConnectionTaskToLeader() + + /** Empty rpc, only for connection test */ + common.TSStatus testConnectionEmptyRPC() + /** * Show the matched cluster Regions' information * See https://apache-iotdb.feishu.cn/docx/doxcnOzmIlaE2MX5tKjmYWuMSRg for detailed matching rules diff --git a/iotdb-protocol/thrift-datanode/src/main/thrift/client.thrift b/iotdb-protocol/thrift-datanode/src/main/thrift/client.thrift index 6069199bd64c9..917a9a5790025 100644 --- a/iotdb-protocol/thrift-datanode/src/main/thrift/client.thrift +++ b/iotdb-protocol/thrift-datanode/src/main/thrift/client.thrift @@ -659,4 +659,7 @@ service IClientRPCService { TSBackupConfigurationResp getBackupConfiguration(); TSConnectionInfoResp fetchAllConnectionsInfo(); + + /** For other node's call */ + common.TSStatus testConnectionEmptyRPC() } \ No newline at end of file diff --git a/iotdb-protocol/thrift-datanode/src/main/thrift/datanode.thrift b/iotdb-protocol/thrift-datanode/src/main/thrift/datanode.thrift index 6373870840977..d7fd5a71e5017 100644 --- a/iotdb-protocol/thrift-datanode/src/main/thrift/datanode.thrift +++ b/iotdb-protocol/thrift-datanode/src/main/thrift/datanode.thrift @@ -1009,6 +1009,11 @@ service IDataNodeRPCService { * Update Table Cache */ common.TSStatus updateTable(TUpdateTableReq req) + + common.TTestConnectionResp submitTestConnectionTask(common.TNodeLocations nodeLocations) + + /** Empty rpc, only for connection test */ + common.TSStatus testConnectionEmptyRPC() } service MPPDataExchangeService { @@ -1021,4 +1026,7 @@ service MPPDataExchangeService { void onNewDataBlockEvent(TNewDataBlockEvent e); void onEndOfDataBlockEvent(TEndOfDataBlockEvent e); + + /** Empty rpc, only for connection test */ + common.TSStatus testConnectionEmptyRPC() } diff --git a/pom.xml b/pom.xml index d16c7b73db65f..105eea127403b 100644 --- a/pom.xml +++ b/pom.xml @@ -76,15 +76,11 @@ true 5.1.9 3.0.2 - 3.8.1-17.0 - 1.17.1 1.16 1.22.0 2.10.1 32.1.2-jre - 3.3.6 - 3.1.3 4.5.14 4.4.16 6.6.0 - 1.9.1 7.0.0 1.5.6 2.0.9 @@ -145,11 +140,6 @@ 1.1.13 3.5.10 0.10.2 - 5.1.3 - 2.12.19 - 2.12 - - 3.0.9 2.0.9 1.1.10.4 target/jacoco-merged-reports/jacoco.xml @@ -160,15 +150,9 @@ target/checkstyle-report.xml target/surefire-reports,target/failsafe-reports apache - 2.4.8 - 3.5.0 false 2.43.0 - - 2.7.18 - - 5.3.34 1.6.11 chmod @@ -180,10 +164,7 @@ we'll stay at 0.14.1. --> 0.14.1 - - 9.0.86 1.9 - 0.11.1 1.5.5-5 1.0.1-tsfilev4-SNAPSHOT @@ -201,51 +182,6 @@ pom import - - org.springframework.boot - spring-boot - ${spring-boot.version} - - - org.springframework.boot - spring-boot-autoconfigure - ${spring-boot.version} - - - org.springframework - spring-tx - ${spring.version} - - - org.springframework - spring-beans - ${spring.version} - - - org.springframework - spring-web - ${spring.version} - - - org.springframework - spring-context - ${spring.version} - - - org.springframework - spring-webmvc - ${spring.version} - - - org.springframework - spring-jdbc - ${spring.version} - - - org.springframework - spring-test - ${spring.version} - org.slf4j slf4j-api @@ -333,68 +269,6 @@ powermock-reflect ${powermock.version} - - org.apache.flink - flink-clients - ${flink.version} - - - org.apache.flink - flink-core - ${flink.version} - - - org.apache.flink - flink-hadoop-fs - ${flink.version} - - - org.apache.flink - flink-java - ${flink.version} - - - org.apache.flink - flink-streaming-core - ${flink.version} - - - org.apache.flink - flink-streaming-java - ${flink.version} - - - - org.apache.flink - flink-shaded-zookeeper-3 - - - - - org.apache.flink - flink-table-api-java-bridge - ${flink.version} - - - org.apache.flink - flink-table-common - ${flink.version} - - - org.apache.flink - flink-table-test-utils - ${flink.version} - - - org.apache.flink - flink-shaded-zookeeper-3 - ${flink-shaded-zookeeper-3.version} - - - org.apache.flink - flink-table-api-java - ${flink.version} - com.google.guava guava @@ -410,117 +284,6 @@ jsr305 ${findbugs.jsr305.version} - - org.apache.hadoop - hadoop-client - ${hadoop.version} - - - javax.xml.bind - jaxb-api - - - org.slf4j - jcl-over-slf4j - - - - - org.apache.hadoop - hadoop-client-api - ${hadoop.version} - - - org.apache.hadoop - hadoop-common - ${hadoop.version} - - - - ch.qos.reload4j - reload4j - - - - org.slf4j - slf4j-reload4j - - - - log4j - log4j - - - javax.xml.bind - jaxb-api - - - javax.ws.rs - jsr311-api - - - com.sun.jersey - jersey-server - - - - - org.apache.hadoop - hadoop-client-runtime - ${hadoop.version} - - - - ch.qos.reload4j - reload4j - - - - org.slf4j - slf4j-reload4j - - - - log4j - log4j - - - - - org.apache.hadoop - hadoop-mapreduce-client-core - ${hadoop.version} - - - - ch.qos.reload4j - reload4j - - - - org.slf4j - slf4j-reload4j - - - javax.xml.bind - jaxb-api - - - com.sun.jersey - jersey-server - - - - io.netty - netty - - - - - org.apache.hadoop - hadoop-yarn-registry - ${hadoop.version} - com.google.code.gson gson @@ -531,261 +294,11 @@ jakarta.servlet-api ${jakarta.servlet-api.version} - - org.apache.hive - hive-exec - ${hive.version} - - core - - - - org.apache.calcite.avatica - avatica - - - org.apache.logging.log4j - log4j-1.2-api - - - javax.xml.bind - jaxb-api - - - - org.apache.ivy - ivy - - - - org.apache.ant - ant - - - - org.bouncycastle - bcprov-jdk15on - - - - org.bouncycastle - bcpkix-jdk15on - - - - log4j - log4j - - - - com.cedarsoftware - json-io - - - - org.apache.calcite - calcite-core - - - - - org.apache.hive - hive-serde - ${hive.version} - - - org.apache.logging.log4j - log4j-slf4j-impl - - - - - org.apache.hive - hive-common - ${hive.version} - - - org.javolution - javolution - - - javax.xml.bind - jaxb-api - - - org.apache.logging.log4j - log4j-1.2-api - - - org.apache.logging.log4j - log4j-slf4j-impl - - - - org.apache.ant - ant - - - - - org.apache.spark - spark-core_2.11 - ${spark-scala.2.11.version} - - - ch.qos.reload4j - reload4j - - - javax.activation - activation - - - javax.ws.rs - javax.ws.rs-api - - - org.glassfish.hk2.external - javax.inject - - - org.glassfish.hk2.external - aopalliance-repackaged - - - org.glassfish.hk2.external - jakarta.inject - - - org.slf4j - slf4j-reload4j - - - org.slf4j - jcl-over-slf4j - - - org.spark-project.spark - unused - - - - org.apache.ivy - ivy - - - - log4j - log4j - - - - io.netty - netty - - - - - org.apache.spark - spark-sql_2.11 - ${spark-scala.2.11.version} - - - org.spark-project.spark - unused - - - - - org.apache.spark - spark-catalyst_2.11 - ${spark-scala.2.11.version} - - - org.spark-project.spark - unused - - - - - org.apache.spark - spark-core_2.12 - ${spark-scala.2.12.version} - - - - org.apache.ivy - ivy - - - - - org.apache.spark - spark-common-utils_2.12 - ${spark-scala.2.12.version} - - - - org.apache.logging.log4j - log4j-slf4j2-impl - - - org.slf4j - jcl-over-slf4j - - - - - org.apache.spark - spark-sql_2.12 - ${spark-scala.2.12.version} - - - org.apache.spark - spark-catalyst_2.12 - ${spark-scala.2.12.version} - - - org.apache.spark - spark-sql-api_2.12 - ${spark-scala.2.12.version} - - - org.scala-lang - scala-library - ${scala.library.version} - org.bouncycastle bcprov-jdk18on 1.78 - - org.scalatest - scalatest_2.11 - ${scalatest.version} - - - org.scalactic - scalactic_2.11 - ${scalatest.version} - - - org.apache.zeppelin - zeppelin-interpreter - ${zeppelin.version} - - - org.slf4j - jcl-over-slf4j - - - - log4j - log4j - - - commons-io commons-io @@ -1000,11 +513,6 @@ - - org.apache.rocketmq - rocketmq-client - ${rocketmq-client.version} - org.fusesource.mqtt-client mqtt-client @@ -1055,11 +563,6 @@ metrics-core ${dropwizard.metrics.version} - - io.dropwizard.metrics - metrics-jmx - ${dropwizard.metrics.version} - org.eclipse.jetty jetty-http @@ -1121,15 +624,6 @@ awaitility ${awaitility.version} - - - org.apache.tomcat.embed - tomcat-embed-core - ${tomcat.version} - io.projectreactor.netty reactor-netty-http @@ -1186,35 +680,10 @@ ${jersey.version} - org.glassfish.jersey.core - jersey-client - ${jersey.version} - - - org.glassfish.jersey.core - jersey-core - ${jersey.version} - - - org.glassfish.jersey.core - jersey-common - ${jersey.version} - - - org.glassfish.jersey.core - jersey-server - ${jersey.version} - - - org.glassfish.jersey.containers - jersey-container-servlet + org.glassfish.jersey.inject + jersey-hk2 ${jersey.version} - - com.rabbitmq - amqp-client - 5.18.0 - - - org.yaml - snakeyaml - 2.0 - - - - com.esotericsoftware.kryo - kryo - 2.24.0 - - - - org.codehaus.woodstox - stax2-api - 4.2.1 - - - - javax.xml.bind - jaxb-api - 2.2.11 - - - - org.apache.commons - commons-compress - 1.26.0 - - - - com.google.inject.extensions - guice-servlet - 4.0 - - - - org.eclipse.jetty - jetty-io - 9.4.52.v20230823 - - - - commons-logging - commons-logging - 1.2 - - - - com.google.inject - guice - 4.0 - - - - com.fasterxml.jackson.module - jackson-module-jaxb-annotations - 2.15.2 - - - - org.apache.commons - commons-text - 1.10.0 - - - - jakarta.activation - jakarta.activation-api - 1.2.2 - - - - org.springframework - spring-core - 5.3.30 - - - - org.apache.hadoop - hadoop-auth - ${hadoop.version} - - - - org.apache.hadoop - hadoop-yarn-api - ${hadoop.version} - - - - org.apache.hadoop - hadoop-yarn-common - ${hadoop.version} - - - - org.apache.hadoop - hadoop-yarn-server-resourcemanager - ${hadoop.version} - - - - org.apache.hadoop - hadoop-annotations - ${hadoop.version} - - - - org.codehaus.jettison - jettison - 1.5.4 - - - - org.eclipse.jetty - jetty-client - 9.4.51.v20230217 - - - - org.apache.zookeeper - zookeeper - 3.7.2 - - - - org.eclipse.jetty - jetty-webapp - 9.4.51.v20230217 - - - - org.apache.avro - avro - 1.11.3 - - - - org.codehaus.jackson - jackson-core-asl - - - org.codehaus.jackson - jackson-mapper-asl - - - - - - org.apache.avro - avro-mapred - 1.8.2 - hadoop2 - - - - org.codehaus.jackson - jackson-core-asl - - - org.codehaus.jackson - jackson-mapper-asl - - - - - - org.apache.parquet - parquet-hadoop - 1.10.1 - - - - org.codehaus.jackson - jackson-core-asl - - - org.codehaus.jackson - jackson-mapper-asl - - - - - - org.eclipse.jetty - jetty-util-ajax - ${jetty.version} - - - - org.apache.curator - curator-framework - 5.2.0 - - - - org.apache.curator - curator-recipes - 5.2.0 - - - - org.apache.curator - curator-client - 5.2.0 - - - - ch.qos.reload4j - reload4j - 1.2.22 - - - - joda-time - joda-time - 2.9.9 - - - - commons-net - commons-net - 3.9.0 - - - - org.antlr - antlr-runtime - 3.5.2 - - - - org.jetbrains.kotlin - kotlin-stdlib - 1.9.10 - - - org.jetbrains.kotlin - kotlin-stdlib-common - 1.9.10 - - - org.jetbrains.kotlin - kotlin-stdlib-jdk7 - 1.9.10 - - - org.jetbrains.kotlin - kotlin-stdlib-jdk8 - 1.9.10 - - - - com.squareup.okio - okio - 3.5.0 - - - - com.google.protobuf - protobuf-java - 3.24.3 - - - com.google.protobuf - protobuf-java-util - 3.24.3 - - - - org.codehaus.janino - janino - 3.1.10 - - - org.codehaus.janino - commons-compiler - 3.1.10 - - - - io.atomix - atomix - 3.1.12 - - - io.atomix - atomix-primitive - 3.1.12 - - - io.atomix - atomix-storage - 3.1.12 - - - io.atomix - atomix-cluster - 3.1.12 - - - io.atomix - atomix-utils - 3.1.12 - - - io.atomix - atomix-raft - 3.1.12 - - - - org.apache.commons - commons-configuration2 - 2.10.1 - - - org.apache.orc - orc-core - ${orc-core.version} - - - org.apache.orc - orc-core - ${orc-core.version} - nohive - - - org.apache.orc - orc-mapreduce - ${orc-core.version} - - - org.apache.orc - orc-mapreduce - ${orc-core.version} - nohive - - - org.apache.orc - orc-shims - ${orc-core.version} - - - org.glassfish.jersey.inject - jersey-hk2 - ${jersey.version} - @@ -1954,21 +963,6 @@ lifecycle-mapping 1.0.0 - - com.github.eirslett - frontend-maven-plugin - 1.14.0 - - - org.apache.maven.plugins - maven-antrun-plugin - 3.1.0 - - - org.scala-tools - maven-scala-plugin - 2.15.2 - org.antlr antlr4-maven-plugin