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

JackieTien97 pushed a commit to branch rc/2.0.11-edge
in repository https://gitbox.apache.org/repos/asf/iotdb.git

commit b6e887e63b9f4c46e3d5a1abf53fedae14c2a800
Author: JackieTien97 <[email protected]>
AuthorDate: Fri Aug 28 15:59:01 2026 +0800

    Add IoTDB Edge distribution: ConfigNode + DataNode merged in one JVM
    
    Produce apache-iotdb-edge-${version}-all-bin from the default distribution
    build, targeting resource-constrained edge machines that share the host
    with other processes (about 512 MB total process RSS by default).
    
    - EdgeNode (iotdb-core/confignode, org.apache.iotdb.edge): bootstraps the
      ConfigNode on a background thread, waits for its internal RPC port, then
      starts the DataNode in the same JVM, saving a whole JVM's fixed overhead
      (~140 MB validated on x86 and Raspberry Pi 4B).
    - One pair of lifecycle scripts only: sbin/start-edge.sh / stop-edge.sh
      (plus Windows bats); no separate ConfigNode/DataNode scripts in this
      package. start-edge.sh sets CONFIGNODE_HOME explicitly so the ConfigNode
      resolves its directories against the installation dir.
    - conf/edge-env.sh: fixed small JVM budget (Xmx 224M, direct 96M,
      metaspace 160m, SerialGC, Xss320k, ActiveProcessorCount=2).
    - Edge-tuned iotdb-system.properties defaults: small thread pools, 1M WAL
      buffer, 4M tsfile write buffer, 128M compaction target, CUSTOM region
      policy with 1 region group per database, series_slot_num=1, metrics off.
    - Validated at 1 Hz mixed read/write on x86 (>=20k series) and
      Raspberry Pi 4B (>=10k series, 30-min soak per shape, zero failed points).
---
 distribution/pom.xml                               |  16 ++
 distribution/src/assembly/all.xml                  |   4 +
 distribution/src/assembly/{all.xml => edge.xml}    |  40 ++--
 .../resources/conf-edge/iotdb-system.properties    | 126 +++++++++++
 .../assembly/resources/conf-edge/logback-edge.xml  | 252 +++++++++++++++++++++
 .../iotdb/confignode/i18n/ConfigNodeMessages.java  |   9 +
 .../iotdb/confignode/i18n/ConfigNodeMessages.java  |   9 +
 .../main/java/org/apache/iotdb/edge/EdgeNode.java  | 114 ++++++++++
 scripts/conf/edge-env.sh                           |  69 ++++++
 scripts/conf/windows/edge-env.bat                  |  44 ++++
 scripts/sbin/start-edge.sh                         |  92 ++++++++
 scripts/sbin/stop-edge.sh                          |  45 ++++
 scripts/sbin/windows/start-edge.bat                | 105 +++++++++
 scripts/sbin/windows/stop-edge.bat                 |  23 ++
 14 files changed, 935 insertions(+), 13 deletions(-)

diff --git a/distribution/pom.xml b/distribution/pom.xml
index 3e618451f58..f14b9deeda4 100644
--- a/distribution/pom.xml
+++ b/distribution/pom.xml
@@ -93,6 +93,21 @@
                             
<finalName>apache-iotdb-${project.version}</finalName>
                         </configuration>
                     </execution>
+                    <!-- Edge distribution: ConfigNode + DataNode merged in 
one JVM,
+                         with resource-constrained default configuration. -->
+                    <execution>
+                        <id>edge-bin</id>
+                        <goals>
+                            <goal>single</goal>
+                        </goals>
+                        <phase>package</phase>
+                        <configuration>
+                            <descriptors>
+                                <descriptor>src/assembly/edge.xml</descriptor>
+                            </descriptors>
+                            
<finalName>apache-iotdb-edge-${project.version}</finalName>
+                        </configuration>
+                    </execution>
                 </executions>
             </plugin>
             <!--
@@ -123,6 +138,7 @@
                                         
<include>apache-iotdb-${project.version}-confignode-bin.zip</include>
                                         
<include>apache-iotdb-${project.version}-library-udf-bin.zip</include>
                                         
<include>apache-iotdb-${project.version}-external-service-impl-bin.zip</include>
+                                        
<include>apache-iotdb-edge-${project.version}-all-bin.zip</include>
                                     </includes>
                                 </fileSet>
                             </fileSets>
diff --git a/distribution/src/assembly/all.xml 
b/distribution/src/assembly/all.xml
index c8b583de664..10b6f09589a 100644
--- a/distribution/src/assembly/all.xml
+++ b/distribution/src/assembly/all.xml
@@ -64,6 +64,8 @@
             <excludes>
                 <exclude>ainode-env.*</exclude>
                 <exclude>**/ainode-env.*</exclude>
+                <exclude>edge-env.*</exclude>
+                <exclude>**/edge-env.*</exclude>
                 <exclude>iotdb-common.sh</exclude>
                 <exclude>**/iotdb-common.bat</exclude>
             </excludes>
@@ -85,6 +87,8 @@
             <excludes>
                 <exclude>*ainode.*</exclude>
                 <exclude>**/*ainode.*</exclude>
+                <exclude>*edge.*</exclude>
+                <exclude>**/*edge.*</exclude>
             </excludes>
             <fileMode>0755</fileMode>
         </fileSet>
diff --git a/distribution/src/assembly/all.xml 
b/distribution/src/assembly/edge.xml
similarity index 77%
copy from distribution/src/assembly/all.xml
copy to distribution/src/assembly/edge.xml
index c8b583de664..16055237409 100644
--- a/distribution/src/assembly/all.xml
+++ b/distribution/src/assembly/edge.xml
@@ -25,7 +25,7 @@
         <format>dir</format>
         <format>zip</format>
     </formats>
-    <baseDirectory>apache-iotdb-${project.version}-all-bin</baseDirectory>
+    <baseDirectory>apache-iotdb-edge-${project.version}-all-bin</baseDirectory>
     <dependencySets>
         <dependencySet>
             <includes>
@@ -46,27 +46,35 @@
         </dependencySet>
     </dependencySets>
     <fileSets>
+        <!-- jmx credentials and the tool logback come from the datanode 
resources;
+             logback-datanode.xml is replaced by the merged logback-edge.xml 
below. -->
         <fileSet>
             <outputDirectory>conf</outputDirectory>
             
<directory>${project.basedir}/../iotdb-core/datanode/src/assembly/resources/conf</directory>
+            <excludes>
+                <exclude>logback-datanode.xml</exclude>
+            </excludes>
         </fileSet>
+        <!-- iotdb-system.properties is replaced by the edge-tuned one below. 
-->
         <fileSet>
             <outputDirectory>conf</outputDirectory>
-            
<directory>${project.basedir}/../iotdb-core/confignode/src/assembly/resources/conf</directory>
+            
<directory>${project.basedir}/../iotdb-core/node-commons/src/assembly/resources/conf</directory>
+            <excludes>
+                <exclude>iotdb-system.properties</exclude>
+            </excludes>
         </fileSet>
+        <!-- edge-specific configuration: tuned iotdb-system.properties + 
merged logback. -->
         <fileSet>
             <outputDirectory>conf</outputDirectory>
-            
<directory>${project.basedir}/../iotdb-core/node-commons/src/assembly/resources/conf</directory>
+            
<directory>${project.basedir}/src/assembly/resources/conf-edge</directory>
         </fileSet>
         <fileSet>
             <outputDirectory>conf</outputDirectory>
             <directory>${project.basedir}/../scripts/conf</directory>
-            <excludes>
-                <exclude>ainode-env.*</exclude>
-                <exclude>**/ainode-env.*</exclude>
-                <exclude>iotdb-common.sh</exclude>
-                <exclude>**/iotdb-common.bat</exclude>
-            </excludes>
+            <includes>
+                <include>edge-env.sh</include>
+                <include>windows/edge-env.bat</include>
+            </includes>
             <fileMode>0755</fileMode>
         </fileSet>
         <fileSet>
@@ -79,13 +87,19 @@
             <filtered>true</filtered>
             <fileMode>0755</fileMode>
         </fileSet>
+        <!-- one pair of start/stop scripts for the merged process, plus the 
cli. -->
         <fileSet>
             <outputDirectory>sbin</outputDirectory>
             <directory>${project.basedir}/../scripts/sbin</directory>
-            <excludes>
-                <exclude>*ainode.*</exclude>
-                <exclude>**/*ainode.*</exclude>
-            </excludes>
+            <includes>
+                <include>start-edge.sh</include>
+                <include>stop-edge.sh</include>
+                <include>start-cli.sh</include>
+                <include>windows/start-edge.bat</include>
+                <include>windows/stop-edge.bat</include>
+                <include>windows/start-cli.bat</include>
+                <include>windows/start-cli-table.bat</include>
+            </includes>
             <fileMode>0755</fileMode>
         </fileSet>
         <fileSet>
diff --git 
a/distribution/src/assembly/resources/conf-edge/iotdb-system.properties 
b/distribution/src/assembly/resources/conf-edge/iotdb-system.properties
new file mode 100644
index 00000000000..e76a17a231c
--- /dev/null
+++ b/distribution/src/assembly/resources/conf-edge/iotdb-system.properties
@@ -0,0 +1,126 @@
+#
+# 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.
+#
+
+####################
+### Cluster Configuration
+####################
+
+cluster_name=defaultCluster
+
+####################
+### Seed ConfigNode
+####################
+
+cn_seed_config_node=127.0.0.1:10710
+
+dn_seed_config_node=127.0.0.1:10710
+
+####################
+### Node RPC Configuration
+####################
+
+cn_internal_address=127.0.0.1
+cn_internal_port=10710
+cn_consensus_port=10720
+
+dn_rpc_address=127.0.0.1
+dn_rpc_port=6667
+dn_internal_address=127.0.0.1
+dn_internal_port=10730
+dn_mpp_data_exchange_port=10740
+dn_schema_region_consensus_port=10750
+dn_data_region_consensus_port=10760
+
+####################
+### Replication configuration
+####################
+
+schema_replication_factor=1
+data_replication_factor=1
+
+####################
+### Directory Configuration
+####################
+
+# dn_data_dirs=data/datanode/data
+# dn_wal_dirs=data/datanode/wal
+
+####################
+### Metric Configuration
+####################
+
+# cn_metric_reporter_list=
+cn_metric_prometheus_reporter_port=9091
+
+# dn_metric_reporter_list=
+dn_metric_prometheus_reporter_port=9092
+
+####################
+### IoTDB Edge Tuning
+####################
+# The following defaults are tuned for the edge distribution: ConfigNode and
+# DataNode run in ONE JVM with a small fixed memory budget (see 
conf/edge-env.sh),
+# sharing the machine with other processes. Validated on x86 and Raspberry Pi 
4B.
+
+# ---- thread pools (small fixed sizes instead of CPU-core-based defaults) ----
+query_thread_count=2
+degree_of_query_parallelism=1
+mpp_data_exchange_core_pool_size=2
+mpp_data_exchange_max_pool_size=2
+flush_thread_count=2
+compaction_thread_count=2
+sub_compaction_thread_count=1
+compaction_schedule_thread_num=1
+pipe_subtask_executor_max_thread_num=2
+pipe_sink_selector_number=1
+pipe_sink_max_client_number=8
+model_inference_execution_thread_count=1
+continuous_query_submit_thread_count=1
+into_operation_execution_thread_count=1
+procedure_core_worker_thread_count=2
+partition_table_recover_worker_num=2
+max_sub_task_num_for_information_table_scan=1
+load_active_listening_max_thread_num=1
+dn_selector_thread_nums_of_client_manager=1
+cn_selector_thread_nums_of_client_manager=1
+max_allowed_concurrent_queries=100
+
+# ---- memory / file buffers ----
+wal_buffer_size_in_byte=1048576
+group_size_in_byte=4194304
+target_compaction_file_size=134217728
+into_operation_buffer_size_in_byte=8388608
+batch_size=10000
+schema_region_ratis_log_appender_buffer_size_max=4194304
+config_node_ratis_log_appender_buffer_size_max=4194304
+
+# ---- background io politeness (share disks with other processes) ----
+compaction_write_throughput_mb_per_sec=8
+partition_table_recover_max_read_mb_per_sec=5
+
+# ---- single-node region / partition layout ----
+schema_region_group_extension_policy=CUSTOM
+default_schema_region_group_num_per_database=1
+data_region_group_extension_policy=CUSTOM
+default_data_region_group_num_per_database=1
+series_slot_num=1
+
+# ---- metrics off (the internal MetricService is shared by both nodes) ----
+cn_metric_level=OFF
+dn_metric_level=OFF
diff --git a/distribution/src/assembly/resources/conf-edge/logback-edge.xml 
b/distribution/src/assembly/resources/conf-edge/logback-edge.xml
new file mode 100644
index 00000000000..58d31b8e84d
--- /dev/null
+++ b/distribution/src/assembly/resources/conf-edge/logback-edge.xml
@@ -0,0 +1,252 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+
+    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.
+
+-->
+<configuration scan="true" scanPeriod="60 seconds">
+    <jmxConfigurator/>
+    <!-- prevent logback from outputting its own status at the start of every 
log -->
+    <statusListener class="ch.qos.logback.core.status.NopStatusListener"/>
+    <appender class="ch.qos.logback.core.rolling.RollingFileAppender" 
name="FILEERROR">
+        <file>${IOTDB_HOME}/logs/log_edge_error.log</file>
+        <rollingPolicy 
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            
<fileNamePattern>${IOTDB_HOME}/logs/log-edge-error-%d{yyyyMMdd}.log.gz</fileNamePattern>
+            <maxHistory>30</maxHistory>
+        </rollingPolicy>
+        <append>true</append>
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>%d [%t] %-5p %C{25}:%L - %m %n</pattern>
+            <charset>utf-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>error</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+    <appender class="ch.qos.logback.core.rolling.RollingFileAppender" 
name="FILEWARN">
+        <file>${IOTDB_HOME}/logs/log_edge_warn.log</file>
+        <rollingPolicy 
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            
<fileNamePattern>${IOTDB_HOME}/logs/log-edge-warn-%d{yyyyMMdd}.log.gz</fileNamePattern>
+            <maxHistory>30</maxHistory>
+        </rollingPolicy>
+        <append>true</append>
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>%d [%t] %-5p %C{25}:%L - %m %n</pattern>
+            <charset>utf-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>WARN</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+    <appender class="ch.qos.logback.core.rolling.RollingFileAppender" 
name="FILEDEBUG">
+        <file>${IOTDB_HOME}/logs/log_edge_debug.log</file>
+        <rollingPolicy 
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            
<fileNamePattern>${IOTDB_HOME}/logs/log-edge-debug-%d{yyyyMMdd}.log.gz</fileNamePattern>
+            <maxHistory>30</maxHistory>
+        </rollingPolicy>
+        <append>true</append>
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>%d [%t] %-5p %C{25}:%L - %m %n</pattern>
+            <charset>utf-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>DEBUG</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+    <appender class="ch.qos.logback.core.rolling.RollingFileAppender" 
name="FILETRACE">
+        <file>${IOTDB_HOME}/logs/log_edge_trace.log</file>
+        <rollingPolicy 
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            
<fileNamePattern>${IOTDB_HOME}/logs/log-edge-trace-%d{yyyyMMdd}.log.gz</fileNamePattern>
+            <maxHistory>30</maxHistory>
+        </rollingPolicy>
+        <append>true</append>
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>%d [%t] %-5p %C{25}:%L - %m %n</pattern>
+            <charset>utf-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.LevelFilter">
+            <level>TRACE</level>
+            <onMatch>ACCEPT</onMatch>
+            <onMismatch>DENY</onMismatch>
+        </filter>
+    </appender>
+    <appender class="ch.qos.logback.core.ConsoleAppender" name="stdout">
+        <Target>System.out</Target>
+        <encoder>
+            <pattern>%d [%t] %-5p %C{25}:%L - %m %n</pattern>
+            <charset>utf-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>${CONSOLE_LOG_LEVEL:-DEBUG}</level>
+        </filter>
+    </appender>
+    <!-- a log appender that collect all log records whose level is greater 
than debug-->
+    <appender class="ch.qos.logback.core.rolling.RollingFileAppender" 
name="FILEALL">
+        <file>${IOTDB_HOME}/logs/log_edge_all.log</file>
+        <rollingPolicy 
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            
<fileNamePattern>${IOTDB_HOME}/logs/log-edge-all-%d{yyyyMMdd}.log.gz</fileNamePattern>
+            <maxHistory>30</maxHistory>
+        </rollingPolicy>
+        <append>true</append>
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>%d [%t] %-5p %C{25}:%L - %m %n</pattern>
+            <charset>utf-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>INFO</level>
+        </filter>
+    </appender>
+    <appender class="ch.qos.logback.core.rolling.RollingFileAppender" 
name="FILE_COST_MEASURE">
+        <file>${IOTDB_HOME}/logs/log_edge_measure.log</file>
+        <rollingPolicy 
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            
<fileNamePattern>${IOTDB_HOME}/logs/log-edge-measure-%d{yyyyMMdd}.log.gz</fileNamePattern>
+            <maxHistory>30</maxHistory>
+        </rollingPolicy>
+        <append>true</append>
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>%d [%t] %-5p %C{25}:%L - %m %n</pattern>
+            <charset>utf-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>INFO</level>
+        </filter>
+    </appender>
+    <appender class="ch.qos.logback.core.rolling.RollingFileAppender" 
name="QUERY_DEBUG">
+        <file>${IOTDB_HOME}/logs/log_edge_query_debug.log</file>
+        <rollingPolicy 
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            
<fileNamePattern>${IOTDB_HOME}/logs/log-edge-query-debug-%d{yyyyMMdd}.log.gz</fileNamePattern>
+            <maxHistory>30</maxHistory>
+        </rollingPolicy>
+        <append>true</append>
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>%d [%t] %C{25}:%L - %m %n</pattern>
+            <charset>utf-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>INFO</level>
+        </filter>
+    </appender>
+    <appender class="ch.qos.logback.core.rolling.RollingFileAppender" 
name="SLOW_SQL">
+        <file>${IOTDB_HOME}/logs/log_edge_slow_sql.log</file>
+        <rollingPolicy 
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            
<fileNamePattern>${IOTDB_HOME}/logs/log-edge-slow-sql-%d{yyyyMMdd}.log.gz</fileNamePattern>
+            <maxHistory>30</maxHistory>
+        </rollingPolicy>
+        <append>true</append>
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>%d [%t] %-5p %C{25}:%L - %m %n</pattern>
+            <charset>utf-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>INFO</level>
+        </filter>
+    </appender>
+    <appender class="ch.qos.logback.core.rolling.RollingFileAppender" 
name="SAMPLED_QUERIES">
+        <file>${IOTDB_HOME}/logs/log_edge_sampled_queries.log</file>
+        <rollingPolicy 
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            
<fileNamePattern>${IOTDB_HOME}/logs/log-edge-sampled-queries-%d{yyyyMMdd}.log.gz</fileNamePattern>
+            <maxHistory>30</maxHistory>
+        </rollingPolicy>
+        <append>true</append>
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>%d %m %n</pattern>
+            <charset>utf-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>INFO</level>
+        </filter>
+    </appender>
+    <appender class="ch.qos.logback.core.rolling.RollingFileAppender" 
name="COMPACTION">
+        <file>${IOTDB_HOME}/logs/log_edge_compaction.log</file>
+        <rollingPolicy 
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            
<fileNamePattern>${IOTDB_HOME}/logs/log-edge-compaction-%d{yyyyMMdd}.log.gz</fileNamePattern>
+            <maxHistory>30</maxHistory>
+        </rollingPolicy>
+        <append>true</append>
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>%d [%t] %-5p %C{25}:%L - %m %n</pattern>
+            <charset>utf-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>INFO</level>
+        </filter>
+    </appender>
+    <appender class="ch.qos.logback.core.rolling.RollingFileAppender" 
name="EXPLAIN_ANALYZE">
+        <file>${IOTDB_HOME}/logs/log_explain_analyze.log</file>
+        <rollingPolicy 
class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
+            
<fileNamePattern>${IOTDB_HOME}/logs/log-edge-explain-%d{yyyyMMdd}.log.gz</fileNamePattern>
+            <maxHistory>30</maxHistory>
+        </rollingPolicy>
+        <append>true</append>
+        <encoder class="ch.qos.logback.classic.encoder.PatternLayoutEncoder">
+            <pattern>%d [%t] %-5p %C{25}:%L - %m %n</pattern>
+            <charset>utf-8</charset>
+        </encoder>
+        <filter class="ch.qos.logback.classic.filter.ThresholdFilter">
+            <level>INFO</level>
+        </filter>
+    </appender>
+    <root level="info">
+        <appender-ref ref="FILETRACE"/>
+        <appender-ref ref="FILEDEBUG"/>
+        <appender-ref ref="FILEWARN"/>
+        <appender-ref ref="FILEERROR"/>
+        <appender-ref ref="FILEALL"/>
+        <appender-ref ref="stdout"/>
+    </root>
+    <logger level="OFF" name="io.moquette.broker.metrics.MQTTMessageLogger"/>
+    <logger level="info" name="org.apache.iotdb.db.service"/>
+    <logger level="info" name="org.apache.iotdb.db.conf"/>
+    <logger level="info" name="org.apache.iotdb.db.cost.statistic">
+        <appender-ref ref="FILE_COST_MEASURE"/>
+    </logger>
+    <logger level="info" name="QUERY_DEBUG">
+        <appender-ref ref="QUERY_DEBUG"/>
+    </logger>
+    <logger level="info" name="SLOW_SQL" additivity="false">
+        <appender-ref ref="SLOW_SQL"/>
+    </logger>
+    <logger level="info" name="SAMPLED_QUERIES" additivity="false">
+        <appender-ref ref="SAMPLED_QUERIES"/>
+    </logger>
+    <logger level="info" name="QUERY_FREQUENCY">
+        <appender-ref ref="QUERY_FREQUENCY"/>
+    </logger>
+    <logger level="info" name="DETAILED_FAILURE_QUERY_TRACE"/>
+    <logger level="info" name="COMPACTION">
+        <appender-ref ref="COMPACTION"/>
+    </logger>
+    <logger level="info" name="org.apache.iotdb.pipe.api">
+        <appender-ref ref="PIPE"/>
+    </logger>
+    <logger level="info" name="org.apache.iotdb.db.pipe">
+        <appender-ref ref="PIPE"/>
+    </logger>
+    <logger level="info" name="org.apache.iotdb.commons.pipe">
+        <appender-ref ref="PIPE"/>
+    </logger>
+    <logger level="info" name="EXPLAIN_ANALYZE" additivity="false">
+        <appender-ref ref="EXPLAIN_ANALYZE"/>
+    </logger>
+</configuration>
diff --git 
a/iotdb-core/confignode/src/main/i18n/en/org/apache/iotdb/confignode/i18n/ConfigNodeMessages.java
 
b/iotdb-core/confignode/src/main/i18n/en/org/apache/iotdb/confignode/i18n/ConfigNodeMessages.java
index 3a5f279f222..07bcc36bd12 100644
--- 
a/iotdb-core/confignode/src/main/i18n/en/org/apache/iotdb/confignode/i18n/ConfigNodeMessages.java
+++ 
b/iotdb-core/confignode/src/main/i18n/en/org/apache/iotdb/confignode/i18n/ConfigNodeMessages.java
@@ -664,4 +664,13 @@ public final class ConfigNodeMessages {
   public static final String
       
EXCEPTION_FAILED_TO_CREATE_OR_ALTER_TOPIC_ARG_AND_ARG_ARE_ONLY_SUPPORTED_FOR_INCREMENTAL_TOPICS_D86CEA8E
 =
           "Failed to create or alter topic, %s and %s are only supported for 
incremental topics";
+  public static final String 
LOG_STARTING_IOTDB_EDGE_CONFIGNODE_AND_DATANODE_IN_ONE_77F32605 =
+      "Starting IoTDB Edge: ConfigNode and DataNode in one process";
+  public static final String 
LOG_IOTDB_EDGE_CONFIGNODE_IS_READY_STARTING_DATANODE_6729159E =
+      "IoTDB Edge: ConfigNode is ready, starting DataNode";
+  public static final String 
EXCEPTION_IOTDB_EDGE_CONFIGNODE_BOOTSTRAP_FAILED_02EEE59A =
+      "IoTDB Edge: ConfigNode bootstrap failed";
+  public static final String
+      
EXCEPTION_IOTDB_EDGE_CONFIGNODE_INTERNAL_PORT_ARG_IS_NOT_READY_WITHIN_03697FF5 =
+          "IoTDB Edge: ConfigNode internal port %s is not ready within %s ms";
 }
diff --git 
a/iotdb-core/confignode/src/main/i18n/zh/org/apache/iotdb/confignode/i18n/ConfigNodeMessages.java
 
b/iotdb-core/confignode/src/main/i18n/zh/org/apache/iotdb/confignode/i18n/ConfigNodeMessages.java
index 2956f59e674..d7ad32ddeca 100644
--- 
a/iotdb-core/confignode/src/main/i18n/zh/org/apache/iotdb/confignode/i18n/ConfigNodeMessages.java
+++ 
b/iotdb-core/confignode/src/main/i18n/zh/org/apache/iotdb/confignode/i18n/ConfigNodeMessages.java
@@ -707,4 +707,13 @@ public final class ConfigNodeMessages {
   public static final String
       
EXCEPTION_FAILED_TO_CREATE_OR_ALTER_TOPIC_ARG_AND_ARG_ARE_ONLY_SUPPORTED_FOR_INCREMENTAL_TOPICS_D86CEA8E
 =
           "创建或修改 topic 失败,%s 和 %s 仅支持 incremental 模式的 topic";
+  public static final String 
LOG_STARTING_IOTDB_EDGE_CONFIGNODE_AND_DATANODE_IN_ONE_77F32605 =
+      "正在启动 IoTDB Edge:ConfigNode 与 DataNode 运行于同一进程";
+  public static final String 
LOG_IOTDB_EDGE_CONFIGNODE_IS_READY_STARTING_DATANODE_6729159E =
+      "IoTDB Edge:ConfigNode 已就绪,开始启动 DataNode";
+  public static final String 
EXCEPTION_IOTDB_EDGE_CONFIGNODE_BOOTSTRAP_FAILED_02EEE59A =
+      "IoTDB Edge:ConfigNode 启动失败";
+  public static final String
+      
EXCEPTION_IOTDB_EDGE_CONFIGNODE_INTERNAL_PORT_ARG_IS_NOT_READY_WITHIN_03697FF5 =
+          "IoTDB Edge:ConfigNode 内部端口 %s 在 %s ms 内未就绪";
 }
diff --git 
a/iotdb-core/confignode/src/main/java/org/apache/iotdb/edge/EdgeNode.java 
b/iotdb-core/confignode/src/main/java/org/apache/iotdb/edge/EdgeNode.java
new file mode 100644
index 00000000000..061e12602d6
--- /dev/null
+++ b/iotdb-core/confignode/src/main/java/org/apache/iotdb/edge/EdgeNode.java
@@ -0,0 +1,114 @@
+/*
+ * 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.edge;
+
+import org.apache.iotdb.confignode.conf.ConfigNodeDescriptor;
+import org.apache.iotdb.confignode.i18n.ConfigNodeMessages;
+import org.apache.iotdb.confignode.service.ConfigNode;
+import org.apache.iotdb.db.service.DataNode;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.net.InetSocketAddress;
+import java.net.Socket;
+
+/**
+ * Entry point of the IoTDB Edge distribution: starts the ConfigNode and the 
DataNode services
+ * inside ONE JVM process, so that a resource-constrained edge machine only 
pays a single JVM's
+ * fixed overhead (metaspace, code cache, GC structures, thread stacks).
+ *
+ * <p>The ConfigNode is bootstrapped on a background thread first; once its 
internal RPC port
+ * accepts connections (i.e. the seed ConfigNode finished its consensus 
initialization), the
+ * DataNode is started on the main thread. Both services then keep the JVM 
alive with their own
+ * non-daemon threads. If either node fails fatally, its own error handling 
terminates the whole
+ * process, which is the intended single-process semantics of the edge 
deployment.
+ *
+ * <p>Note for launchers: both {@code CONFIGNODE_HOME} and {@code IOTDB_HOME} 
system properties must
+ * point to the installation directory (see {@code sbin/start-edge.sh}), 
otherwise the ConfigNode
+ * resolves its data directories against the process working directory.
+ */
+public final class EdgeNode {
+
+  private static final Logger LOGGER = LoggerFactory.getLogger(EdgeNode.class);
+
+  /** Max duration to wait for the ConfigNode internal RPC port to accept 
connections. */
+  private static final long CONFIG_NODE_READY_TIMEOUT_MS = 300_000L;
+
+  private static final long PORT_PROBE_INTERVAL_MS = 500L;
+
+  /** Extra delay after the port opens, leaving time for the leader election 
to settle. */
+  private static final long LEADER_ELECTION_GRACE_MS = 5_000L;
+
+  private EdgeNode() {}
+
+  public static void main(String[] args) throws Exception {
+    
LOGGER.info(ConfigNodeMessages.LOG_STARTING_IOTDB_EDGE_CONFIGNODE_AND_DATANODE_IN_ONE_77F32605);
+
+    final Throwable[] configNodeError = new Throwable[1];
+    Thread configNodeThread =
+        new Thread(
+            () -> {
+              try {
+                ConfigNode.main(new String[] {"-s"});
+              } catch (Throwable t) {
+                configNodeError[0] = t;
+              }
+            },
+            "EdgeNode-ConfigNode-Bootstrap");
+    configNodeThread.start();
+
+    int internalPort = 
ConfigNodeDescriptor.getInstance().getConf().getInternalPort();
+    waitPortOpen(internalPort, configNodeError);
+    if (configNodeError[0] != null) {
+      throw new IllegalStateException(
+          
ConfigNodeMessages.EXCEPTION_IOTDB_EDGE_CONFIGNODE_BOOTSTRAP_FAILED_02EEE59A,
+          configNodeError[0]);
+    }
+    Thread.sleep(LEADER_ELECTION_GRACE_MS);
+    
LOGGER.info(ConfigNodeMessages.LOG_IOTDB_EDGE_CONFIGNODE_IS_READY_STARTING_DATANODE_6729159E);
+
+    // DataNode.main returns after a successful start; the services of both 
nodes keep the JVM
+    // alive with non-daemon threads afterwards.
+    DataNode.main(new String[] {"-s"});
+  }
+
+  private static void waitPortOpen(int port, Throwable[] configNodeError)
+      throws InterruptedException {
+    long deadline = System.currentTimeMillis() + CONFIG_NODE_READY_TIMEOUT_MS;
+    while (System.currentTimeMillis() < deadline) {
+      if (configNodeError[0] != null) {
+        return;
+      }
+      try (Socket socket = new Socket()) {
+        socket.connect(new InetSocketAddress("127.0.0.1", port), 1000);
+        return;
+      } catch (Exception e) {
+        Thread.sleep(PORT_PROBE_INTERVAL_MS);
+      }
+    }
+    throw new IllegalStateException(
+        String.format(
+            ConfigNodeMessages
+                
.EXCEPTION_IOTDB_EDGE_CONFIGNODE_INTERNAL_PORT_ARG_IS_NOT_READY_WITHIN_03697FF5,
+            port,
+            CONFIG_NODE_READY_TIMEOUT_MS));
+  }
+}
diff --git a/scripts/conf/edge-env.sh b/scripts/conf/edge-env.sh
new file mode 100644
index 00000000000..627623047d4
--- /dev/null
+++ b/scripts/conf/edge-env.sh
@@ -0,0 +1,69 @@
+#!/bin/bash
+#
+# 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.
+#
+
+# IoTDB Edge runs ConfigNode and DataNode inside ONE JVM with a fixed, small
+# memory budget so that it can share a machine with other processes.
+# The defaults below target a total process RSS of about 512 MB and were
+# validated on x86 servers and Raspberry Pi 4B class devices.
+
+# On-heap memory of the merged process. Example values: '224M', '512M'.
+ON_HEAP_MEMORY="${ON_HEAP_MEMORY:-224M}"
+# Initial heap. Kept small so an idle edge instance stays light.
+INIT_HEAP_MEMORY="${INIT_HEAP_MEMORY:-64M}"
+# Off-heap (direct buffer) memory.
+OFF_HEAP_MEMORY="${OFF_HEAP_MEMORY:-96M}"
+
+if [ "${OFF_HEAP_MEMORY%"G"}" != "$OFF_HEAP_MEMORY" ]; then
+    off_heap_memory_size_in_mb=$(expr ${OFF_HEAP_MEMORY%"G"} \* 1024)
+else
+    off_heap_memory_size_in_mb=$(expr ${OFF_HEAP_MEMORY%"M"})
+fi
+# Max cached buffer size, which equals OFF_HEAP_MEMORY / io threads number 
(200)
+MAX_CACHED_BUFFER_SIZE=$(expr $off_heap_memory_size_in_mb \* 1024 \* 1024 / 
200)
+
+IOTDB_JMX_OPTS="$IOTDB_JMX_OPTS -Diotdb.jmx.local=true"
+IOTDB_JMX_OPTS="$IOTDB_JMX_OPTS -Xms${INIT_HEAP_MEMORY}"
+IOTDB_JMX_OPTS="$IOTDB_JMX_OPTS -Xmx${ON_HEAP_MEMORY}"
+IOTDB_JMX_OPTS="$IOTDB_JMX_OPTS -XX:MaxDirectMemorySize=${OFF_HEAP_MEMORY}"
+IOTDB_JMX_OPTS="$IOTDB_JMX_OPTS 
-Djdk.nio.maxCachedBufferSize=${MAX_CACHED_BUFFER_SIZE}"
+IOTDB_JMX_OPTS="$IOTDB_JMX_OPTS -XX:+CrashOnOutOfMemoryError"
+# Serial GC has the lowest fixed memory overhead; typical edge write rates 
leave
+# plenty of latency headroom for its pauses.
+IOTDB_JMX_OPTS="$IOTDB_JMX_OPTS -XX:+UseSerialGC"
+IOTDB_JMX_OPTS="$IOTDB_JMX_OPTS -Xss320k"
+IOTDB_JMX_OPTS="$IOTDB_JMX_OPTS -XX:MaxMetaspaceSize=160m"
+IOTDB_JMX_OPTS="$IOTDB_JMX_OPTS -XX:CompressedClassSpaceSize=40m"
+IOTDB_JMX_OPTS="$IOTDB_JMX_OPTS -XX:ReservedCodeCacheSize=64m"
+# Cap the processors the JVM sees, shrinking internal thread pools on big 
hosts.
+IOTDB_JMX_OPTS="$IOTDB_JMX_OPTS -XX:ActiveProcessorCount=2"
+IOTDB_JMX_OPTS="$IOTDB_JMX_OPTS -XX:+UnlockDiagnosticVMOptions"
+IOTDB_JMX_OPTS="$IOTDB_JMX_OPTS -XX:+UseCRC32Intrinsics"
+IOTDB_JMX_OPTS="$IOTDB_JMX_OPTS -XX:SafepointTimeoutDelay=1000"
+IOTDB_JMX_OPTS="$IOTDB_JMX_OPTS -XX:+SafepointTimeout"
+IOTDB_JMX_OPTS="$IOTDB_JMX_OPTS -Dsun.jnu.encoding=UTF-8 -Dfile.encoding=UTF-8"
+
+# Append tsfile locale option populated by Maven at package time
+# (see conf/iotdb-common.sh; empty in default build, "-Dtsfile.locale=zh" 
under with-zh-locale).
+if [ -n "$TSFILE_LOCALE_JVM_OPT" ]; then
+    IOTDB_JMX_OPTS="$IOTDB_JMX_OPTS $TSFILE_LOCALE_JVM_OPT"
+fi
+
+echo "IoTDB Edge on heap memory size = ${ON_HEAP_MEMORY}B, off heap memory 
size = ${OFF_HEAP_MEMORY}B"
+echo "If you want to change this configuration, please check conf/edge-env.sh."
diff --git a/scripts/conf/windows/edge-env.bat 
b/scripts/conf/windows/edge-env.bat
new file mode 100644
index 00000000000..0554d765e97
--- /dev/null
+++ b/scripts/conf/windows/edge-env.bat
@@ -0,0 +1,44 @@
+@echo off
+@REM
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements.  See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership.  The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License.  You may obtain a copy of the License at
+@REM
+@REM     http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied.  See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM
+
+@REM IoTDB Edge runs ConfigNode and DataNode inside ONE JVM with a fixed, small
+@REM memory budget (about 512 MB total process RSS by default).
+
+if "%ON_HEAP_MEMORY%"=="" set ON_HEAP_MEMORY=224M
+if "%INIT_HEAP_MEMORY%"=="" set INIT_HEAP_MEMORY=64M
+if "%OFF_HEAP_MEMORY%"=="" set OFF_HEAP_MEMORY=96M
+
+set IOTDB_JMX_OPTS=%IOTDB_JMX_OPTS% -Diotdb.jmx.local=true
+set IOTDB_JMX_OPTS=%IOTDB_JMX_OPTS% -Xms%INIT_HEAP_MEMORY%
+set IOTDB_JMX_OPTS=%IOTDB_JMX_OPTS% -Xmx%ON_HEAP_MEMORY%
+set IOTDB_JMX_OPTS=%IOTDB_JMX_OPTS% -XX:MaxDirectMemorySize=%OFF_HEAP_MEMORY%
+set IOTDB_JMX_OPTS=%IOTDB_JMX_OPTS% -XX:+CrashOnOutOfMemoryError
+set IOTDB_JMX_OPTS=%IOTDB_JMX_OPTS% -XX:+UseSerialGC
+set IOTDB_JMX_OPTS=%IOTDB_JMX_OPTS% -Xss320k
+set IOTDB_JMX_OPTS=%IOTDB_JMX_OPTS% -XX:MaxMetaspaceSize=160m
+set IOTDB_JMX_OPTS=%IOTDB_JMX_OPTS% -XX:CompressedClassSpaceSize=40m
+set IOTDB_JMX_OPTS=%IOTDB_JMX_OPTS% -XX:ReservedCodeCacheSize=64m
+set IOTDB_JMX_OPTS=%IOTDB_JMX_OPTS% -XX:ActiveProcessorCount=2
+set IOTDB_JMX_OPTS=%IOTDB_JMX_OPTS% -XX:+UnlockDiagnosticVMOptions
+set IOTDB_JMX_OPTS=%IOTDB_JMX_OPTS% -XX:+UseCRC32Intrinsics
+set IOTDB_JMX_OPTS=%IOTDB_JMX_OPTS% -Dsun.jnu.encoding=UTF-8 
-Dfile.encoding=UTF-8
+
+echo IoTDB Edge on heap memory size = %ON_HEAP_MEMORY%B, off heap memory size 
= %OFF_HEAP_MEMORY%B
+echo If you want to change this configuration, please check 
conf\windows\edge-env.bat.
diff --git a/scripts/sbin/start-edge.sh b/scripts/sbin/start-edge.sh
new file mode 100644
index 00000000000..6b5b9477b6b
--- /dev/null
+++ b/scripts/sbin/start-edge.sh
@@ -0,0 +1,92 @@
+#!/bin/bash
+#
+# 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.
+#
+
+# Start IoTDB Edge: ConfigNode + DataNode in one JVM process.
+
+if [ -z "${IOTDB_HOME}" ]; then
+    export IOTDB_HOME="$(cd "$(dirname "$0")"/.. && pwd)"
+fi
+if [ -z "${IOTDB_CONF}" ]; then
+    export IOTDB_CONF=${IOTDB_HOME}/conf
+fi
+export IOTDB_DATA_HOME=${IOTDB_DATA_HOME:-${IOTDB_HOME}}
+export IOTDB_LOG_DIR=${IOTDB_LOG_DIR:-${IOTDB_HOME}/logs}
+mkdir -p "${IOTDB_LOG_DIR}"
+
+# Refuse to start when any node port is already occupied.
+for p in 10710 10720 6667 10730 10740 10750 10760; do
+    (echo > /dev/tcp/127.0.0.1/$p) 2>/dev/null && { echo "ERROR: port $p is 
already in use, IoTDB Edge cannot start."; exit 1; }
+done
+
+if [ -f "${IOTDB_CONF}/iotdb-common.sh" ]; then
+    . "${IOTDB_CONF}/iotdb-common.sh"
+fi
+. "${IOTDB_CONF}/edge-env.sh"
+
+# find java in JAVA_HOME
+if [ -n "$JAVA_HOME" ]; then
+    for java in "$JAVA_HOME"/bin/amd64/java "$JAVA_HOME"/bin/java; do
+        if [ -x "$java" ]; then
+            JAVA="$java"
+            break
+        fi
+    done
+else
+    JAVA=java
+fi
+if [ -z "$JAVA" ]; then
+    echo "Unable to find java executable. Check JAVA_HOME and PATH environment 
variables." > /dev/stderr
+    exit 1
+fi
+
+illegal_access_params=""
+illegal_access_params="$illegal_access_params 
--add-opens=java.base/java.util.concurrent=ALL-UNNAMED"
+illegal_access_params="$illegal_access_params 
--add-opens=java.base/java.lang=ALL-UNNAMED"
+illegal_access_params="$illegal_access_params 
--add-opens=java.base/java.util=ALL-UNNAMED"
+illegal_access_params="$illegal_access_params 
--add-opens=java.base/java.nio=ALL-UNNAMED"
+illegal_access_params="$illegal_access_params 
--add-opens=java.base/java.io=ALL-UNNAMED"
+illegal_access_params="$illegal_access_params 
--add-opens=java.base/java.net=ALL-UNNAMED"
+
+CLASSPATH=""
+for f in "${IOTDB_HOME}"/lib/*.jar; do
+    CLASSPATH=${CLASSPATH}":"$f
+done
+
+iotdb_parms="-Dlogback.configurationFile=${IOTDB_CONF}/logback-edge.xml"
+iotdb_parms="$iotdb_parms -DIOTDB_HOME=${IOTDB_HOME}"
+# CONFIGNODE_HOME must also point to the installation directory, otherwise the
+# ConfigNode part resolves its data directories against the working directory.
+iotdb_parms="$iotdb_parms -DCONFIGNODE_HOME=${IOTDB_HOME}"
+iotdb_parms="$iotdb_parms -DIOTDB_DATA_HOME=${IOTDB_DATA_HOME}"
+iotdb_parms="$iotdb_parms -DTSFILE_HOME=${IOTDB_HOME}"
+iotdb_parms="$iotdb_parms -DIOTDB_CONF=${IOTDB_CONF}"
+iotdb_parms="$iotdb_parms -DCONFIGNODE_CONF=${IOTDB_CONF}"
+iotdb_parms="$iotdb_parms -DTSFILE_CONF=${IOTDB_CONF}"
+iotdb_parms="$iotdb_parms -Dname=iotdb.EdgeNode"
+iotdb_parms="$iotdb_parms -DIOTDB_LOG_DIR=${IOTDB_LOG_DIR}"
+iotdb_parms="$iotdb_parms -DCONFIGNODE_LOG_DIR=${IOTDB_LOG_DIR}"
+iotdb_parms="$iotdb_parms -DOFF_HEAP_MEMORY=${OFF_HEAP_MEMORY}"
+
+classname=org.apache.iotdb.edge.EdgeNode
+
+echo "Starting IoTDB Edge (ConfigNode + DataNode in one process)"
+nohup "$JAVA" $illegal_access_params $iotdb_parms $IOTDB_JMX_OPTS -cp 
"$CLASSPATH" "$classname" -s > "${IOTDB_LOG_DIR}/log_edge_console.log" 2>&1 &
+echo $! > "${IOTDB_HOME}/edge.pid"
+echo "IoTDB Edge started, pid $(cat "${IOTDB_HOME}/edge.pid"), console log: 
${IOTDB_LOG_DIR}/log_edge_console.log"
diff --git a/scripts/sbin/stop-edge.sh b/scripts/sbin/stop-edge.sh
new file mode 100644
index 00000000000..b3944ca9db2
--- /dev/null
+++ b/scripts/sbin/stop-edge.sh
@@ -0,0 +1,45 @@
+#!/bin/bash
+#
+# 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.
+#
+
+# Stop IoTDB Edge (the merged ConfigNode + DataNode process).
+
+IOTDB_HOME="$(cd "$(dirname "$0")"/.. && pwd)"
+
+if [ -f "${IOTDB_HOME}/edge.pid" ]; then
+    PID=$(cat "${IOTDB_HOME}/edge.pid")
+    if kill -0 "$PID" 2>/dev/null; then
+        kill "$PID"
+        for i in $(seq 1 30); do
+            kill -0 "$PID" 2>/dev/null || break
+            sleep 1
+        done
+        if kill -0 "$PID" 2>/dev/null; then
+            kill -9 "$PID"
+        fi
+        echo "IoTDB Edge process $PID stopped."
+    else
+        echo "IoTDB Edge process $PID is not running."
+    fi
+    rm -f "${IOTDB_HOME}/edge.pid"
+else
+    echo "No pid file found, trying to stop by process name."
+    pkill -f "org.apache.iotdb.edge.EdgeNode" 2>/dev/null
+fi
+exit 0
diff --git a/scripts/sbin/windows/start-edge.bat 
b/scripts/sbin/windows/start-edge.bat
new file mode 100644
index 00000000000..42d452ce24c
--- /dev/null
+++ b/scripts/sbin/windows/start-edge.bat
@@ -0,0 +1,105 @@
+@echo off
+@REM
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements.  See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership.  The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License.  You may obtain a copy of the License at
+@REM
+@REM     http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied.  See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM
+
+@REM set cmd format
+powershell -NoProfile -Command "$v=(Get-ItemProperty 
'HKLM:\SOFTWARE\Microsoft\Windows 
NT\CurrentVersion').CurrentMajorVersionNumber; if($v -gt 6) { cmd /c 'chcp 
65001' }"
+
+title IoTDB Edge
+
+echo ````````````````````````
+echo Starting IoTDB Edge (ConfigNode + DataNode in one process)
+echo ````````````````````````
+
+@REM 
-----------------------------------------------------------------------------
+@REM SET JAVA
+set PATH="%JAVA_HOME%\bin\";%PATH%
+set "FULL_VERSION="
+set "MAJOR_VERSION="
+set "MINOR_VERSION="
+
+for /f tokens^=2-5^ delims^=.-_+^" %%j in ('java -fullversion 2^>^&1') do (
+       set "FULL_VERSION=%%j-%%k-%%l-%%m"
+       IF "%%j" == "1" (
+           set "MAJOR_VERSION=%%k"
+           set "MINOR_VERSION=%%l"
+       ) else (
+           set "MAJOR_VERSION=%%j"
+           set "MINOR_VERSION=%%k"
+       )
+)
+
+set JAVA_VERSION=%MAJOR_VERSION%
+
+@REM IoTDB requires JDK 17 or later.
+IF "%JAVA_VERSION%" == "" (
+       echo Failed to determine Java version. IoTDB only supports jdk ^>= 17, 
please check your java installation.
+       goto finally
+)
+IF %JAVA_VERSION% LSS 17 (
+       echo IoTDB only supports jdk ^>= 17, please check your java version.
+       goto finally
+)
+
+@REM 
-----------------------------------------------------------------------------
+@REM SET DIRS
+pushd %~dp0..\..
+if NOT DEFINED IOTDB_HOME set IOTDB_HOME=%cd%
+popd
+if NOT DEFINED IOTDB_CONF set IOTDB_CONF=%IOTDB_HOME%\conf
+set IOTDB_LOG_DIR=%IOTDB_HOME%\logs
+if NOT EXIST %IOTDB_LOG_DIR% mkdir %IOTDB_LOG_DIR%
+
+@REM 
-----------------------------------------------------------------------------
+@REM SET JVM OPTIONS
+if EXIST %IOTDB_CONF%\windows\edge-env.bat (
+       call %IOTDB_CONF%\windows\edge-env.bat
+) else (
+       echo Can't find %IOTDB_CONF%\windows\edge-env.bat
+       goto finally
+)
+
+set 
illegal_access_params=--add-opens=java.base/java.util.concurrent=ALL-UNNAMED 
--add-opens=java.base/java.lang=ALL-UNNAMED 
--add-opens=java.base/java.util=ALL-UNNAMED 
--add-opens=java.base/java.nio=ALL-UNNAMED 
--add-opens=java.base/java.io=ALL-UNNAMED 
--add-opens=java.base/java.net=ALL-UNNAMED
+
+set CLASSPATH=%IOTDB_HOME%\lib\*
+set MAIN_CLASS=org.apache.iotdb.edge.EdgeNode
+
+@REM CONFIGNODE_HOME must also point to the installation directory, otherwise 
the
+@REM ConfigNode part resolves its data directories against the working 
directory.
+set iotdb_parms=-Dlogback.configurationFile="%IOTDB_CONF%\logback-edge.xml"
+set iotdb_parms=%iotdb_parms% -DIOTDB_HOME="%IOTDB_HOME%"
+set iotdb_parms=%iotdb_parms% -DCONFIGNODE_HOME="%IOTDB_HOME%"
+set iotdb_parms=%iotdb_parms% -DIOTDB_DATA_HOME="%IOTDB_HOME%"
+set iotdb_parms=%iotdb_parms% -DTSFILE_HOME="%IOTDB_HOME%"
+set iotdb_parms=%iotdb_parms% -DIOTDB_CONF="%IOTDB_CONF%"
+set iotdb_parms=%iotdb_parms% -DCONFIGNODE_CONF="%IOTDB_CONF%"
+set iotdb_parms=%iotdb_parms% -DTSFILE_CONF="%IOTDB_CONF%"
+set iotdb_parms=%iotdb_parms% -Dname=iotdb.EdgeNode
+set iotdb_parms=%iotdb_parms% -DIOTDB_LOG_DIR="%IOTDB_LOG_DIR%"
+set iotdb_parms=%iotdb_parms% -DCONFIGNODE_LOG_DIR="%IOTDB_LOG_DIR%"
+set iotdb_parms=%iotdb_parms% -DOFF_HEAP_MEMORY=%OFF_HEAP_MEMORY%
+
+@REM 
-----------------------------------------------------------------------------
+@REM START
+java %illegal_access_params% %iotdb_parms% %IOTDB_JMX_OPTS% -cp "%CLASSPATH%" 
%MAIN_CLASS% -s
+
+goto finally
+
+:finally
+pause
diff --git a/scripts/sbin/windows/stop-edge.bat 
b/scripts/sbin/windows/stop-edge.bat
new file mode 100644
index 00000000000..c07917fbba4
--- /dev/null
+++ b/scripts/sbin/windows/stop-edge.bat
@@ -0,0 +1,23 @@
+@echo off
+@REM
+@REM Licensed to the Apache Software Foundation (ASF) under one
+@REM or more contributor license agreements.  See the NOTICE file
+@REM distributed with this work for additional information
+@REM regarding copyright ownership.  The ASF licenses this file
+@REM to you under the Apache License, Version 2.0 (the
+@REM "License"); you may not use this file except in compliance
+@REM with the License.  You may obtain a copy of the License at
+@REM
+@REM     http://www.apache.org/licenses/LICENSE-2.0
+@REM
+@REM Unless required by applicable law or agreed to in writing,
+@REM software distributed under the License is distributed on an
+@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+@REM KIND, either express or implied.  See the License for the
+@REM specific language governing permissions and limitations
+@REM under the License.
+@REM
+
+echo Stopping IoTDB Edge (the merged ConfigNode + DataNode process)
+powershell -NoProfile -Command "Get-CimInstance Win32_Process -Filter 
\"name='java.exe'\" | Where-Object { $_.CommandLine -like 
'*org.apache.iotdb.edge.EdgeNode*' } | ForEach-Object { Stop-Process -Id 
$_.ProcessId -Force; Write-Host ('IoTDB Edge process ' + $_.ProcessId + ' 
stopped.') }"
+pause

Reply via email to