You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@iotdb.apache.org by sh...@apache.org on 2026/08/04 04:27:35 UTC

(iotdb) branch fix/synchronize-tvlist-delete-with-sort-dev1.3 created (now f3481a315fd)

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

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


      at f3481a315fd Fix IndexOutOfBoundsException caused by concurrent sort and delete on TVList

This branch includes the following new commits:

     new f3481a315fd Fix IndexOutOfBoundsException caused by concurrent sort and delete on TVList

The 1 revisions listed above as "new" are entirely new to this
repository and will be described in separate emails.  The revisions
listed as "add" were already present in the repository and have only
been added to this reference.



(iotdb) 01/01: Fix IndexOutOfBoundsException caused by concurrent sort and delete on TVList

Posted by sh...@apache.org.
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 <s1...@gmail.com>
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;