This is an automated email from the ASF dual-hosted git repository.
CRZbulabula pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/iotdb.git
The following commit(s) were added to refs/heads/master by this push:
new 2e099a68eb5 Hot-reload procedure completed-cleaner & disk space
warning threshold (+ fix evict-TTL unit) (#18091)
2e099a68eb5 is described below
commit 2e099a68eb5f8db9487a784f91635ca3c8e934ed
Author: Yongzao <[email protected]>
AuthorDate: Fri Jul 3 11:14:19 2026 +0800
Hot-reload procedure completed-cleaner & disk space warning threshold (+
fix evict-TTL unit) (#18091)
---
.../confignode/conf/ConfigNodeDescriptor.java | 32 +++++++++
.../iotdb/confignode/manager/ConfigManager.java | 12 ++++
.../iotdb/confignode/manager/ProcedureManager.java | 14 ++++
.../procedure/CompletedProcedureRecycler.java | 14 +++-
.../confignode/procedure/ProcedureExecutor.java | 34 +++++++++-
.../procedure/CompletedProcedureRecyclerTest.java | 76 +++++++++++++++++++++
.../procedure/TestProcedureExecutor.java | 14 ++++
.../org/apache/iotdb/db/conf/IoTDBDescriptor.java | 7 ++
.../conf/iotdb-system.properties.template | 6 +-
.../iotdb/commons/conf/CommonDescriptor.java | 23 +++++++
...monDescriptorDiskSpaceWarningThresholdTest.java | 78 ++++++++++++++++++++++
11 files changed, 301 insertions(+), 9 deletions(-)
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeDescriptor.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeDescriptor.java
index 0220543d113..e08b4b72513 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeDescriptor.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeDescriptor.java
@@ -906,10 +906,42 @@ public class ConfigNodeDescriptor {
conf.setReadConsistencyLevel(readConsistencyLevel);
Optional.ofNullable(properties.getProperty("enable_topology_probing"))
.ifPresent(v ->
conf.setEnableTopologyProbing(Boolean.parseBoolean(v)));
+ // Keep the ConfigNode's CommonConfig in sync so that SHOW VARIABLES /
cluster-parameter
+ // consistency checks report the hot-reloaded value; the DataNode side
additionally refreshes
+ // JVMCommonUtils where the ReadOnly disk guard actually consumes it.
+ commonDescriptor.loadHotModifiedDiskSpaceWarningThreshold(properties);
+ loadHotModifiedProcedureConfig(properties);
loadPipeHotModifiedProp(properties);
ConfigurationFileUtils.updateAppliedProperties(properties, true);
}
+ private void loadHotModifiedProcedureConfig(TrimProperties properties)
throws IOException {
+ int procedureCompletedCleanInterval =
+ Integer.parseInt(
+ properties.getProperty(
+ "procedure_completed_clean_interval",
+ String.valueOf(conf.getProcedureCompletedCleanInterval())));
+ if (procedureCompletedCleanInterval <= 0) {
+ throw new IOException(
+ "procedure_completed_clean_interval should be greater than 0, but
was "
+ + procedureCompletedCleanInterval
+ + ".");
+ }
+ int procedureCompletedEvictTTL =
+ Integer.parseInt(
+ properties.getProperty(
+ "procedure_completed_evict_ttl",
+ String.valueOf(conf.getProcedureCompletedEvictTTL())));
+ if (procedureCompletedEvictTTL <= 0) {
+ throw new IOException(
+ "procedure_completed_evict_ttl should be greater than 0, but was "
+ + procedureCompletedEvictTTL
+ + ".");
+ }
+ conf.setProcedureCompletedCleanInterval(procedureCompletedCleanInterval);
+ conf.setProcedureCompletedEvictTTL(procedureCompletedEvictTTL);
+ }
+
private void loadPipeHotModifiedProp(TrimProperties properties) throws
IOException {
PipeDescriptor.loadPipeProps(commonDescriptor.getConfig(), properties,
true);
PipePeriodicalLogReducer.update();
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
index b11c83d5784..dfdafd0f97d 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
@@ -1787,6 +1787,8 @@ public class ConfigManager implements IManager {
int previousSchemaRegionPerDataNode = CONF.getSchemaRegionPerDataNode();
int previousDataRegionPerDataNode = CONF.getDataRegionPerDataNode();
boolean wasTopologyProbingEnabled = CONF.isEnableTopologyProbing();
+ int previousProcedureCompletedCleanInterval =
CONF.getProcedureCompletedCleanInterval();
+ int previousProcedureCompletedEvictTTL =
CONF.getProcedureCompletedEvictTTL();
if (configurationFileFound) {
File file = new File(url.getFile());
try {
@@ -1817,6 +1819,8 @@ public class ConfigManager implements IManager {
handleRegionPerDataNodeHotReload(
previousSchemaRegionPerDataNode, previousDataRegionPerDataNode);
handleTopologyProbingHotReload(wasTopologyProbingEnabled);
+ handleProcedureCleanerHotReload(
+ previousProcedureCompletedCleanInterval,
previousProcedureCompletedEvictTTL);
if (currentNodeId == req.getNodeId() || req.getNodeId() ==
NodeManager.APPLY_CONFIG_LOCALLY) {
return tsStatus;
}
@@ -1884,6 +1888,14 @@ public class ConfigManager implements IManager {
}
}
+ private void handleProcedureCleanerHotReload(int previousCleanInterval, int
previousEvictTTL) {
+ if (previousCleanInterval == CONF.getProcedureCompletedCleanInterval()
+ && previousEvictTTL == CONF.getProcedureCompletedEvictTTL()) {
+ return;
+ }
+ getProcedureManager().updateCompletedProcedureCleaner();
+ }
+
@Override
public TSStatus startRepairData() {
TSStatus status = confirmLeader();
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ProcedureManager.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ProcedureManager.java
index 28514043188..33bd1810a5d 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ProcedureManager.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/manager/ProcedureManager.java
@@ -263,6 +263,20 @@ public class ProcedureManager {
}
}
+ /**
+ * Reload the completed-procedure cleaner with the current {@code
+ * procedure_completed_clean_interval} and {@code
procedure_completed_evict_ttl}. Only takes
+ * effect on the running (leader) ConfigNode; on a follower the executor is
stopped and the fresh
+ * values are picked up when {@link #startExecutor} runs after the next
leader switch.
+ */
+ public void updateCompletedProcedureCleaner() {
+ if (executor.isRunning()) {
+ executor.restartCompletedCleaner(
+ CONFIG_NODE_CONFIG.getProcedureCompletedCleanInterval(),
+ CONFIG_NODE_CONFIG.getProcedureCompletedEvictTTL());
+ }
+ }
+
public boolean isProcedureExecutionThread() {
return ProcedureExecutor.isProcedureExecutionThread();
}
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/CompletedProcedureRecycler.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/CompletedProcedureRecycler.java
index 179563cc3b3..3c524a62d50 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/CompletedProcedureRecycler.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/CompletedProcedureRecycler.java
@@ -19,6 +19,7 @@
package org.apache.iotdb.confignode.procedure;
+import org.apache.iotdb.commons.utils.TestOnly;
import org.apache.iotdb.confignode.procedure.store.IProcedureStore;
import org.slf4j.Logger;
@@ -32,7 +33,7 @@ import java.util.concurrent.TimeUnit;
public class CompletedProcedureRecycler<Env> extends InternalProcedure<Env> {
private static final Logger LOG =
LoggerFactory.getLogger(CompletedProcedureRecycler.class);
private static final int DEFAULT_BATCH_SIZE = 8;
- private final long evictTTL;
+ private final long evictTTLInMs;
private final Map<Long, CompletedProcedureContainer<Env>> completed;
private final IProcedureStore<Env> store;
@@ -44,7 +45,14 @@ public class CompletedProcedureRecycler<Env> extends
InternalProcedure<Env> {
super(TimeUnit.SECONDS.toMillis(cleanTimeInterval));
this.completed = completedMap;
this.store = store;
- this.evictTTL = evictTTL;
+ // evictTTL is configured in seconds, but isExpired compares it against a
+ // System.currentTimeMillis() delta, so it must be converted to
milliseconds here.
+ this.evictTTLInMs = TimeUnit.SECONDS.toMillis(evictTTL);
+ }
+
+ @TestOnly
+ long getEvictTTLInMs() {
+ return evictTTLInMs;
}
@Override
@@ -66,7 +74,7 @@ public class CompletedProcedureRecycler<Env> extends
InternalProcedure<Env> {
final Map.Entry<Long, CompletedProcedureContainer<Env>> entry =
it.next();
final CompletedProcedureContainer<Env> retainer = entry.getValue();
final Procedure<?> proc = retainer.getProcedure();
- if (retainer.isExpired(now, evictTTL)) {
+ if (retainer.isExpired(now, evictTTLInMs)) {
// Failed procedures aren't persisted in WAL.
batchIds[batchCount++] = entry.getKey();
if (batchCount == batchIds.length) {
diff --git
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/ProcedureExecutor.java
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/ProcedureExecutor.java
index bdaace3d768..51953703603 100644
---
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/ProcedureExecutor.java
+++
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/ProcedureExecutor.java
@@ -76,6 +76,15 @@ public class ProcedureExecutor<Env> {
private int corePoolSize;
private int maxPoolSize;
+ /**
+ * The internal cleaner that recycles completed procedures. Kept as a
reference so that its clean
+ * interval / evict TTL can be reloaded at runtime (see {@link
#restartCompletedCleaner}). All
+ * accesses ({@link #startCompletedCleaner} on leader transition, {@link
#restartCompletedCleaner}
+ * on hot reload, and the test getter) are performed while holding this
instance's monitor, so the
+ * field is guarded by {@code synchronized} for both mutual exclusion and
cross-thread visibility.
+ */
+ private CompletedProcedureRecycler<Env> completedProcedureRecycler;
+
private final ProcedureScheduler scheduler;
private final AtomicLong workId = new AtomicLong(0);
@@ -289,9 +298,28 @@ public class ProcedureExecutor<Env> {
LOG.info(ProcedureMessages.PROCEDURE_WORKERS_ARE_STARTED,
workerThreads.size());
}
- public void startCompletedCleaner(long cleanTimeInterval, long
cleanEvictTTL) {
- addInternalProcedure(
- new CompletedProcedureRecycler(store, completed, cleanTimeInterval,
cleanEvictTTL));
+ public synchronized void startCompletedCleaner(long cleanTimeInterval, long
cleanEvictTTL) {
+ completedProcedureRecycler =
+ new CompletedProcedureRecycler<>(store, completed, cleanTimeInterval,
cleanEvictTTL);
+ addInternalProcedure(completedProcedureRecycler);
+ }
+
+ /**
+ * Reload the completed-procedure cleaner with a new clean interval / evict
TTL at runtime. The
+ * clean interval and evict TTL are captured by {@link
CompletedProcedureRecycler} at
+ * construction, so applying the new values requires removing the current
recycler and scheduling
+ * a fresh one.
+ */
+ public synchronized void restartCompletedCleaner(long cleanTimeInterval,
long cleanEvictTTL) {
+ if (completedProcedureRecycler != null) {
+ removeInternalProcedure(completedProcedureRecycler);
+ }
+ startCompletedCleaner(cleanTimeInterval, cleanEvictTTL);
+ }
+
+ @TestOnly
+ synchronized CompletedProcedureRecycler<Env> getCompletedProcedureRecycler()
{
+ return completedProcedureRecycler;
}
public void addInternalProcedure(InternalProcedure interalProcedure) {
diff --git
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/CompletedProcedureRecyclerTest.java
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/CompletedProcedureRecyclerTest.java
new file mode 100644
index 00000000000..eb951641e61
--- /dev/null
+++
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/CompletedProcedureRecyclerTest.java
@@ -0,0 +1,76 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.confignode.procedure;
+
+import org.apache.iotdb.confignode.procedure.entity.NoopProcedure;
+import org.apache.iotdb.confignode.procedure.env.TestProcEnv;
+import org.apache.iotdb.confignode.procedure.store.IProcedureStore;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+
+public class CompletedProcedureRecyclerTest {
+
+ @SuppressWarnings("unchecked")
+ private static IProcedureStore<TestProcEnv> runningStore() {
+ NoopProcedureStore store = new NoopProcedureStore();
+ store.setRunning(true);
+ return store;
+ }
+
+ private static CompletedProcedureContainer<TestProcEnv> completedAt(long
lastUpdate) {
+ NoopProcedure procedure = new NoopProcedure();
+ procedure.setLastUpdate(lastUpdate);
+ return new CompletedProcedureContainer<>(procedure);
+ }
+
+ /** The evict TTL is configured in seconds but compared against a
millisecond delta. */
+ @Test
+ public void evictTtlIsConvertedFromSecondsToMillis() {
+ CompletedProcedureRecycler<TestProcEnv> recycler =
+ new CompletedProcedureRecycler<>(runningStore(), new
ConcurrentHashMap<>(), 30, 60);
+ Assert.assertEquals(TimeUnit.SECONDS.toMillis(60),
recycler.getEvictTTLInMs());
+ }
+
+ @Test
+ public void freshCompletedProcedureIsRetainedWhileStaleOneIsEvicted() {
+ final long now = System.currentTimeMillis();
+ final Map<Long, CompletedProcedureContainer<TestProcEnv>> completed = new
ConcurrentHashMap<>();
+ // Completed 1s ago: with a 100s evict TTL it must survive. Before the
seconds->millis fix a
+ // 100s TTL was treated as 100ms, so this fresh entry was evicted almost
immediately.
+ completed.put(1L, completedAt(now - TimeUnit.SECONDS.toMillis(1)));
+ // Completed 300s ago: with a 100s evict TTL it must be evicted.
+ completed.put(2L, completedAt(now - TimeUnit.SECONDS.toMillis(300)));
+
+ CompletedProcedureRecycler<TestProcEnv> recycler =
+ new CompletedProcedureRecycler<>(runningStore(), completed, 30, 100);
+ recycler.periodicExecute(null);
+
+ Assert.assertTrue(
+ "A procedure completed 1s ago must survive a 100s evict TTL",
completed.containsKey(1L));
+ Assert.assertFalse(
+ "A procedure completed 300s ago must be evicted by a 100s evict TTL",
+ completed.containsKey(2L));
+ }
+}
diff --git
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/TestProcedureExecutor.java
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/TestProcedureExecutor.java
index 75a7168c1f6..ab6ec55f4d7 100644
---
a/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/TestProcedureExecutor.java
+++
b/iotdb-core/confignode/src/test/java/org/apache/iotdb/confignode/procedure/TestProcedureExecutor.java
@@ -140,6 +140,20 @@ public class TestProcedureExecutor extends
TestProcedureBase {
Assert.assertTrue(procExecutor.removeInternalProcedure(internalProcedure));
}
+ @Test
+ public void testRestartCompletedCleanerAppliesNewEvictTtl() {
+ procExecutor.startCompletedCleaner(30, 60);
+ CompletedProcedureRecycler<TestProcEnv> first =
procExecutor.getCompletedProcedureRecycler();
+ Assert.assertNotNull(first);
+ Assert.assertEquals(TimeUnit.SECONDS.toMillis(60),
first.getEvictTTLInMs());
+
+ // Hot reload with a different interval / TTL replaces the recycler with a
fresh instance.
+ procExecutor.restartCompletedCleaner(15, 120);
+ CompletedProcedureRecycler<TestProcEnv> second =
procExecutor.getCompletedProcedureRecycler();
+ Assert.assertNotSame(first, second);
+ Assert.assertEquals(TimeUnit.SECONDS.toMillis(120),
second.getEvictTTLInMs());
+ }
+
private int waitThreadCount(final int expectedThreads) {
long startTime = System.currentTimeMillis();
while (procExecutor.isRunning()
diff --git
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
index 147c3340bb3..df84e525ec8 100644
---
a/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
+++
b/iotdb-core/datanode/src/main/java/org/apache/iotdb/db/conf/IoTDBDescriptor.java
@@ -31,6 +31,7 @@ import org.apache.iotdb.commons.pipe.config.PipeDescriptor;
import org.apache.iotdb.commons.pipe.resource.log.PipePeriodicalLogReducer;
import org.apache.iotdb.commons.schema.SchemaConstant;
import org.apache.iotdb.commons.service.metric.MetricService;
+import org.apache.iotdb.commons.utils.JVMCommonUtils;
import org.apache.iotdb.commons.utils.NodeUrlUtils;
import org.apache.iotdb.confignode.rpc.thrift.TCQConfig;
import org.apache.iotdb.confignode.rpc.thrift.TGlobalConfig;
@@ -2252,6 +2253,12 @@ public class IoTDBDescriptor {
BinaryAllocator.getInstance().close(true);
}
+ // update disk_space_warning_threshold; also refresh the static copy in
JVMCommonUtils that
+ // the ReadOnly disk guard reads, otherwise the new threshold would not
take effect until
+ // restart. Parsing / validation is shared with the ConfigNode
hot-reload path.
+ JVMCommonUtils.setDiskSpaceWarningThreshold(
+
commonDescriptor.loadHotModifiedDiskSpaceWarningThreshold(properties));
+
commonDescriptor
.getConfig()
.setTimestampPrecisionCheckEnabled(
diff --git
a/iotdb-core/node-commons/src/assembly/resources/conf/iotdb-system.properties.template
b/iotdb-core/node-commons/src/assembly/resources/conf/iotdb-system.properties.template
index 64e35fddd75..fdf79943255 100644
---
a/iotdb-core/node-commons/src/assembly/resources/conf/iotdb-system.properties.template
+++
b/iotdb-core/node-commons/src/assembly/resources/conf/iotdb-system.properties.template
@@ -768,7 +768,7 @@ topology_probing_base_interval_in_ms=5000
topology_probing_timeout_ratio=0.5
# Disk remaining threshold at which DataNode is set to ReadOnly status
-# effectiveMode: restart
+# effectiveMode: hot_reload
# Datatype: double(percentage)
disk_space_warning_threshold=0.05
@@ -2190,12 +2190,12 @@ zombie_tsfile_writer_threshold=600000
procedure_core_worker_thread_count=4
# Default time interval of completed procedure cleaner work in, time unit is
second
-# effectiveMode: restart
+# effectiveMode: hot_reload
# Datatype: int
procedure_completed_clean_interval=30
# Default ttl of completed procedure, time unit is second
-# effectiveMode: restart
+# effectiveMode: hot_reload
# Datatype: int
procedure_completed_evict_ttl=60
diff --git
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonDescriptor.java
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonDescriptor.java
index 9d7c6bdffc2..7f2802e0ed0 100644
---
a/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonDescriptor.java
+++
b/iotdb-core/node-commons/src/main/java/org/apache/iotdb/commons/conf/CommonDescriptor.java
@@ -583,6 +583,29 @@ public class CommonDescriptor {
"enable_retry_for_unknown_error"))));
}
+ /**
+ * Parse, validate and apply {@code disk_space_warning_threshold} for a
runtime hot reload, then
+ * return the applied value. Shared by the ConfigNode and DataNode
hot-reload paths so both use
+ * the same parsing / bounds rules. Callers on the DataNode must
additionally refresh the {@code
+ * JVMCommonUtils} static copy that the ReadOnly disk guard actually
consumes.
+ */
+ public double loadHotModifiedDiskSpaceWarningThreshold(final TrimProperties
properties)
+ throws IOException {
+ double diskSpaceWarningThreshold =
+ Double.parseDouble(
+ properties.getProperty(
+ "disk_space_warning_threshold",
+ String.valueOf(config.getDiskSpaceWarningThreshold())));
+ if (diskSpaceWarningThreshold < 0 || diskSpaceWarningThreshold >= 1) {
+ throw new IOException(
+ "disk_space_warning_threshold must be in [0, 1), but was "
+ + diskSpaceWarningThreshold
+ + ".");
+ }
+ config.setDiskSpaceWarningThreshold(diskSpaceWarningThreshold);
+ return diskSpaceWarningThreshold;
+ }
+
/**
* Reload only the subscription consensus properties that are intended to
take effect on hot
* configuration reload.
diff --git
a/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/conf/CommonDescriptorDiskSpaceWarningThresholdTest.java
b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/conf/CommonDescriptorDiskSpaceWarningThresholdTest.java
new file mode 100644
index 00000000000..a28f4b825d3
--- /dev/null
+++
b/iotdb-core/node-commons/src/test/java/org/apache/iotdb/commons/conf/CommonDescriptorDiskSpaceWarningThresholdTest.java
@@ -0,0 +1,78 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ */
+
+package org.apache.iotdb.commons.conf;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.IOException;
+
+public class CommonDescriptorDiskSpaceWarningThresholdTest {
+
+ private static final String KEY = "disk_space_warning_threshold";
+
+ @Test
+ public void validValueIsAppliedAndReturned() throws IOException {
+ final CommonDescriptor descriptor = CommonDescriptor.getInstance();
+ final double original =
descriptor.getConfig().getDiskSpaceWarningThreshold();
+ try {
+ final TrimProperties properties = new TrimProperties();
+ properties.setProperty(KEY, "0.1");
+ final double applied =
descriptor.loadHotModifiedDiskSpaceWarningThreshold(properties);
+ Assert.assertEquals(0.1, applied, 0.0);
+ Assert.assertEquals(0.1,
descriptor.getConfig().getDiskSpaceWarningThreshold(), 0.0);
+ } finally {
+ descriptor.getConfig().setDiskSpaceWarningThreshold(original);
+ }
+ }
+
+ @Test
+ public void absentKeyKeepsCurrentValue() throws IOException {
+ final CommonDescriptor descriptor = CommonDescriptor.getInstance();
+ final double original =
descriptor.getConfig().getDiskSpaceWarningThreshold();
+ try {
+ descriptor.getConfig().setDiskSpaceWarningThreshold(0.07);
+ final double applied =
+ descriptor.loadHotModifiedDiskSpaceWarningThreshold(new
TrimProperties());
+ Assert.assertEquals(0.07, applied, 0.0);
+ } finally {
+ descriptor.getConfig().setDiskSpaceWarningThreshold(original);
+ }
+ }
+
+ @Test
+ public void outOfRangeValueIsRejectedWithoutMutatingConfig() {
+ final CommonDescriptor descriptor = CommonDescriptor.getInstance();
+ final double original =
descriptor.getConfig().getDiskSpaceWarningThreshold();
+ try {
+ for (final String badValue : new String[] {"1.0", "1.5", "-0.1"}) {
+ final TrimProperties properties = new TrimProperties();
+ properties.setProperty(KEY, badValue);
+ Assert.assertThrows(
+ IOException.class,
+ () ->
descriptor.loadHotModifiedDiskSpaceWarningThreshold(properties));
+ }
+ // A rejected value must not mutate the config.
+ Assert.assertEquals(original,
descriptor.getConfig().getDiskSpaceWarningThreshold(), 0.0);
+ } finally {
+ descriptor.getConfig().setDiskSpaceWarningThreshold(original);
+ }
+ }
+}