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 02:55:25 UTC
(iotdb) 01/01: Fix IndexOutOfBoundsException caused by concurrent sort and delete on TVList
This is an automated email from the ASF dual-hosted git repository.
shuwenwei pushed a commit to branch fix/synchronize-tvlist-delete-with-sort
in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit 6ea4c3e5e3d9631f8215a093fd5960f42e51e705
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 | 31 +++++++++++++++++++---
.../iotdb/db/utils/datastructure/TVList.java | 8 +++++-
2 files changed, 34 insertions(+), 5 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 a589e1ea97a..1e29d245756 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
@@ -642,7 +642,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;
@@ -650,7 +656,13 @@ public abstract class AlignedTVList extends TVList {
return deletedNumber;
}
- public int deleteTime(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 deleteTime(long lowerBound, long upperBound) {
delete(lowerBound, upperBound);
int prevDeletedCnt = this.timeDeletedCnt;
for (int i = 0; i < rowCount; i++) {
@@ -693,12 +705,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);
}
@@ -721,7 +738,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 3141ad3c8b4..9dbd11cf626 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
@@ -580,7 +580,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;