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

tanxinyu 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 5a88650  [IOTDB-2685] Create and start config node (#5247)
5a88650 is described below

commit 5a88650415bf786ead97679874d8eea442835cf7
Author: CRZbulabula <[email protected]>
AuthorDate: Wed Mar 16 14:53:01 2022 +0800

    [IOTDB-2685] Create and start config node (#5247)
    
    * stash
    
    * stash script
    
    * finish win and linux script
    
    * Add anotations
    
    * resolve reviews
    
    * resolve review
    
    * resolve conversations
    
    Co-authored-by: CRZbulabula <[email protected]>
---
 confignode/pom.xml                                 |  17 +-
 .../src/assembly/resources/conf/confignode-env.bat | 146 ++++++++++++
 .../src/assembly/resources/conf/confignode-env.sh  | 264 +++++++++++++++++++++
 .../resources/conf/iotdb-confignode.properties     |  10 +-
 .../{iotdb-confignode.properties => jmx.access}    |  21 +-
 .../{iotdb-confignode.properties => jmx.password}  |  21 +-
 .../assembly/resources/sbin/start-confignode.bat   | 122 ++++++++++
 .../assembly/resources/sbin/start-confignode.sh    |  77 ++++++
 .../assembly/resources/sbin/stop-confignode.bat    |  38 +++
 .../resources/sbin/stop-confignode.sh}             |  32 ++-
 .../iotdb/confignode/conf/ConfigNodeConf.java      |   5 +-
 .../iotdb/confignode/conf/ConfigNodeConfCheck.java | 136 +++++++++++
 .../iotdb/confignode/conf/ConfigNodeConstant.java  |  28 ++-
 .../confignode/conf/ConfigNodeDescriptor.java      |  66 +++---
 .../ConfigNodeException.java}                      |  12 +-
 .../conf/RepeatConfigurationException.java}        |  26 +-
 .../startup/StartupException.java}                 |  16 +-
 .../iotdb/confignode/manager/ConfigManager.java    |   2 +-
 .../iotdb/confignode/service/ConfigNode.java       | 125 ++++++++++
 .../ConfigNodeMBean.java}                          |  13 +-
 .../register/IService.java}                        |  39 +--
 .../confignode/service/register/JMXService.java    | 105 ++++++++
 .../service/register/RegisterManager.java          |  82 +++++++
 .../register/ServiceType.java}                     |  30 ++-
 .../startup/StartupCheck.java}                     |  14 +-
 .../confignode/service/startup/StartupChecks.java  |  89 +++++++
 .../{impl => server}/ConfigNodeRPCServer.java      |   2 +-
 .../confignode/conf/ConfigNodeDescriptorTest.java  |  76 ------
 .../manager/hash/DeviceGroupHashExecutorTest.java  |   3 +-
 .../utils/ConfigNodeEnvironmentUtils.java          | 133 +++++++++++
 iotdb-commons/pom.xml                              |  32 +++
 .../apache/iotdb/commons}/hash/APHashExecutor.java |   2 +-
 .../iotdb/commons}/hash/BKDRHashExecutor.java      |   2 +-
 .../commons}/hash/DeviceGroupHashExecutor.java     |   2 +-
 .../apache/iotdb/commons}/hash/JSHashExecutor.java |   2 +-
 .../iotdb/commons}/hash/SDBMHashExecutor.java      |   2 +-
 pom.xml                                            |   1 +
 server/pom.xml                                     |   5 +
 38 files changed, 1539 insertions(+), 259 deletions(-)

diff --git a/confignode/pom.xml b/confignode/pom.xml
index e6a12af..388d5c7 100644
--- a/confignode/pom.xml
+++ b/confignode/pom.xml
@@ -46,10 +46,9 @@
             <version>${project.version}</version>
         </dependency>
         <dependency>
-            <groupId>org.apache.tomcat.embed</groupId>
-            <artifactId>tomcat-embed-core</artifactId>
-            <version>8.5.46</version>
-            <scope>test</scope>
+            <groupId>org.apache.iotdb</groupId>
+            <artifactId>iotdb-commons</artifactId>
+            <version>${project.version}</version>
         </dependency>
         <dependency>
             <groupId>org.jetbrains</groupId>
@@ -57,6 +56,16 @@
             <version>23.0.0</version>
             <scope>provided</scope>
         </dependency>
+        <dependency>
+            <groupId>junit</groupId>
+            <artifactId>junit</artifactId>
+            <version>${junit.version}</version>
+            <scope>test</scope>
+        </dependency>
+        <dependency>
+            <groupId>commons-io</groupId>
+            <artifactId>commons-io</artifactId>
+        </dependency>
     </dependencies>
     <build>
         <plugins>
diff --git a/confignode/src/assembly/resources/conf/confignode-env.bat 
b/confignode/src/assembly/resources/conf/confignode-env.bat
new file mode 100644
index 0000000..294b52b
--- /dev/null
+++ b/confignode/src/assembly/resources/conf/confignode-env.bat
@@ -0,0 +1,146 @@
+@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 off
+@REM true or false
+@REM DO NOT FORGET TO MODIFY THE PASSWORD FOR SECURITY 
(%CONFIGNODE_CONF%\jmx.password and %{CONFIGNODE_CONF%\jmx.access)
+set JMX_LOCAL="true"
+set JMX_PORT="32000"
+@REM only take effect when the jmx_local=false
+@REM You need to change this IP as a public IP if you want to remotely connect 
IoTDB ConfigNode by JMX.
+@REM  0.0.0.0 is not allowed
+set JMX_IP="127.0.0.1"
+
+if %JMX_LOCAL% == "false" (
+  echo "setting remote JMX..."
+  @REM you may have no permission to run chmod. If so, contact your system 
administrator.
+  set CONFIGNODE_JMX_OPTS=-Dcom.sun.management.jmxremote^
+  -Dcom.sun.management.jmxremote.port=%JMX_PORT%^
+  -Dcom.sun.management.jmxremote.rmi.port=%JMX_PORT%^
+  -Djava.rmi.server.randomIDs=true^
+  -Dcom.sun.management.jmxremote.ssl=false^
+  -Dcom.sun.management.jmxremote.authenticate=false^
+  -Dcom.sun.management.jmxremote.password.file=%CONFIGNODE_CONF%\jmx.password^
+  -Dcom.sun.management.jmxremote.access.file=%CONFIGNODE_CONF%\jmx.access^
+  -Djava.rmi.server.hostname=%JMX_IP%
+) else (
+  echo "setting local JMX..."
+)
+
+for /f %%b in ('wmic cpu get numberofcores ^| findstr "[0-9]"') do (
+       set system_cpu_cores=%%b
+)
+
+if %system_cpu_cores% LSS 1 set system_cpu_cores=1
+
+for /f  %%b in ('wmic ComputerSystem get TotalPhysicalMemory ^| findstr 
"[0-9]"') do (
+       set system_memory=%%b
+)
+
+echo wsh.echo FormatNumber(cdbl(%system_memory%)/(1024*1024), 0) > 
%temp%\tmp.vbs
+for /f "tokens=*" %%a in ('cscript //nologo %temp%\tmp.vbs') do set 
system_memory_in_mb=%%a
+del %temp%\tmp.vbs
+set system_memory_in_mb=%system_memory_in_mb:,=%
+
+set /a half_=%system_memory_in_mb%/2
+set /a quarter_=%half_%/2
+
+if %half_% GTR 1024 set half_=1024
+if %quarter_% GTR 65536 set quarter_=65536
+
+if %half_% GTR %quarter_% (
+       set max_heap_size_in_mb=%half_%
+) else set max_heap_size_in_mb=%quarter_%
+
+set MAX_HEAP_SIZE=%max_heap_size_in_mb%M
+set max_sensible_yg_per_core_in_mb=100
+set /a 
max_sensible_yg_in_mb=%max_sensible_yg_per_core_in_mb%*%system_cpu_cores%
+set /a desired_yg_in_mb=%max_heap_size_in_mb%/4
+
+if %desired_yg_in_mb% GTR %max_sensible_yg_in_mb% (
+       set HEAP_NEWSIZE=%max_sensible_yg_in_mb%M
+) else set HEAP_NEWSIZE=%desired_yg_in_mb%M
+
+@REM Maximum heap size
+@REM set MAX_HEAP_SIZE="2G"
+@REM Minimum heap size
+@REM set HEAP_NEWSIZE="2G"
+
+IF ["%CONFIGNODE_HEAP_OPTS%"] EQU [""] (
+       rem detect Java 8 or 11
+       IF "%JAVA_VERSION%" == "8" (
+               java -d64 -version >nul 2>&1
+               set CONFIGNODE_HEAP_OPTS=-Xmx%MAX_HEAP_SIZE% -Xms%HEAP_NEWSIZE% 
-Xloggc:"%CONFIGNODE_HOME%\gc.log" -XX:+PrintGCDateStamps -XX:+PrintGCDetails
+               goto end_config_setting
+       ) ELSE (
+               goto detect_jdk11_bit_version
+       )
+)
+
+:detect_jdk11_bit_version
+for /f "tokens=1-3" %%j in ('java -version 2^>^&1') do (
+       @rem echo %%j
+       @rem echo %%k
+       @rem echo %%l
+       set BIT_VERSION=%%l
+)
+
+@REM maximum direct memory size
+set MAX_DIRECT_MEMORY_SIZE=%MAX_HEAP_SIZE%
+@REM threads number that may use direct memory, including query threads(8) + 
merge threads(4) + space left for system(4)
+set threads_number=16
+@REM the size of buffer cache pool(IOV_MAX) depends on operating system
+set temp_buffer_pool_size=1024
+@REM Max cached buffer size, Note: unit can only be B!
+@REM which equals DIRECT_MEMORY_SIZE / threads_number / temp_buffer_pool_size
+set 
MAX_CACHED_BUFFER_SIZE=%max_heap_size_in_mb%*1024*1024/%threads_number%/%temp_buffer_pool_size%
+
+set CONFIGNODE_HEAP_OPTS=-Xmx%MAX_HEAP_SIZE% -Xms%HEAP_NEWSIZE% 
-Xlog:gc:"..\gc.log"
+set CONFIGNODE_HEAP_OPTS=%CONFIGNODE_HEAP_OPTS% 
-XX:MaxDirectMemorySize=%MAX_DIRECT_MEMORY_SIZE%
+set CONFIGNODE_HEAP_OPTS=%CONFIGNODE_HEAP_OPTS% 
-Djdk.nio.maxCachedBufferSize=%MAX_CACHED_BUFFER_SIZE%
+
+@REM You can put your env variable here
+@REM set JAVA_HOME=%JAVA_HOME%
+
+:end_config_setting
+@REM set gc log.
+IF "%1" equ "printgc" (
+       IF "%JAVA_VERSION%" == "8" (
+           md %CONFIGNODE_HOME%\logs
+               set CONFIGNODE_HEAP_OPTS=%CONFIGNODE_HEAP_OPTS% 
-Xloggc:"%CONFIGNODE_HOME%\logs\gc.log" -XX:+PrintGCDateStamps 
-XX:+PrintGCDetails  -XX:+PrintGCApplicationStoppedTime 
-XX:+PrintPromotionFailure -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 
-XX:GCLogFileSize=10M
+       ) ELSE (
+               md %CONFIGNODE_HOME%\logs
+               set CONFIGNODE_HEAP_OPTS=%CONFIGNODE_HEAP_OPTS%  
-Xlog:gc=info,heap*=trace,age*=debug,safepoint=info,promotion*=trace:file="%CONFIGNODE_HOME%\logs\gc.log":time,uptime,pid,tid,level:filecount=10,filesize=10485760
+       )
+)
+
+@REM Add args for Java 11 and above, due to [JEP 396: Strongly Encapsulate JDK 
Internals by Default] (https://openjdk.java.net/jeps/396)
+IF "%JAVA_VERSION%" == "8" (
+    set ILLEGAL_ACCESS_PARAMS=
+) ELSE (
+    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
+)
+
+echo Maximum memory allocation pool = %MAX_HEAP_SIZE%, initial memory 
allocation pool = %HEAP_NEWSIZE%
+echo If you want to change this configuration, please check 
conf/confignode-env.sh(Unix or OS X, if you use Windows, check 
conf/confignode-env.bat).
diff --git a/confignode/src/assembly/resources/conf/confignode-env.sh 
b/confignode/src/assembly/resources/conf/confignode-env.sh
new file mode 100644
index 0000000..19773bb
--- /dev/null
+++ b/confignode/src/assembly/resources/conf/confignode-env.sh
@@ -0,0 +1,264 @@
+#!/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.
+#
+
+# You can put your env variable here
+# export JAVA_HOME=$JAVA_HOME
+
+# Set max number of open files
+max_num=$(ulimit -n)
+if [ $max_num -le 65535 ]; then
+    ulimit -n 65535
+    if [ $? -ne 0 ]; then
+        echo "Warning: Failed to set max number of files to be 65535, maybe 
you need to use 'sudo ulimit -n 65535' to set it when you use iotdb ConfigNode 
in production environments."
+    fi
+fi
+
+# Set somaxconn to a better value to avoid meaningless connection reset issues 
when the system is under high load.
+# The original somaxconn will be set back when the system reboots.
+# For more detail, see: 
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=19f92a030ca6d772ab44b22ee6a01378a8cb32d4
+SOMAXCONN=65535
+case "$(uname)" in
+    Linux)
+        somaxconn=$(sysctl -n net.core.somaxconn)
+        if [ "$somaxconn" -lt $SOMAXCONN ]; then
+            echo "WARN:"
+            echo "WARN: the value of net.core.somaxconn (=$somaxconn) is too 
small, please set it to a larger value using the following command."
+            echo "WARN:     sudo sysctl -w net.core.somaxconn=$SOMAXCONN"
+            echo "WARN: The original net.core.somaxconn value will be set back 
when the os reboots."
+            echo "WARN:"
+        fi
+    ;;
+    FreeBSD | Darwin)
+        somaxconn=$(sysctl -n kern.ipc.somaxconn)
+        if [ "$somaxconn" -lt $SOMAXCONN ]; then
+            echo "WARN:"
+            echo "WARN: the value of kern.ipc.somaxconn (=$somaxconn) is too 
small, please set it to a larger value using the following command."
+            echo "WARN:     sudo sysctl -w kern.ipc.somaxconn=$SOMAXCONN"
+            echo "WARN: The original kern.ipc.somaxconn value will be set back 
when the os reboots."
+            echo "WARN:"
+        fi
+    ;;
+esac
+
+calculate_heap_sizes()
+{
+    case "`uname`" in
+        Linux)
+            system_memory_in_mb=`free -m| sed -n '2p' | awk '{print $2}'`
+            system_cpu_cores=`egrep -c 'processor([[:space:]]+):.*' 
/proc/cpuinfo`
+        ;;
+        FreeBSD)
+            system_memory_in_bytes=`sysctl hw.physmem | awk '{print $2}'`
+            system_memory_in_mb=`expr $system_memory_in_bytes / 1024 / 1024`
+            system_cpu_cores=`sysctl hw.ncpu | awk '{print $2}'`
+        ;;
+        SunOS)
+            system_memory_in_mb=`prtconf | awk '/Memory size:/ {print $3}'`
+            system_cpu_cores=`psrinfo | wc -l`
+        ;;
+        Darwin)
+            system_memory_in_bytes=`sysctl hw.memsize | awk '{print $2}'`
+            system_memory_in_mb=`expr $system_memory_in_bytes / 1024 / 1024`
+            system_cpu_cores=`sysctl hw.ncpu | awk '{print $2}'`
+        ;;
+        *)
+            # assume reasonable defaults for e.g. a modern desktop or
+            # cheap server
+            system_memory_in_mb="2048"
+            system_cpu_cores="2"
+        ;;
+    esac
+
+    # some systems like the raspberry pi don't report cores, use at least 1
+    if [ "$system_cpu_cores" -lt "1" ]
+    then
+        system_cpu_cores="1"
+    fi
+
+    # set max heap size based on the following
+    # max(min(1/2 ram, 1024MB), min(1/4 ram, 64GB))
+    # calculate 1/2 ram and cap to 1024MB
+    # calculate 1/4 ram and cap to 65536MB
+    # pick the max
+    half_system_memory_in_mb=`expr $system_memory_in_mb / 2`
+    quarter_system_memory_in_mb=`expr $half_system_memory_in_mb / 2`
+    if [ "$half_system_memory_in_mb" -gt "1024" ]
+    then
+        half_system_memory_in_mb="1024"
+    fi
+    if [ "$quarter_system_memory_in_mb" -gt "65536" ]
+    then
+        quarter_system_memory_in_mb="65536"
+    fi
+    if [ "$half_system_memory_in_mb" -gt "$quarter_system_memory_in_mb" ]
+    then
+        max_heap_size_in_mb="$half_system_memory_in_mb"
+    else
+        max_heap_size_in_mb="$quarter_system_memory_in_mb"
+    fi
+    MAX_HEAP_SIZE="${max_heap_size_in_mb}M"
+
+    # Young gen: min(max_sensible_per_modern_cpu_core * num_cores, 1/4 * heap 
size)
+    max_sensible_yg_per_core_in_mb="100"
+    max_sensible_yg_in_mb=`expr $max_sensible_yg_per_core_in_mb "*" 
$system_cpu_cores`
+
+    desired_yg_in_mb=`expr $max_heap_size_in_mb / 4`
+
+    if [ "$desired_yg_in_mb" -gt "$max_sensible_yg_in_mb" ]
+    then
+        HEAP_NEWSIZE="${max_sensible_yg_in_mb}M"
+    else
+        HEAP_NEWSIZE="${desired_yg_in_mb}M"
+    fi
+}
+
+
+# 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
+
+# Determine the sort of JVM we'll be running on.
+java_ver_output=`"$JAVA" -version 2>&1`
+jvmver=`echo "$java_ver_output" | grep '[openjdk|java] version' | awk -F'"' 
'NR==1 {print $2}' | cut -d\- -f1`
+JVM_VERSION=${jvmver%_*}
+JVM_PATCH_VERSION=${jvmver#*_}
+if [ "$JVM_VERSION" \< "1.8" ] ; then
+    echo "IoTDB requires Java 8u40 or later."
+    exit 1;
+fi
+
+if [ "$JVM_VERSION" \< "1.8" ] && [ "$JVM_PATCH_VERSION" -lt 40 ] ; then
+    echo "IoTDB requires Java 8u40 or later."
+    exit 1;
+fi
+
+version_arr=(${JVM_VERSION//./ })
+
+illegal_access_params=""
+#GC log path has to be defined here because it needs to access CONFIGNODE_HOME
+if [ "${version_arr[0]}" = "1" ] ; then
+    # Java 8
+    MAJOR_VERSION=${version_arr[1]}
+    echo "$CONFIGNODE_JMX_OPTS" | grep -q "^-[X]loggc"
+    if [ "$?" = "1" ] ; then # [X] to prevent ccm from replacing this line
+        # only add -Xlog:gc if it's not mentioned in jvm-server.options file
+        mkdir -p ${CONFIGNODE_HOME}/logs
+        if [ "$#" -ge "1" -a "$1" == "printgc" ]; then
+            CONFIGNODE_JMX_OPTS="$CONFIGNODE_JMX_OPTS 
-Xloggc:${CONFIGNODE_HOME}/logs/gc.log  -XX:+PrintGCDateStamps 
-XX:+PrintGCDetails -XX:+PrintGCApplicationStoppedTime 
-XX:+PrintPromotionFailure -XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 
-XX:GCLogFileSize=10M"
+        fi
+    fi
+else
+    #JDK 11 and others
+    MAJOR_VERSION=${version_arr[0]}
+    # See description of https://bugs.openjdk.java.net/browse/JDK-8046148 for 
details about the syntax
+    # The following is the equivalent to -XX:+PrintGCDetails 
-XX:+UseGCLogFileRotation -XX:NumberOfGCLogFiles=10 -XX:GCLogFileSize=10M
+    echo "$CONFIGNODE_JMX_OPTS" | grep -q "^-[X]log:gc"
+    if [ "$?" = "1" ] ; then # [X] to prevent ccm from replacing this line
+        # only add -Xlog:gc if it's not mentioned in jvm-server.options file
+        mkdir -p ${CONFIGNODE_HOME}/logs
+        if [ "$#" -ge "1" -a "$1" == "printgc" ]; then
+            CONFIGNODE_JMX_OPTS="$CONFIGNODE_JMX_OPTS 
-Xlog:gc=info,heap*=info,age*=info,safepoint=info,promotion*=info:file=${CONFIGNODE_HOME}/logs/gc.log:time,uptime,pid,tid,level:filecount=10,filesize=10485760"
+        fi
+    fi
+    # Add argLine for Java 11 and above, due to [JEP 396: Strongly Encapsulate 
JDK Internals by Default] (https://openjdk.java.net/jeps/396)
+    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"
+fi
+
+
+
+calculate_heap_sizes
+
+## Set heap size by percentage of total memory
+#max_percentage=90
+#min_percentage=50
+#MAX_HEAP_SIZE="`expr $system_memory_in_mb \* $max_percentage / 100`M"
+#HEAP_NEWSIZE="`expr $system_memory_in_mb \* $min_percentage / 100`M"
+
+# Maximum heap size
+#MAX_HEAP_SIZE="2G"
+# Minimum heap size
+#HEAP_NEWSIZE="2G"
+# Maximum direct memory size
+MAX_DIRECT_MEMORY_SIZE=${MAX_HEAP_SIZE}
+
+# threads number that may use direct memory, including query threads(8) + 
merge threads(4) + space left for system(4)
+threads_number="16"
+# the size of buffer cache pool(IOV_MAX) depends on operating system
+temp_buffer_pool_size="1024"
+# Max cached buffer size, Note: unit can only be B!
+# which equals DIRECT_MEMORY_SIZE / threads_number / temp_buffer_pool_size
+MAX_CACHED_BUFFER_SIZE=`expr $max_heap_size_in_mb \* 1024 \* 1024 / 
$threads_number / $temp_buffer_pool_size`
+
+#true or false
+#DO NOT FORGET TO MODIFY THE PASSWORD FOR SECURITY 
(${CONFIGNODE_CONF}/jmx.password and ${CONFIGNODE_CONF}/jmx.access)
+#If you want to connect JMX Service by network in local machine, such as 
nodeTool.sh will try to connect 127.0.0.1:31999, please set JMX_LOCAL to false.
+JMX_LOCAL="true"
+
+JMX_PORT="32000"
+#only take effect when the jmx_local=false
+#You need to change this IP as a public IP if you want to remotely connect 
IoTDB ConfigNode by JMX.
+# 0.0.0.0 is not allowed
+JMX_IP="127.0.0.1"
+
+if [ ${JMX_LOCAL} = "false" ]; then
+  echo "setting remote JMX..."
+  #you may have no permission to run chmod. If so, contact your system 
administrator.
+  chmod 600 ${CONFIGNODE_CONF}/jmx.password
+  chmod 600 ${CONFIGNODE_CONF}/jmx.access
+  CONFIGNODE_JMX_OPTS="$CONFIGNODE_JMX_OPTS -Dcom.sun.management.jmxremote"
+  CONFIGNODE_JMX_OPTS="$CONFIGNODE_JMX_OPTS 
-Dcom.sun.management.jmxremote.port=$JMX_PORT"
+  CONFIGNODE_JMX_OPTS="$CONFIGNODE_JMX_OPTS 
-Dcom.sun.management.jmxremote.rmi.port=$JMX_PORT"
+  CONFIGNODE_JMX_OPTS="$CONFIGNODE_JMX_OPTS -Djava.rmi.server.randomIDs=true"
+  CONFIGNODE_JMX_OPTS="$CONFIGNODE_JMX_OPTS 
-Dcom.sun.management.jmxremote.ssl=false"
+  CONFIGNODE_JMX_OPTS="$CONFIGNODE_JMX_OPTS 
-Dcom.sun.management.jmxremote.authenticate=true"
+  CONFIGNODE_JMX_OPTS="$CONFIGNODE_JMX_OPTS 
-Dcom.sun.management.jmxremote.password.file=${CONFIGNODE_CONF}/jmx.password"
+  CONFIGNODE_JMX_OPTS="$CONFIGNODE_JMX_OPTS 
-Dcom.sun.management.jmxremote.access.file=${CONFIGNODE_CONF}/jmx.access"
+  CONFIGNODE_JMX_OPTS="$CONFIGNODE_JMX_OPTS -Djava.rmi.server.hostname=$JMX_IP"
+else
+  echo "setting local JMX..."
+fi
+
+
+CONFIGNODE_JMX_OPTS="$CONFIGNODE_JMX_OPTS -Xms${HEAP_NEWSIZE}"
+CONFIGNODE_JMX_OPTS="$CONFIGNODE_JMX_OPTS -Xmx${MAX_HEAP_SIZE}"
+CONFIGNODE_JMX_OPTS="$CONFIGNODE_JMX_OPTS 
-XX:MaxDirectMemorySize=${MAX_DIRECT_MEMORY_SIZE}"
+CONFIGNODE_JMX_OPTS="$CONFIGNODE_JMX_OPTS 
-Djdk.nio.maxCachedBufferSize=${MAX_CACHED_BUFFER_SIZE}"
+
+echo "Maximum memory allocation pool = ${MAX_HEAP_SIZE}B, initial memory 
allocation pool = ${HEAP_NEWSIZE}B"
+echo "If you want to change this configuration, please check 
conf/confignode-env.sh(Unix or OS X, if you use Windows, check 
conf/confignode-env.bat)."
+
diff --git a/confignode/src/assembly/resources/conf/iotdb-confignode.properties 
b/confignode/src/assembly/resources/conf/iotdb-confignode.properties
index 0dcb8b9..023027c 100644
--- a/confignode/src/assembly/resources/conf/iotdb-confignode.properties
+++ b/confignode/src/assembly/resources/conf/iotdb-confignode.properties
@@ -28,10 +28,10 @@
 # DeviceGroup hash algorithm
 # Datatype: String
 # These hashing algorithms are currently supported:
-# 1. org.apache.iotdb.confignode.manager.hash.BKDRHashExecutor(Default)
-# 2. org.apache.iotdb.confignode.manager.hash.APHashExecutor
-# 3. org.apache.iotdb.confignode.manager.hash.JSHashExecutor
-# 4. org.apache.iotdb.confignode.manager.hash.SDBMHashExecutor
+# 1. org.apache.iotdb.commons.hash.BKDRHashExecutor(Default)
+# 2. org.apache.iotdb.commons.hash.APHashExecutor
+# 3. org.apache.iotdb.commons.hash.JSHashExecutor
+# 4. org.apache.iotdb.commons.hash.SDBMHashExecutor
 # Also, if you want to implement your own hash algorithm, you can inherit the 
DeviceGroupHashExecutor class and
 # modify this parameter to correspond to your Java class
-# 
device_group_hash_executor_class=org.apache.iotdb.confignode.manager.hash.BKDRHashExecutor
\ No newline at end of file
+# 
device_group_hash_executor_class=org.apache.iotdb.commons.hash.BKDRHashExecutor
\ No newline at end of file
diff --git a/confignode/src/assembly/resources/conf/iotdb-confignode.properties 
b/confignode/src/assembly/resources/conf/jmx.access
similarity index 50%
copy from confignode/src/assembly/resources/conf/iotdb-confignode.properties
copy to confignode/src/assembly/resources/conf/jmx.access
index 0dcb8b9..d6b57bc 100644
--- a/confignode/src/assembly/resources/conf/iotdb-confignode.properties
+++ b/confignode/src/assembly/resources/conf/jmx.access
@@ -17,21 +17,6 @@
 # under the License.
 #
 
-####################
-### DeviceGroup Configuration
-####################
-
-# Number of DeviceGroups per StorageGroup
-# Datatype: int
-# device_group_count=10000
-
-# DeviceGroup hash algorithm
-# Datatype: String
-# These hashing algorithms are currently supported:
-# 1. org.apache.iotdb.confignode.manager.hash.BKDRHashExecutor(Default)
-# 2. org.apache.iotdb.confignode.manager.hash.APHashExecutor
-# 3. org.apache.iotdb.confignode.manager.hash.JSHashExecutor
-# 4. org.apache.iotdb.confignode.manager.hash.SDBMHashExecutor
-# Also, if you want to implement your own hash algorithm, you can inherit the 
DeviceGroupHashExecutor class and
-# modify this parameter to correspond to your Java class
-# 
device_group_hash_executor_class=org.apache.iotdb.confignode.manager.hash.BKDRHashExecutor
\ No newline at end of file
+# see 
https://docs.oracle.com/javase/8/docs/technotes/guides/management/agent.html#gdeup
+iotdb readonly
+root readwrite
diff --git a/confignode/src/assembly/resources/conf/iotdb-confignode.properties 
b/confignode/src/assembly/resources/conf/jmx.password
similarity index 50%
copy from confignode/src/assembly/resources/conf/iotdb-confignode.properties
copy to confignode/src/assembly/resources/conf/jmx.password
index 0dcb8b9..9055f01 100644
--- a/confignode/src/assembly/resources/conf/iotdb-confignode.properties
+++ b/confignode/src/assembly/resources/conf/jmx.password
@@ -17,21 +17,6 @@
 # under the License.
 #
 
-####################
-### DeviceGroup Configuration
-####################
-
-# Number of DeviceGroups per StorageGroup
-# Datatype: int
-# device_group_count=10000
-
-# DeviceGroup hash algorithm
-# Datatype: String
-# These hashing algorithms are currently supported:
-# 1. org.apache.iotdb.confignode.manager.hash.BKDRHashExecutor(Default)
-# 2. org.apache.iotdb.confignode.manager.hash.APHashExecutor
-# 3. org.apache.iotdb.confignode.manager.hash.JSHashExecutor
-# 4. org.apache.iotdb.confignode.manager.hash.SDBMHashExecutor
-# Also, if you want to implement your own hash algorithm, you can inherit the 
DeviceGroupHashExecutor class and
-# modify this parameter to correspond to your Java class
-# 
device_group_hash_executor_class=org.apache.iotdb.confignode.manager.hash.BKDRHashExecutor
\ No newline at end of file
+# see 
https://docs.oracle.com/javase/8/docs/technotes/guides/management/agent.html#gdeup
+iotdb passw!d
+root  passw!d
\ No newline at end of file
diff --git a/confignode/src/assembly/resources/sbin/start-confignode.bat 
b/confignode/src/assembly/resources/sbin/start-confignode.bat
new file mode 100644
index 0000000..c80fbf7
--- /dev/null
+++ b/confignode/src/assembly/resources/sbin/start-confignode.bat
@@ -0,0 +1,122 @@
+@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 off
+echo ```````````````````````````
+echo Starting IoTDB ConfigNode
+echo ```````````````````````````
+
+
+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 we do not check jdk that version less than 1.8 because they are too 
stale...
+IF "%JAVA_VERSION%" == "6" (
+       echo IoTDB only supports jdk >= 8, please check your java version.
+       goto finally
+)
+IF "%JAVA_VERSION%" == "7" (
+       echo IoTDB only supports jdk >= 8, please check your java version.
+       goto finally
+)
+
+if "%OS%" == "Windows_NT" setlocal
+
+pushd %~dp0..
+if NOT DEFINED CONFIGNODE_HOME set CONFIGNODE_HOME=%cd%
+popd
+
+set CONFIGNODE_CONF=%CONFIGNODE_HOME%\conf
+
+@setlocal ENABLEDELAYEDEXPANSION ENABLEEXTENSIONS
+set is_conf_path=false
+for %%i in (%*) do (
+       IF "%%i" == "-c" (
+               set is_conf_path=true
+       ) ELSE IF "!is_conf_path!" == "true" (
+               set is_conf_path=false
+               set CONFIGNODE_CONF=%%i
+       ) ELSE (
+               set CONF_PARAMS=!CONF_PARAMS! %%i
+       )
+)
+
+IF EXIST "%CONFIGNODE_CONF%\confignode-env.bat" (
+    CALL "%CONFIGNODE_CONF%\confignode-env.bat" %1
+    ) ELSE (
+    echo "can't find %CONFIGNODE_CONF%\confignode-env.bat"
+    )
+
+if NOT DEFINED MAIN_CLASS set 
MAIN_CLASS=org.apache.iotdb.confignode.service.ConfigNode
+if NOT DEFINED JAVA_HOME goto :err
+
+@REM 
-----------------------------------------------------------------------------
+@REM JVM Opts we'll use in legacy run or installation
+set JAVA_OPTS=-ea^
+ -DCONFIGNODE_HOME="%CONFIGNODE_HOME%"^
+ -DCONFIGNODE_CONF="%CONFIGNODE_CONF%"^
+ -Dsun.jnu.encoding=UTF-8^
+ -Dfile.encoding=UTF-8
+
+@REM ***** CLASSPATH library setting *****
+@REM Ensure that any user defined CLASSPATH variables are not used on startup
+set CLASSPATH="%CONFIGNODE_HOME%\lib\*"
+set CLASSPATH=%CLASSPATH%;iotdb.ConfigNode
+goto okClasspath
+
+:append
+set CLASSPATH=%CLASSPATH%;%1
+
+goto :eof
+
+@REM 
-----------------------------------------------------------------------------
+:okClasspath
+
+rem echo CLASSPATH: %CLASSPATH%
+
+"%JAVA_HOME%\bin\java" %ILLEGAL_ACCESS_PARAMS% %JAVA_OPTS% 
%CONFIGNODE_HEAP_OPTS% -cp %CLASSPATH% %CONFIGNODE_JMX_OPTS% %MAIN_CLASS% 
%CONF_PARAMS%
+goto finally
+
+:err
+echo JAVA_HOME environment variable must be set!
+pause
+
+
+@REM 
-----------------------------------------------------------------------------
+:finally
+
+pause
+
+ENDLOCAL
diff --git a/confignode/src/assembly/resources/sbin/start-confignode.sh 
b/confignode/src/assembly/resources/sbin/start-confignode.sh
new file mode 100644
index 0000000..5d2f360
--- /dev/null
+++ b/confignode/src/assembly/resources/sbin/start-confignode.sh
@@ -0,0 +1,77 @@
+#!/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.
+#
+
+
+echo ----------------------------
+echo Starting IoTDB ConfigNode
+echo ----------------------------
+
+if [ -z "${CONFIGNODE_HOME}" ]; then
+  export CONFIGNODE_HOME="`dirname "$0"`/.."
+fi
+
+CONFIGNODE_CONF=${CONFIGNODE_HOME}/conf
+
+is_conf_path=false
+for arg do
+  shift
+  if [ "$arg" == "-c" ]; then
+    is_conf_path=true
+    continue
+  fi
+  if [ $is_conf_path == true ]; then
+    CONFIGNODE_CONF=$arg
+    is_conf_path=false
+    continue
+  fi
+  set -- "$@" "$arg"
+done
+
+CONF_PARAMS=$*
+
+if [ -f "$CONFIGNODE_CONF/confignode-env.sh" ]; then
+    if [ "$#" -ge "1" -a "$1" == "printgc" ]; then
+      . "$CONFIGNODE_CONF/confignode-env.sh" "printgc"
+    else
+        . "$CONFIGNODE_CONF/confignode-env.sh"
+    fi
+else
+    echo "can't find $CONFIGNODE_CONF/confignode-env.sh"
+fi
+
+CLASSPATH=""
+for f in ${CONFIGNODE_HOME}/lib/*.jar; do
+  CLASSPATH=${CLASSPATH}":"$f
+done
+classname=org.apache.iotdb.confignode.service.ConfigNode
+
+launch_service()
+{
+       class="$1"
+       confignode_parms="$confignode_parms 
-DCONFIGNODE_HOME=${CONFIGNODE_HOME}"
+       confignode_parms="$confignode_parms 
-DCONFIGNODE_CONF=${CONFIGNODE_CONF}"
+       exec "$JAVA" $illegal_access_params $confignode_parms 
$CONFIGNODE_JMX_OPTS -cp "$CLASSPATH" "$class" $CONF_PARAMS
+       return $?
+}
+
+# Start up the service
+launch_service "$classname"
+
+exit $?
diff --git a/confignode/src/assembly/resources/sbin/stop-confignode.bat 
b/confignode/src/assembly/resources/sbin/stop-confignode.bat
new file mode 100644
index 0000000..9771f47
--- /dev/null
+++ b/confignode/src/assembly/resources/sbin/stop-confignode.bat
@@ -0,0 +1,38 @@
+@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 off
+
+set current_dir=%~dp0
+set superior_dir=%current_dir%\..\
+
+for /f  "eol=; tokens=2,2 delims==" %%i in ('findstr /i "rpc_port"
+%superior_dir%\conf\iotdb-confignode.properties') do (
+  set rpc_port=%%i
+)
+
+for /f  "eol=; tokens=2,2 delims==" %%i in ('findstr /i "rpc_address"
+%superior_dir%\conf\iotdb-confignode.properties') do (
+  set rpc_address=%%i
+)
+
+for /f "tokens=5" %%a in ('netstat /ano ^| findstr %rpc_address%:%rpc_port%') 
do (
+  taskkill /f /pid %%a
+)
+rem ps ax | grep -i 'confignode.ConfigNode' | grep -v grep | awk '{print $1}' 
| xargs kill -SIGTERM
diff --git a/confignode/src/test/resources/iotdb-confignode.properties 
b/confignode/src/assembly/resources/sbin/stop-confignode.sh
similarity index 50%
rename from confignode/src/test/resources/iotdb-confignode.properties
rename to confignode/src/assembly/resources/sbin/stop-confignode.sh
index 0dcb8b9..d4725bd 100644
--- a/confignode/src/test/resources/iotdb-confignode.properties
+++ b/confignode/src/assembly/resources/sbin/stop-confignode.sh
@@ -1,3 +1,4 @@
+#!/bin/sh
 #
 # Licensed to the Apache Software Foundation (ASF) under one
 # or more contributor license agreements.  See the NOTICE file
@@ -17,21 +18,18 @@
 # under the License.
 #
 
-####################
-### DeviceGroup Configuration
-####################
 
-# Number of DeviceGroups per StorageGroup
-# Datatype: int
-# device_group_count=10000
-
-# DeviceGroup hash algorithm
-# Datatype: String
-# These hashing algorithms are currently supported:
-# 1. org.apache.iotdb.confignode.manager.hash.BKDRHashExecutor(Default)
-# 2. org.apache.iotdb.confignode.manager.hash.APHashExecutor
-# 3. org.apache.iotdb.confignode.manager.hash.JSHashExecutor
-# 4. org.apache.iotdb.confignode.manager.hash.SDBMHashExecutor
-# Also, if you want to implement your own hash algorithm, you can inherit the 
DeviceGroupHashExecutor class and
-# modify this parameter to correspond to your Java class
-# 
device_group_hash_executor_class=org.apache.iotdb.confignode.manager.hash.BKDRHashExecutor
\ No newline at end of file
+CONFIGNODE_CONF="`dirname "$0"`/../conf"
+rpc_port=`sed '/^rpc_port=/!d;s/.*=//' 
${CONFIGNODE_CONF}/iotdb-confignode.properties`
+if type lsof > /dev/null; then
+  PID=$(lsof -t -i:${rpc_port})
+else
+  PID=$(ps ax | grep -i 'ConfigNode' | grep java | grep -v grep | awk '{print 
$1}')
+fi
+if [ -z "$PID" ]; then
+  echo "No ConfigNode server to stop"
+  exit 1
+else
+  kill -s TERM $PID
+  echo "close ConfigNode"
+fi
diff --git 
a/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConf.java 
b/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConf.java
index 746512b..5c19156 100644
--- 
a/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConf.java
+++ 
b/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConf.java
@@ -20,14 +20,11 @@ package org.apache.iotdb.confignode.conf;
 
 public class ConfigNodeConf {
 
-  public static final String CONF_NAME = "iotdb-confignode.properties";
-
   // Number of DeviceGroups per StorageGroup
   private int deviceGroupCount = 10000;
 
   // DeviceGroup hash executor class
-  private String deviceGroupHashExecutorClass =
-      "org.apache.iotdb.confignode.manager.hash.BKDRHashExecutor";
+  private String deviceGroupHashExecutorClass = 
"org.apache.iotdb.commons.hash.BKDRHashExecutor";
 
   public ConfigNodeConf() {
     // empty constructor
diff --git 
a/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConfCheck.java
 
b/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConfCheck.java
new file mode 100644
index 0000000..de93a5b
--- /dev/null
+++ 
b/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConfCheck.java
@@ -0,0 +1,136 @@
+/*
+ * 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.conf;
+
+import org.apache.iotdb.confignode.exception.conf.RepeatConfigurationException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.util.Objects;
+import java.util.Properties;
+
+/**
+ * ConfigNodeConfCheck checks parameters in iotdb-confignode.properties when 
started, and the
+ * consistency of some specific parameters on restart
+ */
+public class ConfigNodeConfCheck {
+
+  // TODO: Code optimize, reuse logic in iotdb-server
+
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(ConfigNodeConfCheck.class);
+
+  private static final ConfigNodeConf conf = 
ConfigNodeDescriptor.getInstance().getConf();
+
+  private Properties specialProperties;
+
+  public void checkConfig() throws RepeatConfigurationException, IOException {
+
+    String propsDir = ConfigNodeDescriptor.getInstance().getPropsDir();
+    if (propsDir == null) {
+      // Skip configuration check when developer mode or test mode
+      return;
+    }
+    specialProperties = new Properties();
+
+    File specialPropertiesFile =
+        new File(propsDir + File.separator + 
ConfigNodeConstant.SPECIAL_CONF_NAME);
+    if (!specialPropertiesFile.exists()) {
+      if (specialPropertiesFile.createNewFile()) {
+        LOGGER.info(
+            "Special configuration file {} for ConfigNode is created.",
+            specialPropertiesFile.getAbsolutePath());
+        writeSpecialProperties(specialPropertiesFile);
+        return;
+      } else {
+        LOGGER.error(
+            "Can't create special configuration file {} for ConfigNode. 
IoTDB-ConfigNode is shutdown.",
+            specialPropertiesFile.getAbsolutePath());
+        System.exit(-1);
+      }
+    }
+
+    FileInputStream inputStream = new FileInputStream(specialPropertiesFile);
+    specialProperties.load(inputStream);
+    checkSpecialProperties();
+    inputStream.close();
+  }
+
+  /**
+   * There are some special parameters that can't be changed after once we 
start ConfigNode.
+   * Therefore, store them in iotdb-confignode-special.properties at the first 
startup
+   */
+  private void writeSpecialProperties(File specialPropertiesFile) {
+    specialProperties.setProperty("device_group_count", 
String.valueOf(conf.getDeviceGroupCount()));
+    specialProperties.setProperty(
+        "device_group_hash_executor_class", 
conf.getDeviceGroupHashExecutorClass());
+    try {
+      specialProperties.store(new FileOutputStream(specialPropertiesFile), "");
+    } catch (IOException e) {
+      LOGGER.error(
+          "Can't store special properties file {}.", 
specialPropertiesFile.getAbsolutePath());
+    }
+  }
+
+  /** Ensure that special parameters are consistent with each startup except 
the first one */
+  private void checkSpecialProperties() throws RepeatConfigurationException {
+    int specialDeviceGroupCount =
+        Integer.parseInt(
+            specialProperties.getProperty(
+                "device_group_count", 
String.valueOf(conf.getDeviceGroupCount())));
+    if (specialDeviceGroupCount != conf.getDeviceGroupCount()) {
+      throw new RepeatConfigurationException(
+          "device_group_count",
+          String.valueOf(conf.getDeviceGroupCount()),
+          String.valueOf(specialDeviceGroupCount));
+    }
+
+    String specialDeviceGroupHashExecutorClass =
+        specialProperties.getProperty(
+            "device_group_hash_executor_class", 
conf.getDeviceGroupHashExecutorClass());
+    if (!Objects.equals(
+        specialDeviceGroupHashExecutorClass, 
conf.getDeviceGroupHashExecutorClass())) {
+      throw new RepeatConfigurationException(
+          "device_group_hash_executor_class",
+          conf.getDeviceGroupHashExecutorClass(),
+          specialDeviceGroupHashExecutorClass);
+    }
+  }
+
+  private static class ConfigNodeConfCheckHolder {
+
+    private static final ConfigNodeConfCheck INSTANCE = new 
ConfigNodeConfCheck();
+
+    private ConfigNodeConfCheckHolder() {
+      // empty constructor
+    }
+  }
+
+  public static ConfigNodeConfCheck getInstance() {
+    return ConfigNodeConfCheckHolder.INSTANCE;
+  }
+
+  private ConfigNodeConfCheck() {
+    LOGGER.info("Starting IoTDB Cluster ConfigNode " + 
ConfigNodeConstant.VERSION);
+  }
+}
diff --git 
a/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConstant.java
 
b/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConstant.java
index 0680a8e..5629d8d 100644
--- 
a/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConstant.java
+++ 
b/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConstant.java
@@ -20,11 +20,31 @@ package org.apache.iotdb.confignode.conf;
 
 public class ConfigNodeConstant {
 
+  // when running the program in IDE, we can not get the version info using
+  // getImplementationVersion()
+  public static final String VERSION =
+      ConfigNodeConstant.class.getPackage().getImplementationVersion() != null
+          ? ConfigNodeConstant.class.getPackage().getImplementationVersion()
+          : "UNKNOWN";
+
+  public static final String GLOBAL_NAME = "IoTDB ConfigNode";
+  public static final String CONFIGNODE_CONF = "CONFIGNODE_CONF";
+  public static final String CONFIGNODE_HOME = "CONFIGNODE_HOME";
+
+  public static final String ENV_FILE_NAME = "confignode-env";
+  public static final String CONF_NAME = "iotdb-confignode.properties";
+  public static final String SPECIAL_CONF_NAME = 
"iotdb-confignode-special.properties";
+
+  public static final String CONFIGNODE_PACKAGE = 
"org.apache.iotdb.confignode.service";
+  public static final String JMX_TYPE = "type";
+  public static final String CONFIGNODE_JMX_PORT = "confignode.jmx.port";
+
+  public static final String DATA_DIR = "data";
+  public static final String CONF_DIR = "conf";
+
+  public static final int MIN_SUPPORTED_JDK_VERSION = 8;
+
   private ConfigNodeConstant() {
     // empty constructor
   }
-
-  public static final String CONFIG_NODE_CONF = "CONFIG_NODE_CONF";
-
-  public static final String CONFIG_NODE_HOME = "CONFIG_NODE_HOME";
 }
diff --git 
a/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeDescriptor.java
 
b/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeDescriptor.java
index 0477f6d..a5e4a8a 100644
--- 
a/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeDescriptor.java
+++ 
b/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeDescriptor.java
@@ -42,44 +42,40 @@ public class ConfigNodeDescriptor {
     return conf;
   }
 
-  public static ConfigNodeDescriptor getInstance() {
-    return ConfigNodeDescriptorHolder.INSTANCE;
-  }
-
-  private static class ConfigNodeDescriptorHolder {
-
-    private static final ConfigNodeDescriptor INSTANCE = new 
ConfigNodeDescriptor();
-
-    private ConfigNodeDescriptorHolder() {
-      // empty constructor
+  public String getPropsDir() {
+    // Check if CONFIG_NODE_CONF is set
+    String propsDir = System.getProperty(ConfigNodeConstant.CONFIGNODE_CONF, 
null);
+    if (propsDir == null) {
+      // Check if CONFIG_NODE_HOME is set
+      propsDir = System.getProperty(ConfigNodeConstant.CONFIGNODE_HOME, null);
+      if (propsDir == null) {
+        // When start ConfigNode with script, CONFIG_NODE_CONF and 
CONFIG_NODE_HOME must be set.
+        // Therefore, this case is TestOnly
+        // TODO: Specify a test dir
+      }
+      propsDir = propsDir + File.separator + ConfigNodeConstant.CONF_DIR;
     }
+
+    return propsDir;
   }
 
   public URL getPropsUrl() {
-    // The same logic as IoTDBDescriptor
-    String url = System.getProperty(ConfigNodeConstant.CONFIG_NODE_CONF, null);
+    String url = getPropsDir();
+
     if (url == null) {
-      url = System.getProperty(ConfigNodeConstant.CONFIG_NODE_HOME, null);
-      if (url != null) {
-        url = url + File.separatorChar + "conf" + File.separatorChar + 
ConfigNodeConf.CONF_NAME;
-      } else {
-        URL uri = ConfigNodeConf.class.getResource("/" + 
ConfigNodeConf.CONF_NAME);
-        if (uri != null) {
-          return uri;
-        }
-        LOGGER.warn(
-            "Cannot find IOTDB_HOME or IOTDB_CONF environment variable when 
loading config file {}, use default configuration",
-            ConfigNodeConf.CONF_NAME);
-        return null;
-      }
-    } else if (!url.endsWith(".properties")) {
-      url += File.separator + ConfigNodeConf.CONF_NAME;
+      return null;
     }
 
+    // Add props prefix
     if (!url.startsWith("file:") && !url.startsWith("classpath:")) {
       url = "file:" + url;
     }
 
+    // Add props suffix
+    if (!url.endsWith(".properties")) {
+      url += File.separator + ConfigNodeConstant.CONF_NAME;
+    }
+
     try {
       return new URL(url);
     } catch (MalformedURLException e) {
@@ -90,7 +86,8 @@ public class ConfigNodeDescriptor {
   private void loadProps() {
     URL url = getPropsUrl();
     if (url == null) {
-      LOGGER.warn("Couldn't load the ConfigNode configuration from any of the 
known sources.");
+      LOGGER.warn(
+          "Couldn't load the ConfigNode configuration from any of the known 
sources. Use default configuration.");
       return;
     }
 
@@ -114,4 +111,17 @@ public class ConfigNodeDescriptor {
       LOGGER.warn("Couldn't load ConfigNode conf file, use default config", e);
     }
   }
+
+  public static ConfigNodeDescriptor getInstance() {
+    return ConfigNodeDescriptorHolder.INSTANCE;
+  }
+
+  private static class ConfigNodeDescriptorHolder {
+
+    private static final ConfigNodeDescriptor INSTANCE = new 
ConfigNodeDescriptor();
+
+    private ConfigNodeDescriptorHolder() {
+      // empty constructor
+    }
+  }
 }
diff --git 
a/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConstant.java
 
b/confignode/src/main/java/org/apache/iotdb/confignode/exception/ConfigNodeException.java
similarity index 75%
copy from 
confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConstant.java
copy to 
confignode/src/main/java/org/apache/iotdb/confignode/exception/ConfigNodeException.java
index 0680a8e..0c3ea33 100644
--- 
a/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConstant.java
+++ 
b/confignode/src/main/java/org/apache/iotdb/confignode/exception/ConfigNodeException.java
@@ -16,15 +16,11 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.iotdb.confignode.conf;
+package org.apache.iotdb.confignode.exception;
 
-public class ConfigNodeConstant {
+public abstract class ConfigNodeException extends Exception {
 
-  private ConfigNodeConstant() {
-    // empty constructor
+  public ConfigNodeException(String message) {
+    super(message);
   }
-
-  public static final String CONFIG_NODE_CONF = "CONFIG_NODE_CONF";
-
-  public static final String CONFIG_NODE_HOME = "CONFIG_NODE_HOME";
 }
diff --git 
a/confignode/src/main/java/org/apache/iotdb/confignode/manager/hash/JSHashExecutor.java
 
b/confignode/src/main/java/org/apache/iotdb/confignode/exception/conf/RepeatConfigurationException.java
similarity index 60%
copy from 
confignode/src/main/java/org/apache/iotdb/confignode/manager/hash/JSHashExecutor.java
copy to 
confignode/src/main/java/org/apache/iotdb/confignode/exception/conf/RepeatConfigurationException.java
index 855111f..515f098 100644
--- 
a/confignode/src/main/java/org/apache/iotdb/confignode/manager/hash/JSHashExecutor.java
+++ 
b/confignode/src/main/java/org/apache/iotdb/confignode/exception/conf/RepeatConfigurationException.java
@@ -16,25 +16,17 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.iotdb.confignode.manager.hash;
+package org.apache.iotdb.confignode.exception.conf;
 
-public class JSHashExecutor extends DeviceGroupHashExecutor {
+import org.apache.iotdb.confignode.exception.ConfigNodeException;
 
-  private static final int base = 1315423911;
+/** Throws when there exists some special parameters are repeatedly defined */
+public class RepeatConfigurationException extends ConfigNodeException {
 
-  public JSHashExecutor(int deviceGroupCount) {
-    super(deviceGroupCount);
-  }
-
-  @Override
-  public int getDeviceGroupID(String device) {
-    int hash = base;
-
-    for (int i = 0; i < device.length(); i++) {
-      hash ^= ((hash << 5) + (int) device.charAt(i) + (hash >> 2));
-    }
-    hash &= Integer.MAX_VALUE;
-
-    return hash % deviceGroupCount;
+  public RepeatConfigurationException(String parameter, String badValue, 
String correctValue) {
+    super(
+        String.format(
+            "Parameter %s can not be %s, because you're already set to: %s.",
+            parameter, badValue, correctValue));
   }
 }
diff --git 
a/confignode/src/main/java/org/apache/iotdb/confignode/manager/hash/DeviceGroupHashExecutor.java
 
b/confignode/src/main/java/org/apache/iotdb/confignode/exception/startup/StartupException.java
similarity index 64%
copy from 
confignode/src/main/java/org/apache/iotdb/confignode/manager/hash/DeviceGroupHashExecutor.java
copy to 
confignode/src/main/java/org/apache/iotdb/confignode/exception/startup/StartupException.java
index bd62834..242c8c5 100644
--- 
a/confignode/src/main/java/org/apache/iotdb/confignode/manager/hash/DeviceGroupHashExecutor.java
+++ 
b/confignode/src/main/java/org/apache/iotdb/confignode/exception/startup/StartupException.java
@@ -16,16 +16,18 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.iotdb.confignode.manager.hash;
+package org.apache.iotdb.confignode.exception.startup;
 
-/** All DeviceGroup hash algorithm executors must be subclasses of 
DeviceGroupHashExecutor */
-public abstract class DeviceGroupHashExecutor {
+import org.apache.iotdb.confignode.exception.ConfigNodeException;
 
-  protected final int deviceGroupCount;
+/** Throws when there exists errors when startup checks */
+public class StartupException extends ConfigNodeException {
 
-  public DeviceGroupHashExecutor(int deviceGroupCount) {
-    this.deviceGroupCount = deviceGroupCount;
+  public StartupException(String name, String message) {
+    super(String.format("Failed to start [%s], because [%s]", name, message));
   }
 
-  public abstract int getDeviceGroupID(String device);
+  public StartupException(String message) {
+    super(message);
+  }
 }
diff --git 
a/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
 
b/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
index 25cd4fd..260535e 100644
--- 
a/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
+++ 
b/confignode/src/main/java/org/apache/iotdb/confignode/manager/ConfigManager.java
@@ -18,9 +18,9 @@
  */
 package org.apache.iotdb.confignode.manager;
 
+import org.apache.iotdb.commons.hash.DeviceGroupHashExecutor;
 import org.apache.iotdb.confignode.conf.ConfigNodeConf;
 import org.apache.iotdb.confignode.conf.ConfigNodeDescriptor;
-import org.apache.iotdb.confignode.manager.hash.DeviceGroupHashExecutor;
 import org.apache.iotdb.confignode.partition.PartitionTable;
 import org.apache.iotdb.confignode.service.balancer.LoadBalancer;
 
diff --git 
a/confignode/src/main/java/org/apache/iotdb/confignode/service/ConfigNode.java 
b/confignode/src/main/java/org/apache/iotdb/confignode/service/ConfigNode.java
new file mode 100644
index 0000000..f081c56
--- /dev/null
+++ 
b/confignode/src/main/java/org/apache/iotdb/confignode/service/ConfigNode.java
@@ -0,0 +1,125 @@
+/*
+ * 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.service;
+
+import org.apache.iotdb.confignode.conf.ConfigNodeConfCheck;
+import org.apache.iotdb.confignode.conf.ConfigNodeConstant;
+import org.apache.iotdb.confignode.exception.ConfigNodeException;
+import org.apache.iotdb.confignode.exception.startup.StartupException;
+import org.apache.iotdb.confignode.service.register.JMXService;
+import org.apache.iotdb.confignode.service.register.RegisterManager;
+import org.apache.iotdb.confignode.service.startup.StartupChecks;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.IOException;
+
+public class ConfigNode implements ConfigNodeMBean {
+
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(ConfigNode.class);
+
+  private final String mbeanName =
+      String.format(
+          "%s:%s=%s",
+          ConfigNodeConstant.CONFIGNODE_PACKAGE, ConfigNodeConstant.JMX_TYPE, 
"ConfigNode");
+
+  private static final RegisterManager registerManager = new RegisterManager();
+
+  public ConfigNode() {
+    // empty constructor
+  }
+
+  public static void main(String[] args) {
+    try {
+      // Check parameters
+      ConfigNodeConfCheck.getInstance().checkConfig();
+    } catch (ConfigNodeException | IOException e) {
+      LOGGER.error("Meet error when doing start checking", e);
+      System.exit(1);
+    }
+
+    ConfigNode daemon = ConfigNode.getInstance();
+    daemon.active();
+  }
+
+  public void active() {
+    StartupChecks checks = new StartupChecks().withDefaultTest();
+    try {
+      // Startup environment check
+      checks.verify();
+    } catch (StartupException e) {
+      LOGGER.error(
+          "{}: failed to start because some checks failed. ", 
ConfigNodeConstant.GLOBAL_NAME, e);
+      return;
+    }
+
+    try {
+      setUp();
+    } catch (StartupException e) {
+      LOGGER.error("meet error while starting up.", e);
+      deactivate();
+      LOGGER.error("{} exit", ConfigNodeConstant.GLOBAL_NAME);
+      return;
+    }
+
+    LOGGER.info("{} has started.", ConfigNodeConstant.GLOBAL_NAME);
+  }
+
+  /** Register services */
+  private void setUp() throws StartupException {
+    LOGGER.info("Setting up {}...", ConfigNodeConstant.GLOBAL_NAME);
+    registerManager.register(JMXService.getInstance());
+    JMXService.registerMBean(getInstance(), mbeanName);
+    LOGGER.info(
+        "Congratulation, {} is set up successfully. Now, enjoy yourself!",
+        ConfigNodeConstant.GLOBAL_NAME);
+  }
+
+  public void deactivate() {
+    LOGGER.info("Deactivating {}...", ConfigNodeConstant.GLOBAL_NAME);
+    registerManager.deregisterAll();
+    JMXService.deregisterMBean(mbeanName);
+    LOGGER.info("{} is deactivated.", ConfigNodeConstant.GLOBAL_NAME);
+  }
+
+  public void shutdown() {
+    LOGGER.info("Deactivating {}...", ConfigNodeConstant.GLOBAL_NAME);
+    registerManager.shutdownAll();
+    JMXService.deregisterMBean(mbeanName);
+    LOGGER.info("{} is deactivated.", ConfigNodeConstant.GLOBAL_NAME);
+  }
+
+  public void stop() {
+    deactivate();
+  }
+
+  private static class ConfigNodeHolder {
+
+    private static final ConfigNode INSTANCE = new ConfigNode();
+
+    private ConfigNodeHolder() {
+      // empty constructor
+    }
+  }
+
+  public static ConfigNode getInstance() {
+    return ConfigNodeHolder.INSTANCE;
+  }
+}
diff --git 
a/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConstant.java
 
b/confignode/src/main/java/org/apache/iotdb/confignode/service/ConfigNodeMBean.java
similarity index 74%
copy from 
confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConstant.java
copy to 
confignode/src/main/java/org/apache/iotdb/confignode/service/ConfigNodeMBean.java
index 0680a8e..924b71a 100644
--- 
a/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConstant.java
+++ 
b/confignode/src/main/java/org/apache/iotdb/confignode/service/ConfigNodeMBean.java
@@ -16,15 +16,10 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.iotdb.confignode.conf;
+package org.apache.iotdb.confignode.service;
 
-public class ConfigNodeConstant {
+@FunctionalInterface
+public interface ConfigNodeMBean {
 
-  private ConfigNodeConstant() {
-    // empty constructor
-  }
-
-  public static final String CONFIG_NODE_CONF = "CONFIG_NODE_CONF";
-
-  public static final String CONFIG_NODE_HOME = "CONFIG_NODE_HOME";
+  void stop();
 }
diff --git 
a/confignode/src/main/java/org/apache/iotdb/confignode/manager/hash/BKDRHashExecutor.java
 
b/confignode/src/main/java/org/apache/iotdb/confignode/service/register/IService.java
similarity index 51%
copy from 
confignode/src/main/java/org/apache/iotdb/confignode/manager/hash/BKDRHashExecutor.java
copy to 
confignode/src/main/java/org/apache/iotdb/confignode/service/register/IService.java
index 2a3eed2..e2804d5 100644
--- 
a/confignode/src/main/java/org/apache/iotdb/confignode/manager/hash/BKDRHashExecutor.java
+++ 
b/confignode/src/main/java/org/apache/iotdb/confignode/service/register/IService.java
@@ -16,25 +16,36 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.iotdb.confignode.manager.hash;
+package org.apache.iotdb.confignode.service.register;
 
-public class BKDRHashExecutor extends DeviceGroupHashExecutor {
+import org.apache.iotdb.confignode.exception.startup.StartupException;
 
-  private static final int seed = 131;
+/** Any services that run in ConfigNode should implement IService */
+public interface IService {
 
-  public BKDRHashExecutor(int deviceGroupCount) {
-    super(deviceGroupCount);
-  }
+  // TODO: Code optimize, reuse logic in iotdb-server
+
+  /** Start current service. */
+  void start() throws StartupException;
 
-  @Override
-  public int getDeviceGroupID(String device) {
-    int hash = 0;
+  /**
+   * Stop current service. If current service uses thread or thread pool, 
current service should
+   * guarantee to putBack thread or thread pool.
+   */
+  void stop();
 
-    for (int i = 0; i < device.length(); i++) {
-      hash = hash * seed + (int) device.charAt(i);
-    }
-    hash &= Integer.MAX_VALUE;
+  default void waitAndStop(long milliseconds) {
+    stop();
+  }
 
-    return hash % deviceGroupCount;
+  default void shutdown(long milliseconds) {
+    waitAndStop(milliseconds);
   }
+
+  /**
+   * Get the name of the the service.
+   *
+   * @return current service name
+   */
+  ServiceType getID();
 }
diff --git 
a/confignode/src/main/java/org/apache/iotdb/confignode/service/register/JMXService.java
 
b/confignode/src/main/java/org/apache/iotdb/confignode/service/register/JMXService.java
new file mode 100644
index 0000000..aca2a33
--- /dev/null
+++ 
b/confignode/src/main/java/org/apache/iotdb/confignode/service/register/JMXService.java
@@ -0,0 +1,105 @@
+/*
+ * 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.service.register;
+
+import org.apache.iotdb.confignode.conf.ConfigNodeConstant;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import javax.management.InstanceAlreadyExistsException;
+import javax.management.InstanceNotFoundException;
+import javax.management.MBeanRegistrationException;
+import javax.management.MBeanServer;
+import javax.management.MalformedObjectNameException;
+import javax.management.NotCompliantMBeanException;
+import javax.management.ObjectName;
+
+import java.lang.management.ManagementFactory;
+
+public class JMXService implements IService {
+
+  // TODO: Code optimize, reuse logic in iotdb-server
+
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(JMXService.class);
+
+  /** function for registering MBean. */
+  public static void registerMBean(Object mbean, String name) {
+    try {
+      MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+      ObjectName objectName = new ObjectName(name);
+      if (!mbs.isRegistered(objectName)) {
+        mbs.registerMBean(mbean, objectName);
+      }
+    } catch (MalformedObjectNameException
+        | InstanceAlreadyExistsException
+        | MBeanRegistrationException
+        | NotCompliantMBeanException e) {
+      LOGGER.error("Failed to registerMBean {}", name, e);
+    }
+  }
+
+  /** function for deregistering MBean. */
+  public static void deregisterMBean(String name) {
+    try {
+      MBeanServer mbs = ManagementFactory.getPlatformMBeanServer();
+      ObjectName objectName = new ObjectName(name);
+      if (mbs.isRegistered(objectName)) {
+        mbs.unregisterMBean(objectName);
+      }
+    } catch (MalformedObjectNameException
+        | MBeanRegistrationException
+        | InstanceNotFoundException e) {
+      LOGGER.error("Failed to unregisterMBean {}", name, e);
+    }
+  }
+
+  @Override
+  public ServiceType getID() {
+    return ServiceType.JMX_SERVICE;
+  }
+
+  @Override
+  public void start() {
+    String jmxPort = 
System.getProperty(ConfigNodeConstant.CONFIGNODE_JMX_PORT);
+    if (jmxPort == null) {
+      LOGGER.debug("{} JMX port is undefined", this.getID().getName());
+    }
+  }
+
+  @Override
+  public void stop() {
+    // do nothing.
+  }
+
+  private JMXService() {
+    // empty constructor
+  }
+
+  public static JMXService getInstance() {
+    return JMXServerHolder.INSTANCE;
+  }
+
+  private static class JMXServerHolder {
+
+    private static final JMXService INSTANCE = new JMXService();
+
+    private JMXServerHolder() {}
+  }
+}
diff --git 
a/confignode/src/main/java/org/apache/iotdb/confignode/service/register/RegisterManager.java
 
b/confignode/src/main/java/org/apache/iotdb/confignode/service/register/RegisterManager.java
new file mode 100644
index 0000000..1b2c736
--- /dev/null
+++ 
b/confignode/src/main/java/org/apache/iotdb/confignode/service/register/RegisterManager.java
@@ -0,0 +1,82 @@
+/*
+ * 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.service.register;
+
+import org.apache.iotdb.confignode.exception.startup.StartupException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.List;
+
+/** Manager any services that run in ConfigNode */
+public class RegisterManager {
+
+  // TODO: Code optimize, reuse logic in iotdb-server
+
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(RegisterManager.class);
+
+  private final List<IService> iServices;
+  private static final long deregisterTimeOut = 10_000L;
+
+  public RegisterManager() {
+    iServices = new ArrayList<>();
+  }
+
+  /** register service. */
+  public void register(IService service) throws StartupException {
+    for (IService s : iServices) {
+      if (s.getID() == service.getID()) {
+        LOGGER.debug("{} has already been registered. skip", 
service.getID().getName());
+        return;
+      }
+    }
+    iServices.add(service);
+    service.start();
+  }
+
+  /** stop all service and clear iService list. */
+  public void deregisterAll() {
+    // we stop JMXServer at last
+    Collections.reverse(iServices);
+    for (IService service : iServices) {
+      try {
+        service.waitAndStop(deregisterTimeOut);
+        LOGGER.debug("{} deregistered", service.getID());
+      } catch (Exception e) {
+        LOGGER.error("Failed to stop {} because:", service.getID().getName(), 
e);
+      }
+    }
+    iServices.clear();
+    LOGGER.info("deregister all service.");
+  }
+
+  /** stop all service and clear iService list. */
+  public void shutdownAll() {
+    // we stop JMXServer at last
+    Collections.reverse(iServices);
+    for (IService service : iServices) {
+      service.shutdown(deregisterTimeOut);
+    }
+    iServices.clear();
+    LOGGER.info("deregister all service.");
+  }
+}
diff --git 
a/confignode/src/main/java/org/apache/iotdb/confignode/manager/hash/BKDRHashExecutor.java
 
b/confignode/src/main/java/org/apache/iotdb/confignode/service/register/ServiceType.java
similarity index 57%
copy from 
confignode/src/main/java/org/apache/iotdb/confignode/manager/hash/BKDRHashExecutor.java
copy to 
confignode/src/main/java/org/apache/iotdb/confignode/service/register/ServiceType.java
index 2a3eed2..114ab1c 100644
--- 
a/confignode/src/main/java/org/apache/iotdb/confignode/manager/hash/BKDRHashExecutor.java
+++ 
b/confignode/src/main/java/org/apache/iotdb/confignode/service/register/ServiceType.java
@@ -16,25 +16,29 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.iotdb.confignode.manager.hash;
+package org.apache.iotdb.confignode.service.register;
 
-public class BKDRHashExecutor extends DeviceGroupHashExecutor {
+public enum ServiceType {
+  JMX_SERVICE("JMX ServerService", "JMX ServerService"),
+  CLUSTER_RPC_SERVER("Cluster RPC Server", "ClusterRPCServer");
 
-  private static final int seed = 131;
+  private final String name;
+  private final String jmxName;
 
-  public BKDRHashExecutor(int deviceGroupCount) {
-    super(deviceGroupCount);
+  ServiceType(String name, String jmxName) {
+    this.name = name;
+    this.jmxName = jmxName;
   }
 
-  @Override
-  public int getDeviceGroupID(String device) {
-    int hash = 0;
+  public String getName() {
+    return name;
+  }
 
-    for (int i = 0; i < device.length(); i++) {
-      hash = hash * seed + (int) device.charAt(i);
-    }
-    hash &= Integer.MAX_VALUE;
+  public String getJmxName() {
+    return jmxName;
+  }
 
-    return hash % deviceGroupCount;
+  private static String generateJmxName(String packageName, String jmxName) {
+    return String.format("%s:type=%s", packageName, jmxName);
   }
 }
diff --git 
a/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConstant.java
 
b/confignode/src/main/java/org/apache/iotdb/confignode/service/startup/StartupCheck.java
similarity index 73%
copy from 
confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConstant.java
copy to 
confignode/src/main/java/org/apache/iotdb/confignode/service/startup/StartupCheck.java
index 0680a8e..d3128a7 100644
--- 
a/confignode/src/main/java/org/apache/iotdb/confignode/conf/ConfigNodeConstant.java
+++ 
b/confignode/src/main/java/org/apache/iotdb/confignode/service/startup/StartupCheck.java
@@ -16,15 +16,13 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.iotdb.confignode.conf;
+package org.apache.iotdb.confignode.service.startup;
 
-public class ConfigNodeConstant {
+import org.apache.iotdb.confignode.exception.startup.StartupException;
 
-  private ConfigNodeConstant() {
-    // empty constructor
-  }
+@FunctionalInterface
+public interface StartupCheck {
 
-  public static final String CONFIG_NODE_CONF = "CONFIG_NODE_CONF";
-
-  public static final String CONFIG_NODE_HOME = "CONFIG_NODE_HOME";
+  /** Run some tests to check whether ConfigNode is safe to be started. */
+  void execute() throws StartupException;
 }
diff --git 
a/confignode/src/main/java/org/apache/iotdb/confignode/service/startup/StartupChecks.java
 
b/confignode/src/main/java/org/apache/iotdb/confignode/service/startup/StartupChecks.java
new file mode 100644
index 0000000..58d9b67
--- /dev/null
+++ 
b/confignode/src/main/java/org/apache/iotdb/confignode/service/startup/StartupChecks.java
@@ -0,0 +1,89 @@
+/*
+ * 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.service.startup;
+
+import org.apache.iotdb.confignode.conf.ConfigNodeConstant;
+import org.apache.iotdb.confignode.exception.startup.StartupException;
+
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/** StartupChecks checks the startup environment for running ConfigNode */
+public class StartupChecks {
+
+  // TODO: Code optimize, reuse logic in iotdb-server
+
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(StartupChecks.class);
+  public static final StartupCheck checkJMXPort =
+      () -> {
+        String jmxPort = 
System.getProperty(ConfigNodeConstant.CONFIGNODE_JMX_PORT);
+        if (jmxPort == null) {
+          LOGGER.warn(
+              "{} missing from {}.sh(Unix or OS X, if you use Windows," + " 
check conf/{}.bat)",
+              ConfigNodeConstant.CONFIGNODE_JMX_PORT,
+              ConfigNodeConstant.ENV_FILE_NAME,
+              ConfigNodeConstant.ENV_FILE_NAME);
+        } else {
+          LOGGER.info("JMX is enabled to receive remote connection on port 
{}", jmxPort);
+        }
+      };
+  public static final StartupCheck checkJDK =
+      () -> {
+        int version = getJdkVersion();
+        if (version < ConfigNodeConstant.MIN_SUPPORTED_JDK_VERSION) {
+          throw new StartupException(
+              String.format(
+                  "Requires JDK version >= %d, current version is %d",
+                  ConfigNodeConstant.MIN_SUPPORTED_JDK_VERSION, version));
+        } else {
+          LOGGER.info("JDK version is {}.", version);
+        }
+      };
+  private final List<StartupCheck> preChecks = new ArrayList<>();
+  private final List<StartupCheck> defaultChecks = new ArrayList<>();
+
+  public StartupChecks() {
+    defaultChecks.add(checkJMXPort);
+    defaultChecks.add(checkJDK);
+  }
+
+  public StartupChecks withDefaultTest() {
+    preChecks.addAll(defaultChecks);
+    return this;
+  }
+
+  /** execute every pretests. */
+  public void verify() throws StartupException {
+    for (StartupCheck check : preChecks) {
+      check.execute();
+    }
+  }
+
+  private static int getJdkVersion() {
+    String[] javaVersionElements = 
System.getProperty("java.version").split("\\.");
+    if (Integer.parseInt(javaVersionElements[0]) == 1) {
+      return Integer.parseInt(javaVersionElements[1]);
+    } else {
+      return Integer.parseInt(javaVersionElements[0]);
+    }
+  }
+}
diff --git 
a/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/impl/ConfigNodeRPCServer.java
 
b/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/server/ConfigNodeRPCServer.java
similarity index 97%
rename from 
confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/impl/ConfigNodeRPCServer.java
rename to 
confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/server/ConfigNodeRPCServer.java
index bc4d0e7..f922320 100644
--- 
a/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/impl/ConfigNodeRPCServer.java
+++ 
b/confignode/src/main/java/org/apache/iotdb/confignode/service/thrift/server/ConfigNodeRPCServer.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.iotdb.confignode.service.thrift.impl;
+package org.apache.iotdb.confignode.service.thrift.server;
 
 import org.apache.iotdb.confignode.manager.ConfigManager;
 import org.apache.iotdb.confignode.rpc.thrift.ConfigIService;
diff --git 
a/confignode/src/test/java/org/apache/iotdb/confignode/conf/ConfigNodeDescriptorTest.java
 
b/confignode/src/test/java/org/apache/iotdb/confignode/conf/ConfigNodeDescriptorTest.java
deleted file mode 100644
index 3bc580b..0000000
--- 
a/confignode/src/test/java/org/apache/iotdb/confignode/conf/ConfigNodeDescriptorTest.java
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- * 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.conf;
-
-import org.junit.After;
-import org.junit.Assert;
-import org.junit.Before;
-import org.junit.Test;
-
-import java.net.URL;
-
-public class ConfigNodeDescriptorTest {
-
-  private final String confPath = System.getProperty(ConfigNodeConf.CONF_NAME, 
null);
-
-  @Before
-  public void init() {
-    
org.apache.catalina.webresources.TomcatURLStreamHandlerFactory.getInstance();
-  }
-
-  @After
-  public void clear() {
-    if (confPath != null) {
-      System.setProperty(ConfigNodeConstant.CONFIG_NODE_CONF, confPath);
-    } else {
-      System.clearProperty(ConfigNodeConstant.CONFIG_NODE_CONF);
-    }
-  }
-
-  @Test
-  public void testConfigURLWithFileProtocol() {
-    ConfigNodeDescriptor desc = ConfigNodeDescriptor.getInstance();
-    String pathString = "file:/usr/local/bin";
-
-    System.setProperty(ConfigNodeConstant.CONFIG_NODE_CONF, pathString);
-    URL confURL = desc.getPropsUrl();
-    Assert.assertTrue(confURL.toString().startsWith(pathString));
-  }
-
-  @Test
-  public void testConfigURLWithClasspathProtocol() {
-    ConfigNodeDescriptor desc = ConfigNodeDescriptor.getInstance();
-
-    String pathString = "classpath:/root/path";
-    System.setProperty(ConfigNodeConstant.CONFIG_NODE_CONF, pathString);
-    URL confURL = desc.getPropsUrl();
-    Assert.assertTrue(confURL.toString().startsWith(pathString));
-  }
-
-  @Test
-  public void testConfigURLWithPlainFilePath() {
-    ConfigNodeDescriptor desc = ConfigNodeDescriptor.getInstance();
-    URL path = ConfigNodeConf.class.getResource("/" + 
ConfigNodeConf.CONF_NAME);
-    // filePath is a plain path string
-    String filePath = path.getFile();
-    System.setProperty(ConfigNodeConstant.CONFIG_NODE_CONF, filePath);
-    URL confURL = desc.getPropsUrl();
-    Assert.assertEquals(confURL.toString(), path.toString());
-  }
-}
diff --git 
a/confignode/src/test/java/org/apache/iotdb/confignode/manager/hash/DeviceGroupHashExecutorTest.java
 
b/confignode/src/test/java/org/apache/iotdb/confignode/manager/hash/DeviceGroupHashExecutorTest.java
index 7f95cca..6039043 100644
--- 
a/confignode/src/test/java/org/apache/iotdb/confignode/manager/hash/DeviceGroupHashExecutorTest.java
+++ 
b/confignode/src/test/java/org/apache/iotdb/confignode/manager/hash/DeviceGroupHashExecutorTest.java
@@ -60,8 +60,7 @@ public class DeviceGroupHashExecutorTest {
 
   public void GeneralIndexTest() {
     ConfigManager manager =
-        new ConfigManager(
-            "org.apache.iotdb.confignode.manager.hash.BKDRHashExecutor", 
deviceGroupCount);
+        new ConfigManager("org.apache.iotdb.commons.hash.BKDRHashExecutor", 
deviceGroupCount);
     int[] bucket = new int[deviceGroupCount];
     Arrays.fill(bucket, 0);
 
diff --git 
a/confignode/src/test/java/org/apache/iotdb/confignode/utils/ConfigNodeEnvironmentUtils.java
 
b/confignode/src/test/java/org/apache/iotdb/confignode/utils/ConfigNodeEnvironmentUtils.java
new file mode 100644
index 0000000..a14a31d
--- /dev/null
+++ 
b/confignode/src/test/java/org/apache/iotdb/confignode/utils/ConfigNodeEnvironmentUtils.java
@@ -0,0 +1,133 @@
+/*
+ * 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.utils;
+
+import org.apache.iotdb.confignode.conf.ConfigNodeConstant;
+import org.apache.iotdb.confignode.service.ConfigNode;
+
+import org.apache.commons.io.FileUtils;
+import org.jetbrains.annotations.TestOnly;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.io.File;
+import java.io.IOException;
+
+import static org.junit.Assert.fail;
+
+/** Test environment for ConfigNode UT and IT */
+public class ConfigNodeEnvironmentUtils {
+
+  private static final Logger LOGGER = 
LoggerFactory.getLogger(ConfigNodeEnvironmentUtils.class);
+
+  private static ConfigNode daemon;
+
+  @TestOnly
+  public static void envSetUp() {
+    LOGGER.debug("ConfigNodeEnvironmentUtils setup...");
+
+    if (daemon == null) {
+      daemon = new ConfigNode();
+    }
+
+    try {
+      daemon.active();
+    } catch (Exception e) {
+      fail(e.getMessage());
+    }
+
+    createAllDir();
+  }
+
+  @TestOnly
+  public static void cleanEnv() {
+    LOGGER.debug("ConfigNodeEnvironmentUtils cleanEnv...");
+
+    if (daemon != null) {
+      daemon.stop();
+      daemon = null;
+    }
+
+    // delete all directory
+    cleanAllDir();
+  }
+
+  @TestOnly
+  public static void stopDaemon() {
+    if (daemon != null) {
+      daemon.stop();
+    }
+  }
+
+  @TestOnly
+  public static void shutdownDaemon() {
+    if (daemon != null) {
+      daemon.shutdown();
+    }
+  }
+
+  @TestOnly
+  public static void activeDaemon() {
+    if (daemon != null) {
+      daemon.active();
+    }
+  }
+
+  @TestOnly
+  public static void reactiveDaemon() {
+    if (daemon == null) {
+      daemon = new ConfigNode();
+      daemon.active();
+    } else {
+      activeDaemon();
+    }
+  }
+
+  @TestOnly
+  public static void restartDaemon() {
+    shutdownDaemon();
+    stopDaemon();
+    reactiveDaemon();
+  }
+
+  private static void createAllDir() {
+    createDir(ConfigNodeConstant.CONF_DIR);
+    createDir(ConfigNodeConstant.DATA_DIR);
+  }
+
+  private static void createDir(String dir) {
+    File file = new File(dir);
+    if (!file.mkdirs()) {
+      LOGGER.error("ConfigNodeEnvironmentUtils can't mkdir {}.", dir);
+    }
+  }
+
+  private static void cleanAllDir() {
+    cleanDir(ConfigNodeConstant.CONF_DIR);
+    cleanDir(ConfigNodeConstant.DATA_DIR);
+  }
+
+  public static void cleanDir(String dir) {
+    try {
+      FileUtils.deleteDirectory(new File(dir));
+    } catch (IOException e) {
+      LOGGER.error("ConfigNodeEnvironmentUtils can't remove dir {}.", dir, e);
+    }
+  }
+}
diff --git a/iotdb-commons/pom.xml b/iotdb-commons/pom.xml
new file mode 100644
index 0000000..588ebc0
--- /dev/null
+++ b/iotdb-commons/pom.xml
@@ -0,0 +1,32 @@
+<?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.
+
+-->
+<project xmlns="http://maven.apache.org/POM/4.0.0"; 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"; 
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 
http://maven.apache.org/xsd/maven-4.0.0.xsd";>
+    <modelVersion>4.0.0</modelVersion>
+    <parent>
+        <groupId>org.apache.iotdb</groupId>
+        <artifactId>iotdb-parent</artifactId>
+        <version>0.14.0-SNAPSHOT</version>
+        <relativePath>../pom.xml</relativePath>
+    </parent>
+    <artifactId>iotdb-commons</artifactId>
+    <name>IoTDB commons</name>
+</project>
diff --git 
a/confignode/src/main/java/org/apache/iotdb/confignode/manager/hash/APHashExecutor.java
 b/iotdb-commons/src/main/java/org/apache/iotdb/commons/hash/APHashExecutor.java
similarity index 96%
rename from 
confignode/src/main/java/org/apache/iotdb/confignode/manager/hash/APHashExecutor.java
rename to 
iotdb-commons/src/main/java/org/apache/iotdb/commons/hash/APHashExecutor.java
index 0989fbb..0fc18ad 100644
--- 
a/confignode/src/main/java/org/apache/iotdb/confignode/manager/hash/APHashExecutor.java
+++ 
b/iotdb-commons/src/main/java/org/apache/iotdb/commons/hash/APHashExecutor.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.iotdb.confignode.manager.hash;
+package org.apache.iotdb.commons.hash;
 
 public class APHashExecutor extends DeviceGroupHashExecutor {
 
diff --git 
a/confignode/src/main/java/org/apache/iotdb/confignode/manager/hash/BKDRHashExecutor.java
 
b/iotdb-commons/src/main/java/org/apache/iotdb/commons/hash/BKDRHashExecutor.java
similarity index 96%
rename from 
confignode/src/main/java/org/apache/iotdb/confignode/manager/hash/BKDRHashExecutor.java
rename to 
iotdb-commons/src/main/java/org/apache/iotdb/commons/hash/BKDRHashExecutor.java
index 2a3eed2..b5e08a0 100644
--- 
a/confignode/src/main/java/org/apache/iotdb/confignode/manager/hash/BKDRHashExecutor.java
+++ 
b/iotdb-commons/src/main/java/org/apache/iotdb/commons/hash/BKDRHashExecutor.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.iotdb.confignode.manager.hash;
+package org.apache.iotdb.commons.hash;
 
 public class BKDRHashExecutor extends DeviceGroupHashExecutor {
 
diff --git 
a/confignode/src/main/java/org/apache/iotdb/confignode/manager/hash/DeviceGroupHashExecutor.java
 
b/iotdb-commons/src/main/java/org/apache/iotdb/commons/hash/DeviceGroupHashExecutor.java
similarity index 95%
rename from 
confignode/src/main/java/org/apache/iotdb/confignode/manager/hash/DeviceGroupHashExecutor.java
rename to 
iotdb-commons/src/main/java/org/apache/iotdb/commons/hash/DeviceGroupHashExecutor.java
index bd62834..a597c93 100644
--- 
a/confignode/src/main/java/org/apache/iotdb/confignode/manager/hash/DeviceGroupHashExecutor.java
+++ 
b/iotdb-commons/src/main/java/org/apache/iotdb/commons/hash/DeviceGroupHashExecutor.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.iotdb.confignode.manager.hash;
+package org.apache.iotdb.commons.hash;
 
 /** All DeviceGroup hash algorithm executors must be subclasses of 
DeviceGroupHashExecutor */
 public abstract class DeviceGroupHashExecutor {
diff --git 
a/confignode/src/main/java/org/apache/iotdb/confignode/manager/hash/JSHashExecutor.java
 b/iotdb-commons/src/main/java/org/apache/iotdb/commons/hash/JSHashExecutor.java
similarity index 96%
rename from 
confignode/src/main/java/org/apache/iotdb/confignode/manager/hash/JSHashExecutor.java
rename to 
iotdb-commons/src/main/java/org/apache/iotdb/commons/hash/JSHashExecutor.java
index 855111f..6521d28 100644
--- 
a/confignode/src/main/java/org/apache/iotdb/confignode/manager/hash/JSHashExecutor.java
+++ 
b/iotdb-commons/src/main/java/org/apache/iotdb/commons/hash/JSHashExecutor.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.iotdb.confignode.manager.hash;
+package org.apache.iotdb.commons.hash;
 
 public class JSHashExecutor extends DeviceGroupHashExecutor {
 
diff --git 
a/confignode/src/main/java/org/apache/iotdb/confignode/manager/hash/SDBMHashExecutor.java
 
b/iotdb-commons/src/main/java/org/apache/iotdb/commons/hash/SDBMHashExecutor.java
similarity index 96%
rename from 
confignode/src/main/java/org/apache/iotdb/confignode/manager/hash/SDBMHashExecutor.java
rename to 
iotdb-commons/src/main/java/org/apache/iotdb/commons/hash/SDBMHashExecutor.java
index 4c2ab6c..8780ac4 100644
--- 
a/confignode/src/main/java/org/apache/iotdb/confignode/manager/hash/SDBMHashExecutor.java
+++ 
b/iotdb-commons/src/main/java/org/apache/iotdb/commons/hash/SDBMHashExecutor.java
@@ -16,7 +16,7 @@
  * specific language governing permissions and limitations
  * under the License.
  */
-package org.apache.iotdb.confignode.manager.hash;
+package org.apache.iotdb.commons.hash;
 
 public class SDBMHashExecutor extends DeviceGroupHashExecutor {
 
diff --git a/pom.xml b/pom.xml
index 643bfb7..75ae55f 100644
--- a/pom.xml
+++ b/pom.xml
@@ -102,6 +102,7 @@
         <module>flink-iotdb-connector</module>
         <module>distribution</module>
         <module>hive-connector</module>
+        <module>iotdb-commons</module>
         <module>confignode</module>
         <module>cluster</module>
         <module>cross-tests</module>
diff --git a/server/pom.xml b/server/pom.xml
index 6db8881..f729e8f 100644
--- a/server/pom.xml
+++ b/server/pom.xml
@@ -52,6 +52,11 @@
         </dependency>
         <dependency>
             <groupId>org.apache.iotdb</groupId>
+            <artifactId>iotdb-commons</artifactId>
+            <version>${project.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.iotdb</groupId>
             <artifactId>tsfile</artifactId>
             <version>${project.version}</version>
             <exclusions>

Reply via email to