This is an automated email from the ASF dual-hosted git repository.

shuwenwei pushed a commit to branch 
fix/synchronize-tvlist-delete-with-sort-dev1.3
in repository https://gitbox.apache.org/repos/asf/iotdb.git

commit f3481a315fd10ac144b2a003a5485a1929b69abc
Author: shuwenwei <[email protected]>
AuthorDate: Tue Aug 4 10:55:00 2026 +0800

    Fix IndexOutOfBoundsException caused by concurrent sort and delete on TVList
    
    A query may sort the shared working TVList in place while a DELETE is
    running on the same list. sort() is synchronized, but the delete methods
    (AlignedTVList.delete/deleteTime/delete(column)/deleteColumn and
    TVList.delete) were not, so the delete thread could observe the
    half-rebuilt indices during sort and throw IndexOutOfBoundsException
    ("Index 0 out of bounds for length 0") or silently delete wrong rows.
    
    Synchronize the delete methods with sort() on the same TVList instance,
    consistent with putAlignedValue/clone/cloneForFlushSort which are already
    synchronized. The runtime delete path always holds
    TsFileProcessor.flushQueryLock.writeLock() before touching the TVList, so
    the lock order (flushQueryLock -> tvlist monitor) stays consistent with
    the query path and no deadlock is introduced.
---
 .../db/utils/datastructure/AlignedTVList.java      | 23 +++++++++++++++++++---
 .../iotdb/db/utils/datastructure/TVList.java       |  8 +++++++-
 2 files changed, 27 insertions(+), 4 deletions(-)

diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/datastructure/AlignedTVList.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/datastructure/AlignedTVList.java
index 9e3a556710c..591c91a6640 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/datastructure/AlignedTVList.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/datastructure/AlignedTVList.java
@@ -539,7 +539,13 @@ public abstract class AlignedTVList extends TVList {
   }
 
   @Override
-  public int delete(long lowerBound, long upperBound) {
+  /*
+   * Must be synchronized with sort() on the same TVList instance: a query may 
sort
+   * this list in place (sort() is synchronized), and a concurrent delete would
+   * otherwise read the half-rebuilt indices and throw 
IndexOutOfBoundsException
+   * or delete wrong rows.
+   */
+  public synchronized int delete(long lowerBound, long upperBound) {
     int deletedNumber = 0;
     for (int i = 0; i < dataTypes.size(); i++) {
       deletedNumber += delete(lowerBound, upperBound, i).left;
@@ -550,12 +556,17 @@ public abstract class AlignedTVList extends TVList {
   /**
    * Delete points in a specific column.
    *
+   * <p>Must be synchronized with {@link #sort()} on the same TVList instance: 
a query may sort this
+   * list in place ({@code sort()} is synchronized), and a concurrent delete 
would otherwise read
+   * the half-rebuilt {@code indices} and throw IndexOutOfBoundsException or 
delete wrong rows.
+   *
    * @param lowerBound deletion lower bound
    * @param upperBound deletion upper bound
    * @param columnIndex column index to be deleted
    * @return Delete info pair. Left: deletedNumber int; right: ifDeleteColumn 
boolean
    */
-  public Pair<Integer, Boolean> delete(long lowerBound, long upperBound, int 
columnIndex) {
+  public synchronized Pair<Integer, Boolean> delete(
+      long lowerBound, long upperBound, int columnIndex) {
     if (columnIndex >= values.size()) {
       return new Pair<>(0, false);
     }
@@ -577,7 +588,13 @@ public abstract class AlignedTVList extends TVList {
     return new Pair<>(deletedNumber, deleteColumn);
   }
 
-  public void deleteColumn(int columnIndex) {
+  /*
+   * Must be synchronized with sort() on the same TVList instance: a query may 
sort
+   * this list in place (sort() is synchronized), and a concurrent delete would
+   * otherwise read the half-rebuilt indices and throw 
IndexOutOfBoundsException
+   * or delete wrong rows.
+   */
+  public synchronized void deleteColumn(int columnIndex) {
     if (bitMaps == null) {
       List<List<BitMap>> localBitMaps = new ArrayList<>(dataTypes.size());
       for (int j = 0; j < dataTypes.size(); j++) {
diff --git 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/datastructure/TVList.java
 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/datastructure/TVList.java
index d21ecc83e0f..220ca87a9a8 100644
--- 
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/datastructure/TVList.java
+++ 
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/utils/datastructure/TVList.java
@@ -558,7 +558,13 @@ public abstract class TVList implements WALEntryValue {
     return clone();
   }
 
-  public int delete(long lowerBound, long upperBound) {
+  /*
+   * Must be synchronized with sort() on the same TVList instance: a query may 
sort
+   * this list in place (sort() is synchronized), and a concurrent delete would
+   * otherwise read the half-rebuilt indices and throw 
IndexOutOfBoundsException
+   * or delete wrong rows.
+   */
+  public synchronized int delete(long lowerBound, long upperBound) {
     int deletedNumber = 0;
     long maxTime = Long.MIN_VALUE;
     long minTime = Long.MAX_VALUE;

Reply via email to