From 364bbd80317887e290fee08ee40345058d004da9 Mon Sep 17 00:00:00 2001 From: VGalaxies Date: Wed, 21 Jan 2026 23:07:08 +0800 Subject: [PATCH] Cherry-pick #16789 to dev/1.3 --- .../pipe/pattern/PipePatternPruningTest.java | 156 ++++++++ .../datastructure/pattern/PipePattern.java | 377 ++++++++++++++---- .../pattern/UnionIoTDBPipePattern.java | 6 + .../WithExclusionIoTDBPipePattern.java | 2 - .../pattern/WithExclusionPipePattern.java | 2 - 5 files changed, 472 insertions(+), 71 deletions(-) create mode 100644 iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/pattern/PipePatternPruningTest.java diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/pattern/PipePatternPruningTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/pattern/PipePatternPruningTest.java new file mode 100644 index 000000000000..4b0c5b1ef2f5 --- /dev/null +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/pipe/pattern/PipePatternPruningTest.java @@ -0,0 +1,156 @@ +/* + * 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.pattern; + +import org.apache.iotdb.commons.pipe.config.constant.PipeSourceConstant; +import org.apache.iotdb.commons.pipe.datastructure.pattern.IoTDBPipePattern; +import org.apache.iotdb.commons.pipe.datastructure.pattern.PipePattern; +import org.apache.iotdb.commons.pipe.datastructure.pattern.PrefixPipePattern; +import org.apache.iotdb.commons.pipe.datastructure.pattern.UnionIoTDBPipePattern; +import org.apache.iotdb.pipe.api.customizer.parameter.PipeParameters; +import org.apache.iotdb.pipe.api.exception.PipeException; + +import org.junit.Assert; +import org.junit.Test; + +import java.util.HashMap; + +public class PipePatternPruningTest { + + @Test + public void testUnionInternalPruning_Cover() { + final PipeParameters params = + new PipeParameters( + new HashMap() { + { + put(PipeSourceConstant.SOURCE_PATH_KEY, "root.db.d1.*,root.db.d1.s1"); + } + }); + + final PipePattern result = PipePattern.parsePipePatternFromSourceParameters(params); + + Assert.assertTrue("Should be IoTDBPipePattern", result instanceof IoTDBPipePattern); + Assert.assertEquals("root.db.d1.*", result.getPattern()); + } + + @Test + public void testUnionInternalPruning_Duplicates() { + final PipeParameters params = + new PipeParameters( + new HashMap() { + { + put(PipeSourceConstant.SOURCE_PATH_KEY, "root.db.d1,root.db.d1"); + } + }); + + final PipePattern result = PipePattern.parsePipePatternFromSourceParameters(params); + + Assert.assertTrue(result instanceof IoTDBPipePattern); + Assert.assertEquals("root.db.d1", result.getPattern()); + } + + @Test + public void testInclusionPrunedByExclusion_Partial() { + final PipeParameters params = + new PipeParameters( + new HashMap() { + { + put(PipeSourceConstant.SOURCE_PATH_KEY, "root.sg.d1,root.sg.d2"); + put(PipeSourceConstant.SOURCE_PATH_EXCLUSION_KEY, "root.sg.d1"); + } + }); + + final PipePattern result = PipePattern.parsePipePatternFromSourceParameters(params); + + Assert.assertTrue(result instanceof IoTDBPipePattern); + Assert.assertEquals("root.sg.d2", result.getPattern()); + } + + @Test + public void testInclusionPrunedByExclusion_FullCoverage_Exception() { + final PipeParameters params = + new PipeParameters( + new HashMap() { + { + put(PipeSourceConstant.SOURCE_PATH_KEY, "root.sg.d1"); + put(PipeSourceConstant.SOURCE_PATH_EXCLUSION_KEY, "root.sg.**"); + } + }); + + try { + PipePattern.parsePipePatternFromSourceParameters(params); + Assert.fail("Should throw PipeException because Exclusion fully covers Inclusion"); + } catch (final PipeException ignored) { + // Expected exception + } + } + + @Test + public void testComplexPruning() { + final PipeParameters params = + new PipeParameters( + new HashMap() { + { + put(PipeSourceConstant.SOURCE_PATH_KEY, "root.sg.A,root.sg.B,root.sg.A.sub"); + put(PipeSourceConstant.SOURCE_PATH_EXCLUSION_KEY, "root.sg.A,root.sg.A.**"); + } + }); + + final PipePattern result = PipePattern.parsePipePatternFromSourceParameters(params); + + Assert.assertTrue(result instanceof IoTDBPipePattern); + Assert.assertEquals("root.sg.B", result.getPattern()); + } + + @Test + public void testComplexPruning_Prefix() { + final PipeParameters params = + new PipeParameters( + new HashMap() { + { + put(PipeSourceConstant.SOURCE_PATTERN_KEY, "root.sg.A,root.sg.B,root.sg.A.sub"); + put(PipeSourceConstant.SOURCE_PATTERN_EXCLUSION_KEY, "root.sg.A"); + put(PipeSourceConstant.SOURCE_PATTERN_FORMAT_KEY, "prefix"); + } + }); + + final PipePattern result = PipePattern.parsePipePatternFromSourceParameters(params); + + Assert.assertTrue(result instanceof PrefixPipePattern); + Assert.assertEquals("root.sg.B", result.getPattern()); + } + + @Test + public void testUnionPreservedWhenNotCovered() { + final PipeParameters params = + new PipeParameters( + new HashMap() { + { + put(PipeSourceConstant.SOURCE_PATH_KEY, "root.sg.d1,root.sg.d2"); + put(PipeSourceConstant.SOURCE_PATH_EXCLUSION_KEY, "root.other"); + } + }); + + final PipePattern result = PipePattern.parsePipePatternFromSourceParametersInternal(params); + + Assert.assertTrue(result instanceof UnionIoTDBPipePattern); + Assert.assertEquals("root.sg.d1,root.sg.d2", result.getPattern()); + } +} diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/datastructure/pattern/PipePattern.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/datastructure/pattern/PipePattern.java index 24973ab7bfa2..a76306aab816 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/datastructure/pattern/PipePattern.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/datastructure/pattern/PipePattern.java @@ -19,7 +19,9 @@ package org.apache.iotdb.commons.pipe.datastructure.pattern; +import org.apache.iotdb.commons.conf.IoTDBConstant; import org.apache.iotdb.commons.path.PartialPath; +import org.apache.iotdb.commons.utils.TestOnly; import org.apache.iotdb.pipe.api.customizer.parameter.PipeParameters; import org.apache.iotdb.pipe.api.exception.PipeException; @@ -29,7 +31,9 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; +import java.util.HashMap; import java.util.List; +import java.util.Map; import java.util.Objects; import java.util.function.Function; import java.util.stream.Collectors; @@ -142,53 +146,71 @@ public static PipePattern parsePipePatternFromSourceParameters( public static PipePattern parsePipePatternFromSourceParametersInternal( final PipeParameters sourceParameters) { - // 1. Define the default inclusion pattern (matches all, "root.**") - // This is used if no inclusion patterns are specified. - final PipePattern defaultInclusionPattern = - buildUnionPattern(Collections.singletonList(new IoTDBPipePattern(null))); - - // 2. Parse INCLUSION patterns using the helper - final PipePattern inclusionPattern = - parsePatternUnion( + // 1. Parse INCLUSION patterns into a list + List inclusionPatterns = + parsePatternList( sourceParameters, - // 'path' keys (IoTDB wildcard) EXTRACTOR_PATH_KEY, SOURCE_PATH_KEY, - // 'pattern' keys (Prefix or IoTDB via format) EXTRACTOR_PATTERN_KEY, - SOURCE_PATTERN_KEY, - // Default pattern if no keys are found - defaultInclusionPattern); + SOURCE_PATTERN_KEY); - // 3. Parse EXCLUSION patterns using the helper - final PipePattern exclusionPattern = - parsePatternUnion( + // If no inclusion patterns are specified, use default "root.**" + if (inclusionPatterns.isEmpty()) { + inclusionPatterns = new ArrayList<>(Collections.singletonList(new IoTDBPipePattern(null))); + } + + // 2. Parse EXCLUSION patterns into a list + List exclusionPatterns = + parsePatternList( sourceParameters, - // 'path.exclusion' keys (IoTDB wildcard) EXTRACTOR_PATH_EXCLUSION_KEY, SOURCE_PATH_EXCLUSION_KEY, - // 'pattern.exclusion' keys (Prefix) EXTRACTOR_PATTERN_EXCLUSION_KEY, - SOURCE_PATTERN_EXCLUSION_KEY, - // Default for exclusion is "match nothing" (null) - null); - - // 4. Combine inclusion and exclusion - if (exclusionPattern == null) { - // No exclusion defined, return the inclusion pattern directly - return inclusionPattern; - } else { - // If both inclusion and exclusion patterns support IoTDB operations, - // use the specialized ExclusionIoTDBPipePattern - if (inclusionPattern instanceof IoTDBPipePatternOperations - && exclusionPattern instanceof IoTDBPipePatternOperations) { - return new WithExclusionIoTDBPipePattern( - (IoTDBPipePatternOperations) inclusionPattern, - (IoTDBPipePatternOperations) exclusionPattern); - } - // Both are defined, wrap them in an ExclusionPipePattern - return new WithExclusionPipePattern(inclusionPattern, exclusionPattern); + SOURCE_PATTERN_EXCLUSION_KEY); + + // 3. Optimize the lists: remove redundant patterns + inclusionPatterns = optimizePatterns(inclusionPatterns); + exclusionPatterns = optimizePatterns(exclusionPatterns); + + // 4. Prune inclusion patterns covered by exclusions + inclusionPatterns = pruneInclusionPatterns(inclusionPatterns, exclusionPatterns); + + // 5. Check if the resulting inclusion pattern is empty + if (inclusionPatterns.isEmpty()) { + final String msg = + String.format( + "Pipe: The provided exclusion pattern fully covers the inclusion pattern. " + + "This pipe pattern will match nothing. " + + "Inclusion: %s, Exclusion: %s", + sourceParameters.getStringByKeys(EXTRACTOR_PATTERN_KEY, SOURCE_PATTERN_KEY), + sourceParameters.getStringByKeys( + EXTRACTOR_PATTERN_EXCLUSION_KEY, SOURCE_PATTERN_EXCLUSION_KEY)); + LOGGER.warn(msg); + throw new PipeException(msg); + } + + // 6. Prune exclusion patterns that do not overlap with any inclusion + exclusionPatterns = pruneIrrelevantExclusions(inclusionPatterns, exclusionPatterns); + + // 7. Build final patterns + final PipePattern finalInclusionPattern = buildUnionPattern(inclusionPatterns); + + if (exclusionPatterns.isEmpty()) { + return finalInclusionPattern; + } + + final PipePattern finalExclusionPattern = buildUnionPattern(exclusionPatterns); + + // 8. Combine inclusion and exclusion + if (finalInclusionPattern instanceof IoTDBPipePatternOperations + && finalExclusionPattern instanceof IoTDBPipePatternOperations) { + return new WithExclusionIoTDBPipePattern( + (IoTDBPipePatternOperations) finalInclusionPattern, + (IoTDBPipePatternOperations) finalExclusionPattern); } + + return new WithExclusionPipePattern(finalInclusionPattern, finalExclusionPattern); } /** @@ -255,53 +277,164 @@ public static PipePattern parsePatternFromString( } /** - * A private helper method to parse a set of 'path' and 'pattern' keys into a single union - * PipePattern. This contains the original logic of parsePipePatternFromSourceParameters. - * - * @param sourceParameters The source parameters. - * @param extractorPathKey Key for extractor path (e.g., "extractor.path"). - * @param sourcePathKey Key for source path (e.g., "source.path"). - * @param extractorPatternKey Key for extractor pattern (e.g., "extractor.pattern"). - * @param sourcePatternKey Key for source pattern (e.g., "source.pattern"). - * @param defaultPattern The pattern to return if both path and pattern are null. If this - * parameter is null, this method returns null. - * @return The parsed PipePattern, or defaultPattern, or null if defaultPattern is null and no - * patterns are specified. + * Helper method to parse pattern parameters into a list of patterns without creating the Union + * object immediately. */ - private static PipePattern parsePatternUnion( + private static List parsePatternList( final PipeParameters sourceParameters, final String extractorPathKey, final String sourcePathKey, final String extractorPatternKey, - final String sourcePatternKey, - final PipePattern defaultPattern) { + final String sourcePatternKey) { final String path = sourceParameters.getStringByKeys(extractorPathKey, sourcePathKey); final String pattern = sourceParameters.getStringByKeys(extractorPatternKey, sourcePatternKey); - // 1. If both "source.path" and "source.pattern" are specified, their union will be used. - if (path != null && pattern != null) { - final List result = new ArrayList<>(); - // Parse "source.path" as IoTDB-style path. + final List result = new ArrayList<>(); + + if (path != null) { result.addAll(parseMultiplePatterns(path, IoTDBPipePattern::new)); - // Parse "source.pattern" using the helper method. + } + + if (pattern != null) { result.addAll(parsePatternsFromPatternParameter(pattern, sourceParameters)); - return buildUnionPattern(result); } - // 2. If only "source.path" is specified, it will be interpreted as an IoTDB-style path. - if (path != null) { - return buildUnionPattern(parseMultiplePatterns(path, IoTDBPipePattern::new)); + return result; + } + + /** + * Removes patterns from the list that are covered by other patterns in the same list. For + * example, if "root.**" and "root.db.**" are present, "root.db.**" is removed. + */ + private static List optimizePatterns(final List patterns) { + if (patterns == null || patterns.isEmpty()) { + return new ArrayList<>(); + } + if (patterns.size() == 1) { + return patterns; } - // 3. If only "source.pattern" is specified, parse it using the helper method. - if (pattern != null) { - return buildUnionPattern(parsePatternsFromPatternParameter(pattern, sourceParameters)); + // 1. Sort patterns by "Broadness" + final List sortedPatterns = new ArrayList<>(patterns); + sortedPatterns.sort( + (o1, o2) -> { + final PartialPath p1 = o1.getBaseInclusionPaths().get(0); + final PartialPath p2 = o2.getBaseInclusionPaths().get(0); + + final int lenCompare = Integer.compare(p1.getNodeLength(), p2.getNodeLength()); + if (lenCompare != 0) { + return lenCompare; + } + + final boolean w1 = p1.hasWildcard(); + final boolean w2 = p2.hasWildcard(); + if (w1 && !w2) { + return -1; + } + if (!w1 && w2) { + return 1; + } + + return p1.compareTo(p2); + }); + + // 2. Filter using Trie + final PatternTrie trie = new PatternTrie(); + final List optimized = new ArrayList<>(); + + for (final PipePattern pattern : sortedPatterns) { + boolean isCovered = true; + for (final PartialPath path : pattern.getBaseInclusionPaths()) { + if (!trie.isCovered(path)) { + isCovered = false; + break; + } + } + + if (!isCovered) { + optimized.add(pattern); + for (final PartialPath path : pattern.getBaseInclusionPaths()) { + trie.add(path); + } + } } - // 4. If neither "source.path" nor "source.pattern" is specified, - // return the provided default pattern (which may be null). - return defaultPattern; + return optimized; + } + + /** + * Prunes patterns from the inclusion list that are fully covered by ANY pattern in the exclusion + * list. + */ + private static List pruneInclusionPatterns( + final List inclusion, final List exclusion) { + if (inclusion == null || inclusion.isEmpty()) { + return new ArrayList<>(); + } + if (exclusion == null || exclusion.isEmpty()) { + return inclusion; + } + + final PatternTrie exclusionTrie = new PatternTrie(); + for (final PipePattern exc : exclusion) { + for (final PartialPath path : exc.getBaseInclusionPaths()) { + exclusionTrie.add(path); + } + } + + final List prunedInclusion = new ArrayList<>(); + for (final PipePattern inc : inclusion) { + boolean isFullyExcluded = true; + for (final PartialPath path : inc.getBaseInclusionPaths()) { + if (!exclusionTrie.isCovered(path)) { + isFullyExcluded = false; + break; + } + } + + if (!isFullyExcluded) { + prunedInclusion.add(inc); + } + } + return prunedInclusion; + } + + /** + * Prunes patterns from the exclusion list that do NOT overlap with any of the remaining inclusion + * patterns. + */ + private static List pruneIrrelevantExclusions( + final List inclusion, final List exclusion) { + if (exclusion == null || exclusion.isEmpty()) { + return new ArrayList<>(); + } + if (inclusion == null || inclusion.isEmpty()) { + return new ArrayList<>(); + } + + final PatternTrie inclusionTrie = new PatternTrie(); + for (final PipePattern inc : inclusion) { + for (final PartialPath path : inc.getBaseInclusionPaths()) { + inclusionTrie.add(path); + } + } + + final List relevantExclusion = new ArrayList<>(); + for (final PipePattern exc : exclusion) { + boolean overlapsWithAnyInclusion = false; + for (final PartialPath path : exc.getBaseInclusionPaths()) { + if (inclusionTrie.overlaps(path)) { + overlapsWithAnyInclusion = true; + break; + } + } + + if (overlapsWithAnyInclusion) { + relevantExclusion.add(exc); + } + } + return relevantExclusion; } /** @@ -439,6 +572,7 @@ private static int findMatchingParenthesis(final String text, final int openPare * @return An int array `[coveredCount, totalInclusionPaths]` for testing non-failing scenarios. * @throws PipeException If the inclusion pattern is fully covered by the exclusion pattern. */ + @TestOnly public static int[] checkAndLogPatternCoverage( final PipePattern inclusion, final PipePattern exclusion) throws PipeException { if (inclusion == null || exclusion == null) { @@ -502,4 +636,113 @@ public static int[] checkAndLogPatternCoverage( return new int[] {coveredCount, inclusionPaths.size()}; } + + /** A specialized Trie to efficiently check path coverage. */ + private static class PatternTrie { + private final TrieNode root = new TrieNode(); + + private static class TrieNode { + Map children = new HashMap<>(); + TrieNode wildcardNode = null; + + boolean isLeaf = false; + boolean isMultiLevelWildcard = false; + } + + public void add(final PartialPath path) { + TrieNode node = root; + final String[] nodes = path.getNodes(); + + for (final String segment : nodes) { + if (node.isMultiLevelWildcard) { + return; + } + + if (segment.equals(IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD)) { + node.isMultiLevelWildcard = true; + node.children = Collections.emptyMap(); + node.wildcardNode = null; + node.isLeaf = true; + return; + } + + if (segment.equals(IoTDBConstant.ONE_LEVEL_PATH_WILDCARD)) { + if (node.wildcardNode == null) { + node.wildcardNode = new TrieNode(); + } + node = node.wildcardNode; + } else { + node = node.children.computeIfAbsent(segment, k -> new TrieNode()); + } + } + node.isLeaf = true; + } + + public boolean isCovered(final PartialPath path) { + return checkCoverage(root, path.getNodes(), 0); + } + + private boolean checkCoverage(final TrieNode node, final String[] pathNodes, final int index) { + if (node.isMultiLevelWildcard) { + return true; + } + + if (index >= pathNodes.length) { + return node.isLeaf; + } + + final String currentSegment = pathNodes[index]; + + final TrieNode child = node.children.get(currentSegment); + if (child != null && checkCoverage(child, pathNodes, index + 1)) { + return true; + } + + if (node.wildcardNode != null) { + return checkCoverage(node.wildcardNode, pathNodes, index + 1); + } + + return false; + } + + public boolean overlaps(final PartialPath path) { + return checkOverlap(root, path.getNodes(), 0); + } + + private boolean checkOverlap(final TrieNode node, final String[] pathNodes, final int index) { + if (node.isMultiLevelWildcard) { + return true; + } + + if (index < pathNodes.length + && pathNodes[index].equals(IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD)) { + return true; + } + + if (index >= pathNodes.length) { + return node.isLeaf; + } + + final String pNode = pathNodes[index]; + + if (pNode.equals(IoTDBConstant.ONE_LEVEL_PATH_WILDCARD)) { + for (final TrieNode child : node.children.values()) { + if (checkOverlap(child, pathNodes, index + 1)) { + return true; + } + } + if (node.wildcardNode != null) { + return checkOverlap(node.wildcardNode, pathNodes, index + 1); + } + return false; + } + + final TrieNode exactChild = node.children.get(pNode); + if (exactChild != null && checkOverlap(exactChild, pathNodes, index + 1)) { + return true; + } + + return node.wildcardNode != null && checkOverlap(node.wildcardNode, pathNodes, index + 1); + } + } } diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/datastructure/pattern/UnionIoTDBPipePattern.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/datastructure/pattern/UnionIoTDBPipePattern.java index 5d331d07b03f..5000ff22657c 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/datastructure/pattern/UnionIoTDBPipePattern.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/datastructure/pattern/UnionIoTDBPipePattern.java @@ -21,6 +21,7 @@ import org.apache.iotdb.commons.path.PartialPath; import org.apache.iotdb.commons.path.PathPatternTree; +import org.apache.iotdb.commons.utils.TestOnly; import java.util.ArrayList; import java.util.Collections; @@ -45,6 +46,11 @@ public UnionIoTDBPipePattern(final IoTDBPipePattern pattern) { this.patterns = Collections.singletonList(pattern); } + @TestOnly + public List getPatterns() { + return patterns; + } + //////////////////////////// Pipe Pattern Operations //////////////////////////// @Override diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/datastructure/pattern/WithExclusionIoTDBPipePattern.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/datastructure/pattern/WithExclusionIoTDBPipePattern.java index 51ee704e178f..b68f10b54dc6 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/datastructure/pattern/WithExclusionIoTDBPipePattern.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/datastructure/pattern/WithExclusionIoTDBPipePattern.java @@ -42,8 +42,6 @@ public WithExclusionIoTDBPipePattern( final IoTDBPipePatternOperations exclusionPattern) { this.inclusionPattern = inclusionPattern; this.exclusionPattern = exclusionPattern; - - PipePattern.checkAndLogPatternCoverage(inclusionPattern, exclusionPattern); } //////////////////////////// Pipe Pattern Operations //////////////////////////// diff --git a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/datastructure/pattern/WithExclusionPipePattern.java b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/datastructure/pattern/WithExclusionPipePattern.java index b2e914347e6e..5a10613c8f25 100644 --- a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/datastructure/pattern/WithExclusionPipePattern.java +++ b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/pipe/datastructure/pattern/WithExclusionPipePattern.java @@ -39,8 +39,6 @@ public WithExclusionPipePattern( final PipePattern inclusionPattern, final PipePattern exclusionPattern) { this.inclusionPattern = inclusionPattern; this.exclusionPattern = exclusionPattern; - - PipePattern.checkAndLogPatternCoverage(inclusionPattern, exclusionPattern); } @Override