diff --git a/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBTableIT.java b/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBTableIT.java index ef003debab67..839d33aadcf8 100644 --- a/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBTableIT.java +++ b/integration-test/src/test/java/org/apache/iotdb/relational/it/schema/IoTDBTableIT.java @@ -83,6 +83,43 @@ public static void tearDown() throws Exception { EnvFactory.getEnv().cleanClusterEnvironment(); } + @Test + public void testSetInfiniteTtlAfterMaximumNumericTtl() throws Exception { + final String database = "ttl_infinite_reset"; + try (final Connection connection = + EnvFactory.getEnv().getConnection(BaseEnv.TABLE_SQL_DIALECT); + final Statement statement = connection.createStatement()) { + try { + statement.execute("CREATE DATABASE " + database); + statement.execute("USE " + database); + statement.execute( + "CREATE TABLE table_1(device_id STRING TAG, text TEXT FIELD, float FLOAT FIELD)"); + statement.execute("ALTER TABLE IF EXISTS table_1 SET PROPERTIES ttl=3600000"); + TestUtils.tableResultSetEqualTestUnordered( + "SHOW TABLES", + new String[] {"TableName", "TTL(ms)"}, + new String[] {"table_1,3600000,"}, + database); + for (final String ttl : new String[] {"'INF'", "DEFAULT"}) { + statement.execute("ALTER TABLE table_1 SET PROPERTIES ttl=" + Long.MAX_VALUE); + TestUtils.tableResultSetEqualTestUnordered( + "SHOW TABLES", + new String[] {"TableName", "TTL(ms)"}, + new String[] {"table_1," + Long.MAX_VALUE + ","}, + database); + statement.execute("ALTER TABLE table_1 SET PROPERTIES ttl=" + ttl); + TestUtils.tableResultSetEqualTestUnordered( + "SHOW TABLES", + new String[] {"TableName", "TTL(ms)"}, + new String[] {"table_1,INF,"}, + database); + } + } finally { + statement.execute("DROP DATABASE IF EXISTS " + database); + } + } + } + @Test public void testResetTableTtlUsesDatabaseDefault() throws Exception { final String database = "ttl_default_reset"; diff --git a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/schema/ClusterSchemaManager.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/schema/ClusterSchemaManager.java index 0b3262c64edd..42d0ab3ef78e 100644 --- a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/schema/ClusterSchemaManager.java +++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/schema/ClusterSchemaManager.java @@ -2018,7 +2018,8 @@ public Pair updateTableProperties( key -> { if (TsTable.TTL_PROPERTY.equals(key) && IoTDBConstant.TTL_INFINITE.equalsIgnoreCase(updatedProperties.get(key))) { - return originalTable.getTableTTL() == Long.MAX_VALUE; + return IoTDBConstant.TTL_INFINITE.equalsIgnoreCase( + originalTable.getPropValue(key).orElse(IoTDBConstant.TTL_INFINITE)); } return Objects.equals( updatedProperties.get(key), originalTable.getPropValue(key).orElse(null)); diff --git a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/manager/ClusterSchemaManagerTest.java b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/manager/ClusterSchemaManagerTest.java index bc66d5e2b94e..8d582be43a14 100644 --- a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/manager/ClusterSchemaManagerTest.java +++ b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/manager/ClusterSchemaManagerTest.java @@ -551,7 +551,7 @@ public void testResetTableTtlUsesInfiniteDatabaseDefault() throws Exception { } @Test - public void testResetTableTtlWithInfiniteDefaultIsNoOp() throws Exception { + public void testResetTableTtlWithInfiniteDefault() throws Exception { final String database = "ttl_default_no_op_test"; for (final boolean explicitInfinite : new boolean[] {false, true}) { for (final String initialTtl : new String[] {null, "INF", String.valueOf(Long.MAX_VALUE)}) { @@ -578,9 +578,17 @@ public void testResetTableTtlWithInfiniteDefaultIsNoOp() throws Exception { database, TABLE, originalProperties, updatedProperties, false); Assert.assertEquals( TSStatusCode.SUCCESS_STATUS.getStatusCode(), result.getLeft().getCode()); - Assert.assertNull(result.getRight()); - Assert.assertTrue(updatedProperties.isEmpty()); - Assert.assertTrue(originalProperties.isEmpty()); + if (String.valueOf(Long.MAX_VALUE).equals(initialTtl)) { + Assert.assertNotNull(result.getRight()); + Assert.assertEquals("INF", updatedProperties.get(TsTable.TTL_PROPERTY)); + Assert.assertEquals(initialTtl, originalProperties.get(TsTable.TTL_PROPERTY)); + Assert.assertEquals( + "INF", result.getRight().getPropValue(TsTable.TTL_PROPERTY).orElse(null)); + } else { + Assert.assertNull(result.getRight()); + Assert.assertTrue(updatedProperties.isEmpty()); + Assert.assertTrue(originalProperties.isEmpty()); + } Assert.assertEquals( initialTtl, manager diff --git a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/schema/table/SetTablePropertiesProcedureTest.java b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/schema/table/SetTablePropertiesProcedureTest.java index 3704cb3fd026..ebff7200df2d 100644 --- a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/schema/table/SetTablePropertiesProcedureTest.java +++ b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/impl/schema/table/SetTablePropertiesProcedureTest.java @@ -20,6 +20,7 @@ package org.apache.iotdb.confignode.procedure.impl.schema.table; import org.apache.iotdb.common.rpc.thrift.TSStatus; +import org.apache.iotdb.commons.conf.IoTDBConstant; import org.apache.iotdb.commons.exception.IllegalPathException; import org.apache.iotdb.commons.schema.table.TsTable; import org.apache.iotdb.confignode.consensus.request.ConfigPhysicalPlanType; @@ -52,6 +53,75 @@ import static org.apache.iotdb.confignode.procedure.state.schema.SetTablePropertiesState.SET_PROPERTIES; public class SetTablePropertiesProcedureTest { + @Test + public void testSetInfiniteTtlAfterMaximumNumericTtl() throws Exception { + for (final String ttl : new String[] {IoTDBConstant.TTL_INFINITE, null}) { + final String database = "ttl_infinite_test"; + final String tableName = "table1"; + final String maximumTtl = String.valueOf(Long.MAX_VALUE); + final ClusterSchemaInfo schemaInfo = new ClusterSchemaInfo(); + schemaInfo.createDatabase( + new DatabaseSchemaPlan( + ConfigPhysicalPlanType.CreateDatabase, + new TDatabaseSchema(database).setIsTableModel(true).setTTL(Long.MAX_VALUE))); + final TsTable table = new TsTable(tableName); + table.addProp(TsTable.TTL_PROPERTY, maximumTtl); + schemaInfo.preCreateTable(new PreCreateTablePlan(database, table)); + schemaInfo.commitCreateTable(new CommitCreateTablePlan(database, tableName)); + final ConfigManager configManager = Mockito.mock(ConfigManager.class); + final PartitionManager partitionManager = Mockito.mock(PartitionManager.class); + Mockito.when(configManager.getPartitionManager()).thenReturn(partitionManager); + Mockito.when(partitionManager.isDatabaseExist(database)).thenReturn(true); + final ClusterSchemaManager manager = + new ClusterSchemaManager( + configManager, schemaInfo, Mockito.mock(ClusterSchemaQuotaStatistics.class)); + Mockito.when(configManager.getClusterSchemaManager()).thenReturn(manager); + final ConfigNodeProcedureEnv env = Mockito.mock(ConfigNodeProcedureEnv.class); + Mockito.when(env.getConfigManager()).thenReturn(configManager); + final Map properties = new HashMap<>(); + properties.put(TsTable.TTL_PROPERTY, ttl); + final SetTablePropertiesProcedure procedure = + new SetTablePropertiesProcedure(database, tableName, "0", properties, false); + + procedure.validateTable(env); + Assert.assertFalse(procedure.isFailed()); + Assert.assertNotNull(procedure.table); + Assert.assertEquals( + IoTDBConstant.TTL_INFINITE, procedure.table.getPropValue(TsTable.TTL_PROPERTY).get()); + Assert.assertEquals(maximumTtl, procedure.originalProperties.get(TsTable.TTL_PROPERTY)); + Assert.assertEquals( + maximumTtl, + manager + .getTableIfExists(database, tableName) + .get() + .getPropValue(TsTable.TTL_PROPERTY) + .get()); + + Assert.assertEquals( + TSStatusCode.SUCCESS_STATUS.getStatusCode(), + schemaInfo + .setTableProperties( + (SetTablePropertiesPlan) procedure.createSetPropertiesPlan(properties, false)) + .getCode()); + Assert.assertEquals( + IoTDBConstant.TTL_INFINITE, + manager + .getTableIfExists(database, tableName) + .get() + .getPropValue(TsTable.TTL_PROPERTY) + .get()); + + // Repeating an infinite TTL should still be treated as an unchanged property. + final Map repeatedProperties = new HashMap<>(); + repeatedProperties.put(TsTable.TTL_PROPERTY, ttl); + final SetTablePropertiesProcedure repeated = + new SetTablePropertiesProcedure(database, tableName, "1", repeatedProperties, false); + repeated.validateTable(env); + Assert.assertFalse(repeated.isFailed()); + Assert.assertNull(repeated.table); + } + } + @Test public void testRollbackRestoresMissingTableTtlAfterDatabaseDefaultChanges() throws Exception { final String database = "ttl_rollback_test"; diff --git a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/node/WALNodeTest.java b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/node/WALNodeTest.java index 210ee544ea47..427d7a0ea59b 100644 --- a/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/node/WALNodeTest.java +++ b/iotdb-core/datanode/src/test/java/org/apache/iotdb/db/storageengine/dataregion/wal/node/WALNodeTest.java @@ -332,6 +332,7 @@ public void testConcurrentCheckpoint() throws Exception { @Test public void testDeleteOutdatedFiles() throws Exception { + List walFlushListeners = new ArrayList<>(); // write data to make the first WAL file non-empty IMemTable memTable = new PrimitiveMemTable(databasePath, dataRegionId); long memTableId = memTable.getMemTableId(); @@ -353,10 +354,12 @@ public void testDeleteOutdatedFiles() throws Exception { for (long time = 1; time <= 100; ++time) { InsertTabletNode insertTabletNode = getInsertTabletNode(devicePath + memTableId, new long[] {time}); - walNode.log( - memTableId, - insertTabletNode, - Collections.singletonList(new int[] {0, insertTabletNode.getRowCount()})); + WALFlushListener walFlushListener = + walNode.log( + memTableId, + insertTabletNode, + Collections.singletonList(new int[] {0, insertTabletNode.getRowCount()})); + walFlushListeners.add(walFlushListener); } walNode.onMemTableFlushed(memTable); walNode.rollWALFile();