Skip to content

Commit d703886

Browse files
authored
[Bug fix] The partition table is cleaned incorrectly when set only device TTL for tree mode (#17123)
1 parent b6c7300 commit d703886

5 files changed

Lines changed: 129 additions & 6 deletions

File tree

integration-test/src/test/java/org/apache/iotdb/confignode/it/partition/IoTDBPartitionTableAutoCleanIT.java

Lines changed: 55 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ public class IoTDBPartitionTableAutoCleanIT {
5050

5151
private static final int TEST_REPLICATION_FACTOR = 1;
5252
private static final long TEST_TIME_PARTITION_INTERVAL = 604800000;
53-
private static final long TEST_TTL_CHECK_INTERVAL = 5_000;
53+
private static final long TEST_TTL_CHECK_INTERVAL_IN_MS = 5_00;
5454

5555
private static final TTimePartitionSlot TEST_CURRENT_TIME_SLOT =
5656
new TTimePartitionSlot()
@@ -68,7 +68,7 @@ public void setUp() throws Exception {
6868
.setSchemaReplicationFactor(TEST_REPLICATION_FACTOR)
6969
.setDataReplicationFactor(TEST_REPLICATION_FACTOR)
7070
.setTimePartitionInterval(TEST_TIME_PARTITION_INTERVAL)
71-
.setTTLCheckInterval(TEST_TTL_CHECK_INTERVAL);
71+
.setTTLCheckInterval(TEST_TTL_CHECK_INTERVAL_IN_MS);
7272

7373
// Init 1C1D environment
7474
EnvFactory.getEnv().initClusterEnvironment(1, 1);
@@ -135,6 +135,59 @@ public void testAutoCleanPartitionTableForTreeModel() throws Exception {
135135
Assert.fail("The PartitionTable in the ConfigNode is not auto cleaned!");
136136
}
137137

138+
@Test
139+
public void testAutoCleanTakesNoEffectsForTreeDeviceTTL() throws Exception {
140+
try (Connection connection = EnvFactory.getEnv().getConnection(BaseEnv.TREE_SQL_DIALECT);
141+
Statement statement = connection.createStatement()) {
142+
// Create databases and insert test data
143+
for (int i = 0; i < 3; i++) {
144+
String databaseName = String.format("%s%d", TREE_DATABASE_PREFIX, i);
145+
statement.execute(String.format("CREATE DATABASE %s", databaseName));
146+
statement.execute(
147+
String.format(
148+
"CREATE TIMESERIES %s.s WITH DATATYPE=INT64,ENCODING=PLAIN", databaseName));
149+
// Insert expired data
150+
statement.execute(
151+
String.format(
152+
"INSERT INTO %s(timestamp, s) VALUES (%d, %d)",
153+
databaseName, TEST_CURRENT_TIME_SLOT.getStartTime() - TEST_TTL * 2, -1));
154+
// Insert existed data
155+
statement.execute(
156+
String.format(
157+
"INSERT INTO %s(timestamp, s) VALUES (%d, %d)",
158+
databaseName, TEST_CURRENT_TIME_SLOT.getStartTime(), 1));
159+
// Create an empty device and set a TTL.
160+
// This TTL should not trigger the auto cleaner,
161+
// since the database does not have a TTL.
162+
statement.execute(
163+
String.format(
164+
"CREATE TIMESERIES %s.m.empty WITH DATATYPE=INT64,ENCODING=PLAIN", databaseName));
165+
statement.execute(String.format("SET TTL TO %s.m.** %d", databaseName, TEST_TTL));
166+
}
167+
}
168+
169+
TDataPartitionReq req = new TDataPartitionReq();
170+
for (int i = 0; i < 3; i++) {
171+
req.putToPartitionSlotsMap(String.format("%s%d", TREE_DATABASE_PREFIX, i), new TreeMap<>());
172+
}
173+
try (SyncConfigNodeIServiceClient client =
174+
(SyncConfigNodeIServiceClient) EnvFactory.getEnv().getLeaderConfigNodeConnection()) {
175+
for (int retry = 0; retry < 10; retry++) {
176+
// Ensure the partitions are not cleaned
177+
boolean partitionTableAutoCleaned = false;
178+
TDataPartitionTableResp resp = client.getDataPartitionTable(req);
179+
if (TSStatusCode.SUCCESS_STATUS.getStatusCode() == resp.getStatus().getCode()) {
180+
partitionTableAutoCleaned =
181+
resp.getDataPartitionTable().entrySet().stream()
182+
.flatMap(e1 -> e1.getValue().entrySet().stream())
183+
.allMatch(e2 -> e2.getValue().size() == 1);
184+
}
185+
Assert.assertFalse(partitionTableAutoCleaned);
186+
TimeUnit.SECONDS.sleep(1);
187+
}
188+
}
189+
}
190+
138191
@Test
139192
public void testAutoCleanPartitionTableForTableModel() throws Exception {
140193
try (final Connection connection =

iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/TTLManager.java

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,20 @@ public int getTTLCount() {
130130
return ttlInfo.getTTLCount();
131131
}
132132

133+
/**
134+
* Get the maximum ttl of the corresponding database level.
135+
*
136+
* @param database the path of the database.
137+
* @return the maximum ttl of the corresponding database level.
138+
*/
139+
public long getDatabaseLevelTTL(final String database) {
140+
final long ttl = ttlInfo.getDatabaseLevelTTL(database);
141+
return ttl == Long.MAX_VALUE || ttl < 0
142+
? ttl
143+
: CommonDateTimeUtils.convertMilliTimeWithPrecision(
144+
ttl, CommonDescriptor.getInstance().getConfig().getTimestampPrecision());
145+
}
146+
133147
/**
134148
* Get the maximum ttl of the subtree of the corresponding database.
135149
*

iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/persistence/TTLInfo.java

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,23 @@ public int getTTLCount() {
158158
}
159159
}
160160

161+
/**
162+
* Get the maximum ttl of the corresponding database level.
163+
*
164+
* @param database the path of the database.
165+
* @return the maximum ttl of the corresponding database level.
166+
*/
167+
public long getDatabaseLevelTTL(final String database) {
168+
lock.readLock().lock();
169+
try {
170+
return ttlCache.getDatabaseLevelTTL(database);
171+
} catch (IllegalPathException e) {
172+
return TTLCache.NULL_TTL;
173+
} finally {
174+
lock.readLock().unlock();
175+
}
176+
}
177+
161178
/**
162179
* Get the maximum ttl of the subtree of the corresponding database.
163180
*

iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/PartitionTableAutoCleaner.java

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -61,10 +61,20 @@ protected void periodicExecute(Env env) {
6161
List<String> databases = configManager.getClusterSchemaManager().getDatabaseNames(null);
6262
Map<String, Long> databaseTTLMap = new TreeMap<>();
6363
for (String database : databases) {
64-
long databaseTTL =
65-
PathUtils.isTableModelDatabase(database)
66-
? configManager.getClusterSchemaManager().getDatabaseMaxTTL(database)
67-
: configManager.getTTLManager().getDatabaseMaxTTL(database);
64+
long databaseTTL;
65+
if (PathUtils.isTableModelDatabase(database)) {
66+
// For table mode, the auto cleaner takes effect
67+
// when the maximum TTL among tables is less than Long.MAX_VALUE.
68+
// Because the database-level TTL do not affect data in table mode.
69+
databaseTTL = configManager.getClusterSchemaManager().getDatabaseMaxTTL(database);
70+
} else {
71+
databaseTTL = configManager.getTTLManager().getDatabaseLevelTTL(database);
72+
if (0 < databaseTTL && databaseTTL < Long.MAX_VALUE) {
73+
// For tree mode, the auto cleaner takes effect only when the database-level TTL is set.
74+
// Subsequently, we employ the maximum TTL among all time series in this database.
75+
databaseTTL = configManager.getTTLManager().getDatabaseMaxTTL(database);
76+
}
77+
}
6878
databaseTTLMap.put(database, databaseTTL);
6979
}
7080
LOGGER.info(

iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/schema/ttl/TTLCache.java

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,35 @@ public long getLastNodeTTL(String[] nodes) {
175175
return node.ttl;
176176
}
177177

178+
/**
179+
* Get the maximum ttl of the corresponding database level.
180+
*
181+
* @param database the path of the database.
182+
* @return the maximum ttl of the corresponding database level.
183+
* @throws IllegalPathException if the database path is illegal.
184+
*/
185+
public long getDatabaseLevelTTL(String database) throws IllegalPathException {
186+
long curTTL = NULL_TTL;
187+
// Get global TTL root.** if exists
188+
CacheNode curNode = ttlCacheTree.searchChild(IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD);
189+
if (curNode != null && curNode.ttl < Long.MAX_VALUE) {
190+
curTTL = curNode.ttl;
191+
}
192+
// Compare database TTL if exists
193+
curNode = ttlCacheTree.searchChild(database);
194+
if (curNode != null && curNode.ttl < Long.MAX_VALUE) {
195+
curTTL = Math.max(curTTL, curNode.ttl);
196+
}
197+
// Compare database.** TTL if exists
198+
curNode =
199+
ttlCacheTree.searchChild(
200+
database + IoTDBConstant.PATH_SEPARATOR + IoTDBConstant.MULTI_LEVEL_PATH_WILDCARD);
201+
if (curNode != null && curNode.ttl < Long.MAX_VALUE) {
202+
curTTL = Math.max(curTTL, curNode.ttl);
203+
}
204+
return curTTL;
205+
}
206+
178207
/**
179208
* Get the maximum ttl of the subtree of the corresponding database.
180209
*

0 commit comments

Comments
 (0)