This is an automated email from the ASF dual-hosted git repository. CRZbulabula pushed a commit to branch confignode-ops-config-hidden-hotreload in repository https://gitbox.apache.org/repos/asf/iotdb.git
commit 00d60109f7c2a17353ba2f01fe21953fa9fe9ec6 Author: Yongzao <[email protected]> AuthorDate: Thu Jul 2 13:31:09 2026 +0800 Hide cluster-ops tunables and hot-reload procedure cleaner & disk threshold Config template (iotdb-system.properties.template): - Hide (remove from template, still parsed with config-class defaults): enable_auto_leader_balance_for_ratis_consensus, enable_topology_probing, topology_probing_base_interval_in_ms, topology_probing_timeout_ratio. - Change effectiveMode restart -> hot_reload for procedure_completed_evict_ttl, procedure_completed_clean_interval and disk_space_warning_threshold. procedure_completed_evict_ttl / procedure_completed_clean_interval hot reload: ProcedureExecutor keeps a reference to the CompletedProcedureRecycler and adds restartCompletedCleaner() to re-schedule it with the new interval/TTL (both are captured at construction). ProcedureManager.updateCompletedProcedureCleaner() re-applies on the running (leader) executor; ConfigManager.setConfiguration captures the previous values and re-applies via handleProcedureCleanerHotReload. The recycler reference is volatile and both writers are synchronized. disk_space_warning_threshold hot reload: CommonDescriptor.loadHotModifiedDiskSpaceWarningThreshold() parses, validates ([0,1)) and applies the value; it is shared by the ConfigNode path (so SHOW VARIABLES / cluster-parameter consistency reflect the change) and the DataNode path, which additionally refreshes the JVMCommonUtils static copy that the ReadOnly disk guard consumes. --- .../confignode/conf/ConfigNodeDescriptor.java | 32 ++++++++++++++++++++++ .../iotdb/confignode/manager/ConfigManager.java | 12 ++++++++ .../iotdb/confignode/manager/ProcedureManager.java | 14 ++++++++++ .../confignode/procedure/ProcedureExecutor.java | 29 ++++++++++++++++++-- .../org/apache/iotdb/db/conf/IoTDBDescriptor.java | 7 +++++ .../conf/iotdb-system.properties.template | 28 ++----------------- .../iotdb/commons/conf/CommonDescriptor.java | 23 ++++++++++++++++ 7 files changed, 117 insertions(+), 28 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 43996574723..81f31330595 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 @@ -897,10 +897,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/ProcedureExecutor.java b/iotdb-core/confignode/src/main/java/org/apache/iotdb/confignode/procedure/ProcedureExecutor.java index bdaace3d768..91ef793fa7e 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}). Written + * by both {@link #startCompletedCleaner} (leader transition) and {@link #restartCompletedCleaner} + * (hot reload); both writers are {@code synchronized} and the field is {@code volatile} for + * cross-thread visibility. + */ + private volatile CompletedProcedureRecycler<Env> completedProcedureRecycler; + private final ProcedureScheduler scheduler; private final AtomicLong workId = new AtomicLong(0); @@ -289,9 +298,23 @@ 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); } public void addInternalProcedure(InternalProcedure interalProcedure) { 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 23036c78414..e30edb71f51 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 @@ -703,13 +703,6 @@ data_region_per_data_node=0 # Datatype: String region_group_allocate_policy=GCR -# Whether to enable auto leader balance for Ratis consensus protocol. -# The ConfigNode-leader will balance the leader of Ratis-RegionGroups by leader_distribution_policy if set true. -# Notice: Default is false because the Ratis is unstable for this function. -# effectiveMode: restart -# Datatype: Boolean -enable_auto_leader_balance_for_ratis_consensus=true - #################### ### Cluster management #################### @@ -752,23 +745,8 @@ failure_detector_phi_threshold=30 # Datatype: long failure_detector_phi_acceptable_pause_in_ms=10000 -# Whether to enable topology probing between DataNodes -# effectiveMode: hot_reload -# Datatype: Boolean -enable_topology_probing=false - -# Base interval in ms for topology probing between DataNodes -# effectiveMode: restart -# Datatype: long -topology_probing_base_interval_in_ms=5000 - -# Ratio of probing timeout to probing interval (must be less than 1.0) -# effectiveMode: restart -# Datatype: double -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 @@ -2185,12 +2163,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.
