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

CritasWang pushed a commit to branch wx/iotdb-2.0.11-alignment
in repository https://gitbox.apache.org/repos/asf/iotdb-extras.git

commit 4f03d97753d1119384c2bbc6a5f7fa49741284ad
Author: CritasWang <[email protected]>
AuthorDate: Thu Sep 17 17:50:47 2026 +0800

    thingsboard: drop per-test databases and refresh 2.0.11 notes
    
    The container ITs provisioned a fresh database per test and never
    dropped it; on an 8 GB Docker host the DataNode ran out of region memory
    after about a dozen databases and later tests timed out on their first
    write. Track the databases each test creates and drop them afterwards.
    
    apache/iotdb#18300 (grouped MAX of non-positive floats) ships in 2.0.11,
    so the DAO comment no longer claims it is unreleased; the -MIN(-x)
    projection stays for older servers. Remaining 2.0.8 references in the
    README and migration guide now name the verified 2.0.11 behavior.
---
 iotdb-thingsboard-table/README.md                  |  2 +-
 iotdb-thingsboard-table/docs/migration-guide.md    |  4 +--
 .../thingsboard/table/IoTDBTableTimeseriesDao.java | 40 +++++++++++-----------
 .../table/IoTDBTableAttributesDaoIT.java           | 20 ++++++++++-
 .../table/IoTDBTableIngestionBenchmarkIT.java      | 20 ++++++++++-
 .../thingsboard/table/IoTDBTableLatestDaoIT.java   | 20 ++++++++++-
 .../table/IoTDBTableTimeseriesAggregationIT.java   | 20 ++++++++++-
 .../table/IoTDBTableTimeseriesDaoIT.java           | 20 ++++++++++-
 .../extras/thingsboard/table/IoTDBTableTtlIT.java  | 21 +++++++++++-
 9 files changed, 138 insertions(+), 29 deletions(-)

diff --git a/iotdb-thingsboard-table/README.md 
b/iotdb-thingsboard-table/README.md
index 777ae16..827f560 100644
--- a/iotdb-thingsboard-table/README.md
+++ b/iotdb-thingsboard-table/README.md
@@ -236,7 +236,7 @@ a retention window in **milliseconds**, and the accepted 
forms are narrow:
 | `TTL='INF'` | Never expire. The **quoted** string is the only accepted 
spelling; this is the form `entity_attributes` and `telemetry_latest` ship 
with. |
 | `TTL=DEFAULT` | Inherit the database default, which is `INF` on a fresh 
node. |
 
-Anything else is rejected by IoTDB 2.0.8: an unquoted `TTL=INF` is parsed as an
+Anything else is rejected by IoTDB 2.0.11 (and 2.0.8): an unquoted `TTL=INF` 
is parsed as an
 identifier (`ttl value must be a LongLiteral, but now is Identifier`), and any
 other quoted value — including a quoted number (`'604800000'`) or a duration
 (`'7d'`) — fails with `ttl value must be 'INF' or a long literal`.
diff --git a/iotdb-thingsboard-table/docs/migration-guide.md 
b/iotdb-thingsboard-table/docs/migration-guide.md
index ee46c9d..3fbba63 100644
--- a/iotdb-thingsboard-table/docs/migration-guide.md
+++ b/iotdb-thingsboard-table/docs/migration-guide.md
@@ -92,7 +92,7 @@ Notes:
 ## Before you begin
 
 - A reachable IoTDB 2.x server in **Table Mode** (the tested server is IoTDB
-  2.0.8). Have its host, port, and credentials ready.
+  2.0.11). Have its host, port, and credentials ready.
 - A ThingsBoard 4.3.1.2 build you control (the module is consumed as a
   compile/runtime dependency of the ThingsBoard application; it is not a
   drop-in for a pre-built binary distribution).
@@ -227,7 +227,7 @@ ALTER TABLE telemetry SET PROPERTIES TTL=DEFAULT;      -- 
back to the db default
 ```
 
 Quoted numbers (`'604800000'`) and duration forms (`'7d'`) are rejected by 
IoTDB
-2.0.8. The `telemetry_latest` overlay table is created `WITH (TTL='INF')` and 
is
+2.0.11 (and 2.0.8). The `telemetry_latest` overlay table is created `WITH 
(TTL='INF')` and is
 **exempt** from the `telemetry` TTL: setting a retention window on `telemetry`
 does not evict overlay rows, so bound the overlay separately if needed (see
 *Limitations*).
diff --git 
a/iotdb-thingsboard-table/src/main/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableTimeseriesDao.java
 
b/iotdb-thingsboard-table/src/main/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableTimeseriesDao.java
index 573e852..598639c 100644
--- 
a/iotdb-thingsboard-table/src/main/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableTimeseriesDao.java
+++ 
b/iotdb-thingsboard-table/src/main/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableTimeseriesDao.java
@@ -612,18 +612,17 @@ public class IoTDBTableTimeseriesDao extends 
IoTDBTableBaseDao
       // promote to DOUBLE. Project the partial long/double sums plus the 
long/double non-null
       // counts so the row mapper can pick the type without re-reading the raw 
rows.
       case SUM ->
-          // IoTDB 2.0.8 computes SUM over an INT64 column with a DOUBLE 
accumulator and returns a
-          // DOUBLE. Project the long partial as SUM(CAST(long_v AS DOUBLE)) 
-- a plain DOUBLE --
-          // and
-          // NEVER cast it back to INT64 in SQL: CAST(SUM(long_v) AS INT64) 
THROWS a "Double value
-          // out of range of long value" error at the IoTDB level when the 
long-only sum exceeds
-          // Long.MAX, which would fail the whole aggregate query before the 
Java
-          // bound-check/fallback
-          // could run. The DOUBLE accumulator only keeps the sum bit-exact 
while every partial sum
-          // stays within +/-2^53, so the row mapper reads 
MIN(long_v)/MAX(long_v) to bound the sum,
-          // returns the DOUBLE cast back to long (lossless within the bound) 
for the provably-exact
-          // long-only case, and falls back to an exact Java re-sum when the 
bound exceeds 2^53 (see
-          // aggregatedSumEntry). The double partial stays DOUBLE.
+          // IoTDB (verified on 2.0.8 and 2.0.11) computes SUM over an INT64 
column with a DOUBLE
+          // accumulator and returns a DOUBLE. Project the long partial as
+          // SUM(CAST(long_v AS DOUBLE)) -- a plain DOUBLE -- and NEVER cast 
it back to INT64 in
+          // SQL: CAST(SUM(long_v) AS INT64) THROWS a "Double value out of 
range of long value"
+          // error at the IoTDB level when the long-only sum exceeds Long.MAX, 
which would fail
+          // the whole aggregate query before the Java bound-check/fallback 
could run. The DOUBLE
+          // accumulator only keeps the sum bit-exact while every partial sum 
stays within
+          // +/-2^53, so the row mapper reads MIN(long_v)/MAX(long_v) to bound 
the sum, returns
+          // the DOUBLE cast back to long (lossless within the bound) for the 
provably-exact
+          // long-only case, and falls back to an exact Java re-sum when the 
bound exceeds 2^53
+          // (see aggregatedSumEntry). The double partial stays DOUBLE.
           "SUM(CAST(long_v AS DOUBLE)) AS "
               + SUM_LONG_COLUMN
               + ", SUM(double_v) AS "
@@ -660,14 +659,15 @@ public class IoTDBTableTimeseriesDao extends 
IoTDBTableBaseDao
       // `value >= state`, so a bucket whose numeric maximum is zero or 
negative comes back
       // NULL. This DAO reads a NULL aggregate as "empty bucket" and skips it, 
so a MAX
       // downsampling query over e.g. a sub-zero sensor would silently lose 
whole buckets
-      // instead of failing. Every release up to and including 2.0.10 is 
affected; fixed on
-      // master by apache/iotdb#18300, which is not in a released version yet. 
The grouped MIN
-      // accumulator seeds with MAX_VALUE and is not affected, and IEEE-754 
negation is exact,
-      // so -MIN(-x) is an exact substitute for MAX(x) over finite values, on 
affected and
-      // fixed servers alike. This projection is shared with the calendar 
path, whose
-      // non-grouped accumulators track an explicit initialized flag rather 
than a sentinel, so
-      // the substitution is exact there too and an empty bucket still yields 
NULL. MAX(long_v)
-      // and MAX(str_v) are already correct (true Long.MIN_VALUE seed / 
flag-based) and stay.
+      // instead of failing. Every release up to and including 2.0.10 is 
affected; the fix
+      // (apache/iotdb#18300) ships in 2.0.11. The substitution is kept 
because the pool can be
+      // pointed at any 2.x server: the grouped MIN accumulator seeds with 
MAX_VALUE and is not
+      // affected, and IEEE-754 negation is exact, so -MIN(-x) is an exact 
substitute for MAX(x)
+      // over finite values, on affected and fixed servers alike. This 
projection is shared with
+      // the calendar path, whose non-grouped accumulators track an explicit 
initialized flag
+      // rather than a sentinel, so the substitution is exact there too and an 
empty bucket still
+      // yields NULL. MAX(long_v) and MAX(str_v) are already correct (true 
Long.MIN_VALUE seed /
+      // flag-based) and stay.
       case MAX ->
           "-1 * MIN(-1 * ("
               + NUMERIC_VALUE
diff --git 
a/iotdb-thingsboard-table/src/test/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableAttributesDaoIT.java
 
b/iotdb-thingsboard-table/src/test/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableAttributesDaoIT.java
index 16c1c4b..a0baddc 100644
--- 
a/iotdb-thingsboard-table/src/test/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableAttributesDaoIT.java
+++ 
b/iotdb-thingsboard-table/src/test/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableAttributesDaoIT.java
@@ -25,6 +25,7 @@ import org.apache.iotdb.session.pool.TableSessionPoolBuilder;
 
 import com.google.common.util.concurrent.ListenableFuture;
 import org.apache.commons.lang3.tuple.Pair;
+import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Tag;
 import org.junit.jupiter.api.Test;
 import org.testcontainers.containers.GenericContainer;
@@ -69,6 +70,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 @Tag("integration")
 @Testcontainers(disabledWithoutDocker = true)
 class IoTDBTableAttributesDaoIT {
+  private final List<String> createdDatabases = new ArrayList<>();
   // Cold testcontainer first writes/reads are slower than a warm production 
node, so the
   // per-future assertion timeout is generous.
   private static final int FUTURE_TIMEOUT_SECONDS = 30;
@@ -638,12 +640,28 @@ class IoTDBTableAttributesDaoIT {
         new TestEntityId(UUID.fromString(entityId), EntityType.DEVICE));
   }
 
+  @AfterEach
+  void dropCreatedDatabases() throws Exception {
+    // Every test provisions its own database. Drop them once the test is 
done: the shared
+    // container has a fixed region memory budget, and leaving dozens of 
databases behind makes
+    // later tests in the class fail schema-region creation ("Total allocated 
memory for direct
+    // buffer ... is greater than limit mem cost") and time out on their first 
write.
+    try (ITableSessionPool pool = newPool(null);
+        ITableSession session = pool.getSession()) {
+      for (String database : createdDatabases) {
+        session.executeNonQueryStatement("DROP DATABASE IF EXISTS " + 
database);
+      }
+    }
+  }
+
   private String uniqueDatabase(String prefix) {
     // IoTDB caps database names at 64 chars; keep the per-test prefix short 
and append a trimmed
     // UUID so the total length stays well within the limit.
     String shortPrefix = prefix.length() > 12 ? prefix.substring(0, 12) : 
prefix;
     String shortUuid = UUID.randomUUID().toString().replace("-", 
"").substring(0, 16);
-    return "tb_at_" + shortPrefix + "_" + shortUuid;
+    String database = "tb_at_" + shortPrefix + "_" + shortUuid;
+    createdDatabases.add(database);
+    return database;
   }
 
   private TestAttributeKvEntry attr(long lastUpdateTs, String key, KvEntry 
value) {
diff --git 
a/iotdb-thingsboard-table/src/test/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableIngestionBenchmarkIT.java
 
b/iotdb-thingsboard-table/src/test/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableIngestionBenchmarkIT.java
index 2ba0261..e0187b0 100644
--- 
a/iotdb-thingsboard-table/src/test/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableIngestionBenchmarkIT.java
+++ 
b/iotdb-thingsboard-table/src/test/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableIngestionBenchmarkIT.java
@@ -24,6 +24,7 @@ import org.apache.iotdb.isession.pool.ITableSessionPool;
 import org.apache.iotdb.session.pool.TableSessionPoolBuilder;
 
 import com.google.common.util.concurrent.ListenableFuture;
+import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Tag;
 import org.junit.jupiter.api.Test;
 import org.slf4j.Logger;
@@ -79,6 +80,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 @Tag("integration")
 @Testcontainers(disabledWithoutDocker = true)
 class IoTDBTableIngestionBenchmarkIT {
+  private final List<String> createdDatabases = new ArrayList<>();
   private static final Logger LOG = 
LoggerFactory.getLogger(IoTDBTableIngestionBenchmarkIT.class);
 
   // Smoke sizing: concurrency mirrors the TC-1 design (50 concurrent threads) 
but the total row
@@ -402,10 +404,26 @@ class IoTDBTableIngestionBenchmarkIT {
         uniqueDatabase(), new 
TenantId(UUID.fromString("55555555-5555-5555-5555-555555555501")));
   }
 
+  @AfterEach
+  void dropCreatedDatabases() throws Exception {
+    // Every test provisions its own database. Drop them once the test is 
done: the shared
+    // container has a fixed region memory budget, and leaving dozens of 
databases behind makes
+    // later tests in the class fail schema-region creation ("Total allocated 
memory for direct
+    // buffer ... is greater than limit mem cost") and time out on their first 
write.
+    try (ITableSessionPool pool = newPool(null);
+        ITableSession session = pool.getSession()) {
+      for (String database : createdDatabases) {
+        session.executeNonQueryStatement("DROP DATABASE IF EXISTS " + 
database);
+      }
+    }
+  }
+
   private String uniqueDatabase() {
     // IoTDB caps database names at 64 chars; keep the prefix short and append 
a trimmed UUID.
     String shortUuid = UUID.randomUUID().toString().replace("-", 
"").substring(0, 16);
-    return "tb_bench_tc1_" + shortUuid;
+    String database = "tb_bench_tc1_" + shortUuid;
+    createdDatabases.add(database);
+    return database;
   }
 
   private static java.util.concurrent.ThreadFactory saverThreadFactory() {
diff --git 
a/iotdb-thingsboard-table/src/test/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableLatestDaoIT.java
 
b/iotdb-thingsboard-table/src/test/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableLatestDaoIT.java
index cc00b4a..880ea2a 100644
--- 
a/iotdb-thingsboard-table/src/test/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableLatestDaoIT.java
+++ 
b/iotdb-thingsboard-table/src/test/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableLatestDaoIT.java
@@ -24,6 +24,7 @@ import org.apache.iotdb.isession.pool.ITableSessionPool;
 import org.apache.iotdb.session.pool.TableSessionPoolBuilder;
 
 import com.google.common.util.concurrent.ListenableFuture;
+import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Tag;
 import org.junit.jupiter.api.Test;
 import org.testcontainers.containers.GenericContainer;
@@ -64,6 +65,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 @Tag("integration")
 @Testcontainers(disabledWithoutDocker = true)
 class IoTDBTableLatestDaoIT {
+  private final List<String> createdDatabases = new ArrayList<>();
   // Cold testcontainer first writes/reads are slower than a warm production 
node, so the
   // per-future assertion timeout is generous; production throughput is 
covered elsewhere.
   private static final int FUTURE_TIMEOUT_SECONDS = 30;
@@ -1098,12 +1100,28 @@ class IoTDBTableLatestDaoIT {
         new TestEntityId(UUID.fromString(entityId), EntityType.DEVICE));
   }
 
+  @AfterEach
+  void dropCreatedDatabases() throws Exception {
+    // Every test provisions its own database. Drop them once the test is 
done: the shared
+    // container has a fixed region memory budget, and leaving dozens of 
databases behind makes
+    // later tests in the class fail schema-region creation ("Total allocated 
memory for direct
+    // buffer ... is greater than limit mem cost") and time out on their first 
write.
+    try (ITableSessionPool pool = newPool(null);
+        ITableSession session = pool.getSession()) {
+      for (String database : createdDatabases) {
+        session.executeNonQueryStatement("DROP DATABASE IF EXISTS " + 
database);
+      }
+    }
+  }
+
   private String uniqueDatabase(String prefix) {
     // IoTDB caps database names at 64 chars; keep the per-test prefix short 
and append a trimmed
     // UUID so the total length stays well within the limit.
     String shortPrefix = prefix.length() > 12 ? prefix.substring(0, 12) : 
prefix;
     String shortUuid = UUID.randomUUID().toString().replace("-", 
"").substring(0, 16);
-    return "tb_lt_" + shortPrefix + "_" + shortUuid;
+    String database = "tb_lt_" + shortPrefix + "_" + shortUuid;
+    createdDatabases.add(database);
+    return database;
   }
 
   private TestTsKvEntry entry(long ts, String key, DataType dataType, Object 
value) {
diff --git 
a/iotdb-thingsboard-table/src/test/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableTimeseriesAggregationIT.java
 
b/iotdb-thingsboard-table/src/test/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableTimeseriesAggregationIT.java
index 97bc1ff..4bf100d 100644
--- 
a/iotdb-thingsboard-table/src/test/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableTimeseriesAggregationIT.java
+++ 
b/iotdb-thingsboard-table/src/test/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableTimeseriesAggregationIT.java
@@ -23,6 +23,7 @@ import org.apache.iotdb.isession.pool.ITableSessionPool;
 import org.apache.iotdb.session.pool.TableSessionPoolBuilder;
 
 import com.google.common.util.concurrent.ListenableFuture;
+import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Tag;
 import org.junit.jupiter.api.Test;
 import org.testcontainers.containers.GenericContainer;
@@ -67,6 +68,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 @Tag("integration")
 @Testcontainers(disabledWithoutDocker = true)
 class IoTDBTableTimeseriesAggregationIT {
+  private final List<String> createdDatabases = new ArrayList<>();
   private static final int FUTURE_TIMEOUT_SECONDS = 30;
   private static final Duration IOTDB_STARTUP_TIMEOUT = Duration.ofMinutes(3);
   private static final Duration IOTDB_READY_TIMEOUT = Duration.ofSeconds(60);
@@ -1111,10 +1113,26 @@ class IoTDBTableTimeseriesAggregationIT {
         new TestEntityId(UUID.fromString(entityId), EntityType.DEVICE));
   }
 
+  @AfterEach
+  void dropCreatedDatabases() throws Exception {
+    // Every test provisions its own database. Drop them once the test is 
done: the shared
+    // container has a fixed region memory budget, and leaving dozens of 
databases behind makes
+    // later tests in the class fail schema-region creation ("Total allocated 
memory for direct
+    // buffer ... is greater than limit mem cost") and time out on their first 
write.
+    try (ITableSessionPool pool = newPool(null);
+        ITableSession session = pool.getSession()) {
+      for (String database : createdDatabases) {
+        session.executeNonQueryStatement("DROP DATABASE IF EXISTS " + 
database);
+      }
+    }
+  }
+
   private String uniqueDatabase(String prefix) {
     String shortPrefix = prefix.length() > 12 ? prefix.substring(0, 12) : 
prefix;
     String shortUuid = UUID.randomUUID().toString().replace("-", 
"").substring(0, 16);
-    return "tb_it_" + shortPrefix + "_" + shortUuid;
+    String database = "tb_it_" + shortPrefix + "_" + shortUuid;
+    createdDatabases.add(database);
+    return database;
   }
 
   private TestTsKvEntry entry(long ts, String key, DataType dataType, Object 
value) {
diff --git 
a/iotdb-thingsboard-table/src/test/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableTimeseriesDaoIT.java
 
b/iotdb-thingsboard-table/src/test/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableTimeseriesDaoIT.java
index 355fc4e..cc9bf77 100644
--- 
a/iotdb-thingsboard-table/src/test/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableTimeseriesDaoIT.java
+++ 
b/iotdb-thingsboard-table/src/test/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableTimeseriesDaoIT.java
@@ -25,6 +25,7 @@ import org.apache.iotdb.session.pool.TableSessionPoolBuilder;
 
 import com.google.common.util.concurrent.ListenableFuture;
 import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.BeforeAll;
 import org.junit.jupiter.api.Tag;
 import org.junit.jupiter.api.Test;
@@ -67,6 +68,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 @Tag("integration")
 @Testcontainers(disabledWithoutDocker = true)
 class IoTDBTableTimeseriesDaoIT {
+  private final List<String> createdDatabases = new ArrayList<>();
   // Cold testcontainer first writes are slower than a warm production node, 
so the per-future
   // assertion timeout is generous; production throughput is covered 
elsewhere, not here.
   private static final int FUTURE_TIMEOUT_SECONDS = 30;
@@ -630,12 +632,28 @@ class IoTDBTableTimeseriesDaoIT {
         new TestEntityId(UUID.fromString(entityId), EntityType.DEVICE));
   }
 
+  @AfterEach
+  void dropCreatedDatabases() throws Exception {
+    // Every test provisions its own database. Drop them once the test is 
done: the shared
+    // container has a fixed region memory budget, and leaving dozens of 
databases behind makes
+    // later tests in the class fail schema-region creation ("Total allocated 
memory for direct
+    // buffer ... is greater than limit mem cost") and time out on their first 
write.
+    try (ITableSessionPool pool = newPool(null);
+        ITableSession session = pool.getSession()) {
+      for (String database : createdDatabases) {
+        session.executeNonQueryStatement("DROP DATABASE IF EXISTS " + 
database);
+      }
+    }
+  }
+
   private String uniqueDatabase(String prefix) {
     // IoTDB caps database names at 64 chars; keep the per-test prefix short 
and
     // append a trimmed UUID so the total length stays well within the limit.
     String shortPrefix = prefix.length() > 12 ? prefix.substring(0, 12) : 
prefix;
     String shortUuid = UUID.randomUUID().toString().replace("-", 
"").substring(0, 16);
-    return "tb_it_" + shortPrefix + "_" + shortUuid;
+    String database = "tb_it_" + shortPrefix + "_" + shortUuid;
+    createdDatabases.add(database);
+    return database;
   }
 
   private int assertTelemetryRows(
diff --git 
a/iotdb-thingsboard-table/src/test/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableTtlIT.java
 
b/iotdb-thingsboard-table/src/test/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableTtlIT.java
index 6fa7fb6..fde0ac7 100644
--- 
a/iotdb-thingsboard-table/src/test/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableTtlIT.java
+++ 
b/iotdb-thingsboard-table/src/test/java/org/apache/iotdb/extras/thingsboard/table/IoTDBTableTtlIT.java
@@ -23,6 +23,7 @@ import org.apache.iotdb.isession.SessionDataSet;
 import org.apache.iotdb.isession.pool.ITableSessionPool;
 import org.apache.iotdb.session.pool.TableSessionPoolBuilder;
 
+import org.junit.jupiter.api.AfterEach;
 import org.junit.jupiter.api.Tag;
 import org.junit.jupiter.api.Test;
 import org.testcontainers.containers.GenericContainer;
@@ -34,6 +35,7 @@ import org.testcontainers.utility.DockerImageName;
 import java.io.InputStream;
 import java.nio.charset.StandardCharsets;
 import java.time.Duration;
+import java.util.ArrayList;
 import java.util.List;
 import java.util.UUID;
 import java.util.concurrent.TimeUnit;
@@ -61,6 +63,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue;
 @Tag("integration")
 @Testcontainers(disabledWithoutDocker = true)
 class IoTDBTableTtlIT {
+  private final List<String> createdDatabases = new ArrayList<>();
   private static final Duration IOTDB_STARTUP_TIMEOUT = Duration.ofMinutes(3);
   private static final Duration IOTDB_READY_TIMEOUT = Duration.ofSeconds(60);
   private static final Duration IOTDB_READY_POLL_INTERVAL = 
Duration.ofMillis(500);
@@ -210,9 +213,25 @@ class IoTDBTableTtlIT {
         "IoTDB did not accept table-session statements within " + 
IOTDB_READY_TIMEOUT, lastFailure);
   }
 
+  @AfterEach
+  void dropCreatedDatabases() throws Exception {
+    // Every test provisions its own database. Drop them once the test is 
done: the shared
+    // container has a fixed region memory budget, and leaving dozens of 
databases behind makes
+    // later tests in the class fail schema-region creation ("Total allocated 
memory for direct
+    // buffer ... is greater than limit mem cost") and time out on their first 
write.
+    try (ITableSessionPool pool = newPool(null);
+        ITableSession session = pool.getSession()) {
+      for (String database : createdDatabases) {
+        session.executeNonQueryStatement("DROP DATABASE IF EXISTS " + 
database);
+      }
+    }
+  }
+
   private String uniqueDatabase(String prefix) {
     String shortPrefix = prefix.length() > 12 ? prefix.substring(0, 12) : 
prefix;
     String shortUuid = UUID.randomUUID().toString().replace("-", 
"").substring(0, 16);
-    return "tb_it_" + shortPrefix + "_" + shortUuid;
+    String database = "tb_it_" + shortPrefix + "_" + shortUuid;
+    createdDatabases.add(database);
+    return database;
   }
 }

Reply via email to