Copilot commented on code in PR #17304:
URL: https://github.com/apache/iotdb/pull/17304#discussion_r2944868403


##########
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/queryengine/execution/operator/OperatorContext.java:
##########
@@ -177,7 +176,7 @@ public void recordSpecifiedInfo(String key, String value) {
   }
 
   public Map<String, String> getSpecifiedInfo() {
-    return specifiedInfo == null ? new HashMap<>() : specifiedInfo;
+    return specifiedInfo == null ? specifiedInfo = new ConcurrentHashMap<>() : 
specifiedInfo;
   }

Review Comment:
   `getSpecifiedInfo()` lazily initializes `specifiedInfo` via assignment 
inside a ternary. Since this map is accessed concurrently (as noted in 
`recordSpecifiedInfo`), this unsynchronized lazy init can still race and 
briefly create/lose maps (and it’s also hard to read). Prefer initializing 
`specifiedInfo` eagerly (e.g., final `ConcurrentHashMap`) or use a thread-safe 
lazy-init pattern (synchronized/AtomicReference) so all threads share the same 
map deterministically.



##########
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/datastructure/TVList.java:
##########
@@ -854,6 +857,10 @@ protected void skipToCurrentTimeRangeStartPosition() {
         }
         if (searchTimestamp > outer.getMaxTime()) {
           // all satisfied data has been consumed
+          // the data with same timestamp could exist multi times, which means 
filter multi times
+          if (this.getQueryContext().isVerbose()) {
+            
this.getQueryContext().getQueryStatistics().addFilteredRowsOfRowLevel(rows - 
index);
+          }

Review Comment:
   `queryContext` can be null (e.g., iterators created for flushing/encoding 
pass null via MemPointIteratorFactory), but this code calls 
`getQueryContext().isVerbose()` unconditionally, which can trigger a 
NullPointerException during `hasNextTimeValuePair()/prepareNext()` and 
`nextBatch()`. Make the verbose/statistics recording null-safe (check 
`queryContext != null` before dereferencing) or ensure a non-null QueryContext 
is always provided.



##########
integration-test/src/test/java/org/apache/iotdb/relational/it/query/recent/IoTDBTableFilteredRowsIT.java:
##########
@@ -0,0 +1,200 @@
+package org.apache.iotdb.relational.it.query.recent;
+
+/**
+ * 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
+ *
+ * <p>http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * <p>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.
+ */
+import org.apache.iotdb.isession.ITableSession;
+import org.apache.iotdb.isession.SessionDataSet;
+import org.apache.iotdb.it.env.EnvFactory;
+import org.apache.iotdb.it.framework.IoTDBTestRunner;
+import org.apache.iotdb.itbase.category.TableClusterIT;
+import org.apache.iotdb.itbase.category.TableLocalStandaloneIT;
+import org.apache.iotdb.rpc.IoTDBConnectionException;
+import org.apache.iotdb.rpc.StatementExecutionException;
+
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.write.record.Tablet;
+import org.apache.tsfile.write.schema.IMeasurementSchema;
+import org.apache.tsfile.write.schema.MeasurementSchema;
+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.util.Arrays;
+import java.util.List;
+import java.util.stream.Collectors;
+
+import static org.junit.Assert.assertEquals;
+
+@RunWith(IoTDBTestRunner.class)
+@Category({TableLocalStandaloneIT.class, TableClusterIT.class})
+public class IoTDBTableFilteredRowsIT {
+
+  private static final String TABLE_DATABASE = "filter_info";
+  private static final int max_number_of_points_in_page = 10;
+  private static final String DEVICE1 = "device1";
+  private static final List<String> targetKeys =
+      Arrays.asList(
+          "timeSeriesIndexFilteredRows",
+          "chunkIndexFilteredRows",
+          "pageIndexFilteredRows",
+          "rowScanFilteredRows");

Review Comment:
   Constant names should follow Java constant conventions (UPPER_SNAKE_CASE). 
Rename `max_number_of_points_in_page` (and similarly `targetKeys`) to 
`MAX_NUMBER_OF_POINTS_IN_PAGE` / `TARGET_KEYS` (and update references) to avoid 
style/checkstyle violations.



##########
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/datastructure/MultiTVListIterator.java:
##########
@@ -235,6 +252,13 @@ public TsBlock nextBatch() {
         throw new UnSupportedDataTypeException(
             String.format("Data type %s is not supported.", tsDataType));
     }
+
+    if (this.getQueryContext().isVerbose() && filteredRowsByPushDownFilter > 
0) {
+      this.getQueryContext()
+          .getQueryStatistics()
+          .addFilteredRowsOfRowLevel(filteredRowsByPushDownFilter);
+    }

Review Comment:
   `getQueryContext()` may be null (e.g., WritableMemChunk encoding path passes 
null into MemPointIteratorFactory), but this code calls 
`getQueryContext().isVerbose()` unconditionally, which can cause an NPE. Guard 
the verbose/statistics path with a null-check or ensure callers always pass a 
non-null QueryContext.



##########
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/datastructure/MultiAlignedTVListIterator.java:
##########
@@ -269,13 +274,18 @@ public TsBlock nextBatch() {
     }
     TsBlock tsBlock = builder.build();
     if (pushDownFilter != null) {
+      Consumer<Long> filterRowsRecorder =
+          this.getQueryContext().isVerbose()
+              ? s -> 
this.getQueryContext().getQueryStatistics().addFilteredRowsOfRowLevel(s)
+              : null;

Review Comment:
   `getQueryContext()` can be null (e.g., iterator used for memchunk 
flush/encode is created with null context), but `getQueryContext().isVerbose()` 
is called unconditionally here, which can throw a NullPointerException. Make 
the recorder creation null-safe (e.g., treat null as non-verbose).



##########
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/WritableMemChunk.java:
##########
@@ -487,7 +487,7 @@ public void encode(BlockingQueue<Object> ioTaskQueue, 
BatchEncodeInfo encodeInfo
     tvLists.add(workingListForFlush);
     MemPointIterator timeValuePairIterator =
         MemPointIteratorFactory.create(
-            schema.getType(), tvLists, encodeInfo.maxNumberOfPointsInPage);
+            schema.getType(), tvLists, encodeInfo.maxNumberOfPointsInPage, 
null);

Review Comment:
   This creates a MemPointIterator with `queryContext` = null, but the updated 
iterators now dereference `getQueryContext().isVerbose()` in multiple code 
paths (e.g., TVListIterator.prepareNext/nextBatch), which can crash 
flushing/encoding with NPE. Pass a non-null QueryContext (with verbose=false) 
or update iterators to handle null contexts safely.



##########
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/read/reader/chunk/MemPageReader.java:
##########
@@ -137,13 +142,18 @@ public TsBlock getAllSatisfiedData() {
     return builder.build();
   }
 
-  private boolean[] buildSatisfyInfoArray() {
+  private boolean[] buildSatisfyInfoArray(Consumer<Long> filterRowsRecorder) {
     if (recordFilter == null || recordFilter.allSatisfy(this)) {
       boolean[] satisfyInfo = new boolean[tsBlock.getPositionCount()];
       Arrays.fill(satisfyInfo, true);
       return satisfyInfo;
     }
-    return recordFilter.satisfyTsBlock(tsBlock);
+
+    boolean[] selection = new boolean[tsBlock.getPositionCount()];
+    Arrays.fill(selection, true);
+    return filterRowsRecorder == null
+        ? recordFilter.satisfyTsBlock(tsBlock)
+        : recordFilter.satisfyTsBlock(selection, tsBlock, filterRowsRecorder);

Review Comment:
   `buildSatisfyInfoArray` allocates and fills a `selection` array even when 
`filterRowsRecorder` is null, but in that branch the array is unused 
(`recordFilter.satisfyTsBlock(tsBlock)` is called). Avoid allocating 
`selection` unless the recorder is non-null to reduce per-page overhead.



##########
iotdb-core/datanode/src/main/java/org/apache/iotdb/db/storageengine/dataregion/memtable/AlignedWritableMemChunk.java:
##########
@@ -800,7 +800,8 @@ public void encode(BlockingQueue<Object> ioTaskQueue, 
BatchEncodeInfo encodeInfo
             columnIndexList,
             alignedTvLists,
             ignoreAllNullRows,
-            encodeInfo.maxNumberOfPointsInPage);
+            encodeInfo.maxNumberOfPointsInPage,
+            null);

Review Comment:
   This creates an aligned MemPointIterator with `queryContext` = null. After 
the iterator changes, several iterator implementations call 
`getQueryContext().isVerbose()` without null-checks, so the encode/flush path 
may throw NPE. Pass a non-null QueryContext (verbose=false) or make iterator 
code null-safe.



##########
iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/read/reader/chunk/MemAlignedChunkLoaderTest.java:
##########
@@ -116,7 +116,7 @@ public void testMemAlignedChunkLoader() throws IOException {
         alignedTvListMap.keySet().stream().map(x -> (AlignedTVList) 
x).collect(Collectors.toList());
     MemPointIterator timeValuePairIterator =
         MemPointIteratorFactory.create(
-            dataTypes, null, alignedTvLists, false, maxNumberOfPointsInPage);
+            dataTypes, null, alignedTvLists, false, maxNumberOfPointsInPage, 
null);
     timeValuePairIterator.setStreamingQueryMemChunk(false);

Review Comment:
   This test passes `null` as the QueryContext to MemPointIteratorFactory. With 
the new verbose/statistics logic, some iterator implementations call 
`getQueryContext().isVerbose()` and will NPE when `nextBatch()` is invoked. 
Pass a real QueryContext (e.g., `ctx`) instead of null to keep the test 
representative and non-flaky.



##########
integration-test/src/test/java/org/apache/iotdb/relational/it/query/recent/IoTDBTableFilteredRowsIT.java:
##########
@@ -0,0 +1,200 @@
+package org.apache.iotdb.relational.it.query.recent;
+
+/**
+ * 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
+ *
+ * <p>http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * <p>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.
+ */

Review Comment:
   The ASF license header should be the first content in the file (before the 
`package` declaration). Move the license comment block above the `package` line 
to match the repository’s standard header placement and avoid 
license/checkstyle issues.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to