diff --git a/.lgtm.yml b/.lgtm.yml
new file mode 100644
index 0000000000000000000000000000000000000000..fbcedead432f57b7f9ed2161a4a1e500446b489f
--- /dev/null
+++ b/.lgtm.yml
@@ -0,0 +1,402 @@
+##########################################################################################
+# Customize file classifications. #
+# Results from files under any classifier will be excluded from LGTM #
+# statistics. #
+##########################################################################################
+
+##########################################################################################
+# Use the `path_classifiers` block to define changes to the default classification of #
+# files. #
+##########################################################################################
+
+path_classifiers:
+ # docs:
+ # Identify the top-level file called `generate_javadoc.py` as documentation-related.
+ test:
+ # Override LGTM's default classification of test files by excluding all files.
+ - exclude: /
+ # Classify all files in the top-level directories tests/ and testsuites/ as test code.
+ - tests
+ # - testsuites
+ # Classify all files with suffix `.test` as test code.
+ # Note: use only forward slash / as a path separator.
+ # Use ** to indicate an arbitrary parent path.
+ # Use * to indicate any sequence of characters excluding /.
+ # Always enclose the expression in double quotes if it includes *.
+ # - "**/*.test"
+ # Refine the classifications above by excluding files in test/util/.
+ # - exclude: test/util
+ # The default behavior is to tag all files created during the
+ # build as `generated`. Results are hidden for generated code. You can tag
+ # further files as being generated by adding them to the `generated` section.
+ generated:
+ # Exclude all `*.c` files under the `ui/` directory from classification as
+ # generated code.
+ # - exclude: ui/**/*.c
+ # By default, all files not checked into the repository are considered to be
+ # 'generated'.
+ # The default behavior is to tag library code as `library`. Results are hidden
+ # for library code. You can tag further files as being library code by adding them
+ # to the `library` section.
+ library:
+ - exclude: deps/
+ # The default behavior is to tag template files as `template`. Results are hidden
+ # for template files. You can tag further files as being template files by adding
+ # them to the `template` section.
+ template:
+ #- exclude: path/to/template/code/**/*.c
+ # Define your own category, for example: 'some_custom_category'.
+ some_custom_category:
+ # Classify all files in the top-level directory tools/ (or the top-level file
+ # called tools).
+ # - tools
+
+#########################################################################################
+# Use the `queries` block to change the default display of query results. #
+#########################################################################################
+
+ # queries:
+ # Start by hiding the results of all queries.
+ # - exclude: "*"
+ # Then include all queries tagged 'security' and 'correctness', and with a severity of
+ # 'error'.
+ # - include:
+ # tags:
+ # - "security"
+ # - "correctness"
+ # severity: "error"
+ # Specifically hide the results of two queries.
+ # - exclude: cpp/use-of-goto
+ # - exclude: java/equals-on-unrelated-types
+ # Refine by including the `java/command-line-injection` query.
+ # - include: java/command-line-injection
+
+#########################################################################################
+# Define changes to the default code extraction process. #
+# Each block configures the extraction of a single language, and modifies actions in a #
+# named step. Every named step includes automatic default actions, #
+# except for the 'prepare' step. The steps are performed in the following sequence: #
+# prepare #
+# after_prepare #
+# configure (C/C++ only) #
+# python_setup (Python only) #
+# before_index #
+# index #
+##########################################################################################
+
+#########################################################################################
+# Environment variables available to the steps: #
+#########################################################################################
+
+# LGTM_SRC
+# The root of the source tree.
+# LGTM_WORKSPACE
+# An existing (initially empty) folder outside the source tree.
+# Used for temporary download and setup commands.
+
+#########################################################################################
+# Use the extraction block to define changes to the default code extraction process #
+# for one or more languages. The settings for each language are defined in a child #
+# block, with one or more steps. #
+#########################################################################################
+
+extraction:
+ # Define settings for C/C++ analysis
+ #####################################
+ cpp:
+ # The `prepare` step exists for customization on LGTM.com only.
+ prepare:
+ # # The `packages` section is valid for LGTM.com only. It names Ubuntu packages to
+ # # be installed.
+ packages:
+ - cmake
+ # Add an `after-prepare` step if you need to run commands after the prepare step.
+ # Each command should be listed on a separate line.
+ # This step is useful for C/C++ analysis where you want to prepare the environment
+ # for the `configure` step without changing the default behavior for that step.
+ # after_prepare:
+ #- export GNU_MAKE=make
+ #- export GIT=true
+ # The `configure` step generates build configuration files which the `index` step
+ # then uses to build the codebase.
+ configure:
+ command:
+ - mkdir build
+ - cd build
+ - cmake ..
+ # - ./prepare_deps
+ # Optional step. You should add a `before_index` step if you need to run commands
+ # before the `index` step.
+ # before_index:
+ # - export BOOST_DIR=$LGTM_SRC/boost
+ # - export GTEST_DIR=$LGTM_SRC/googletest
+ # - export HUNSPELL_DIR=$LGTM_SRC/hunspell
+ # - export CRYPTOPP_DIR=$LGTM_SRC/cryptopp
+ # The `index` step builds the code and extracts information during the build
+ # process.
+ index:
+ # Override the autobuild process by specifying a list of custom build commands
+ # to use instead.
+ build_command:
+ - cd build
+ - make
+ # - $GNU_MAKE -j2 -s
+ # Specify that all project or solution files should be used for extraction.
+ # Default: false.
+ # all_solutions: true
+ # Specify a list of one or more project or solution files for extraction.
+ # Default: LGTM chooses the file closest to the root of the repository (this may
+ # fail if there are multiple candidates).
+ # solution:
+ # - myProject.sln
+ # Specify MSBuild settings
+ # msbuild:
+ # Specify a list of additional arguments to MSBuild. Default: empty.
+ # arguments: /p:Platform=x64 /p:Configuration=Release
+ # Specify the MSBuild configuration to use, for example, debug or release.
+ # Default: read from the solution file or files.
+ # configuration:
+ # Specify the platform to target, for example: x86, x64, or Any CPU.
+ # Default: read from the solution file or files.
+ # platform:
+ # Specify the MSBuild target. Default: rebuild.
+ # target:
+ # Specify whether or not to perform a NuGet restore for extraction. Default: true.
+ # nuget_restore: false
+ # Specify a version of Microsoft Visual Studio to use for MSBuild or any custom
+ # build commands (build_command). For example:
+ # 10 for Visual Studio 2010
+ # 12 for Visual Studio 2012
+ # 14 for Visual Studio 2015
+ # 15 for Visual Studio 2017
+ # Default: read from project files.
+ # vstools_version: 10
+
+ # Define settings for C# analysis
+ ##################################
+ # csharp:
+ # The `prepare` step exists for customization on LGTM.com only.
+ # prepare:
+ # packages:
+ # - example_package
+ # Add an `after-prepare` step if you need to run commands after the `prepare` step.
+ # Each command should be listed on a separate line.
+ # after_prepare:
+ # - export PATH=$LGTM_WORKSPACE/tools:$PATH
+ # The `index` step builds the code and extracts information during the build
+ # process.
+ #index:
+ # Specify that all project or solution files should be used for extraction.
+ # Default: false.
+ # all_solutions: true
+ # Specify a list of one or more project or solution files for extraction.
+ # Default: LGTM chooses the file closest to the root of the repository (this may
+ # fail if there are multiple candidates).
+ # solution:
+ # - myProject.sln
+ # Override the autobuild process by specifying a list of custom build commands
+ # to use instead.
+ # build_command:
+ # - ./example-compile-all.sh
+ # By default, LGTM analyzes the code by building it. You can override this,
+ # and tell LGTM not to build the code. Beware that this can lead
+ # to less accurate results.
+ # buildless: true
+ # Specify .NET Core settings.
+ # dotnet:
+ # Specify additional arguments to `dotnet build`.
+ # Default: empty.
+ # arguments: "example_arg"
+ # Specify the version of .NET Core SDK to use.
+ # Default: The version installed on the build machine.
+ # version: 2.1
+ # Specify MSBuild settings.
+ # msbuild:
+ # Specify a list of additional arguments to MSBuild. Default: empty.
+ # arguments: /P:WarningLevel=2
+ # Specify the MSBuild configuration to use, for example, debug or release.
+ # Default: read from the solution file or files.
+ # configuration: release
+ # Specify the platform to target, for example: x86, x64, or Any CPU.
+ # Default: read from the solution file or files.
+ # platform: x86
+ # Specify the MSBuild target. Default: rebuild.
+ # target: notest
+ # Specify whether or not to perform a NuGet restore for extraction. Default: true.
+ # nuget_restore: false
+ # Specify a version of Microsoft Visual Studio to use for MSBuild or any custom
+ # build commands (build_command). For example:
+ # 10 for Visual Studio 2010
+ # 12 for Visual Studio 2012
+ # 14 for Visual Studio 2015
+ # 15 for Visual Studio 2017
+ # Default: read from project files
+ # vstools_version: 10
+ # Specify additional options for the extractor,
+ # for example --fast to perform a faster extraction that produces a smaller
+ # database.
+ # extractor: "--fast"
+
+ # Define settings for Go analysis
+ ##################################
+ # go:
+ # The `prepare` step exists for customization on LGTM.com only.
+ # prepare:
+ # packages:
+ # - example_package
+ # Add an `after-prepare` step if you need to run commands after the `prepare` step.
+ # Each command should be listed on a separate line.
+ # after_prepare:
+ # - export PATH=$LGTM_WORKSPACE/tools:$PATH
+ # The `index` step builds the code and extracts information during the build
+ # process.
+ # index:
+ # Override the autobuild process by specifying a list of custom build commands
+ # to use instead.
+ # build_command:
+ # - ./compile-all.sh
+
+ # Define settings for Java analysis
+ ####################################
+ # java:
+ # The `prepare` step exists for customization on LGTM.com only.
+ # prepare:
+ # packages:
+ # - example_package
+ # Add an `after-prepare` step if you need to run commands after the prepare step.
+ # Each command should be listed on a separate line.
+ # after_prepare:
+ # - export PATH=$LGTM_WORKSPACE/tools:$PATH
+ # The `index` step extracts information from the files in the codebase.
+ # index:
+ # Specify Gradle settings.
+ # gradle:
+ # Specify the required Gradle version.
+ # Default: determined automatically.
+ # version: 4.4
+ # Override the autobuild process by specifying a list of custom build commands
+ # to use instead.
+ # build_command: ./compile-all.sh
+ # Specify the Java version required to build the project.
+ # java_version: 11
+ # Specify whether to extract Java .properties files
+ # Default: false
+ # properties_files: true
+ # Specify Maven settings.
+ # maven:
+ # Specify the path (absolute or relative) of a Maven settings file to use.
+ # Default: Maven uses a settings file in the default location, if it exists.
+ # settings_file: /opt/share/settings.xml
+ # Specify the path of a Maven toolchains file.
+ # Default: Maven uses a toolchains file in the default location, if it exists.
+ # toolchains_file: /opt/share/toolchains.xml
+ # Specify the required Maven version.
+ # Default: the Maven version is determined automatically, where feasible.
+ # version: 3.5.2
+ # Specify how XML files should be extracted:
+ # all = extract all XML files.
+ # default = only extract XML files named `AndroidManifest.xml`, `pom.xml`, and `web.xml`.
+ # disabled = do not extract any XML files.
+ # xml_mode: all
+
+ # Define settings for JavaScript analysis
+ ##########################################
+ # javascript:
+ # The `prepare` step exists for customization on LGTM.com only.
+ # prepare:
+ # packages:
+ # - example_package
+ # Add an `after-prepare` step if you need to run commands after the prepare step.
+ # Each command should be listed on a separate line.
+ # after_prepare:
+ # - export PATH=$LGTM_WORKSPACE/tools:$PATH
+ # The `index` step extracts information from the files in the codebase.
+ # index:
+ # Specify a list of files and folders to extract.
+ # Default: The project root directory.
+ # include:
+ # - src/js
+ # Specify a list of files and folders to exclude from extraction.
+ # exclude:
+ # - thirdparty/lib
+ # You can add additional file types for LGTM to extract, by mapping file
+ # extensions (including the leading dot) to file types. The usual
+ # include/exclude patterns apply, so, for example, `.jsm` files under
+ # `thirdparty/lib` will not be extracted.
+ # filetypes:
+ # ".jsm": "js"
+ # ".tmpl": "html"
+ # Specify a list of glob patterns to include/exclude files from extraction; this
+ # is applied on top of the include/exclude paths from above; patterns are
+ # processed in the same way as for path classifiers above.
+ # Default: include all files with known extensions (such as .js, .ts and .html),
+ # but exclude files ending in `-min.js` or `.min.js` and folders named `node_modules`
+ # or `bower_components`
+ # filters:
+ # exclude any *.ts files anywhere.
+ # - exclude: "**/*.ts"
+ # but include *.ts files under src/js/typescript.
+ # - include: "src/js/typescript/**/*.ts"
+ # Specify how TypeScript files should be extracted:
+ # none = exclude all TypeScript files.
+ # basic = extract syntactic information from TypeScript files.
+ # full = extract syntactic and type information from TypeScript files.
+ # Default: full.
+ # typescript: basic
+ # By default, LGTM doesn't extract any XML files. You can override this by
+ # using the `xml_mode` property and setting it to `all`.
+ # xml_mode: all
+
+ # Define settings for Python analysis
+ ######################################
+ # python:
+ # # The `prepare` step exists for customization on LGTM.com only.
+ # # prepare:
+ # # # The `packages` section is valid for LGTM.com only. It names packages to
+ # # # be installed.
+ # # packages: libpng-dev
+ # # This step is useful for Python analysis where you want to prepare the
+ # # environment for the `python_setup` step without changing the default behavior
+ # # for that step.
+ # after_prepare:
+ # - export PATH=$LGTM_WORKSPACE/tools:$PATH
+ # # This sets up the Python interpreter and virtual environment, ready for the
+ # # `index` step to extract the codebase.
+ # python_setup:
+ # # Specify packages that should NOT be installed despite being mentioned in the
+ # # requirements.txt file.
+ # # Default: no package marked for exclusion.
+ # exclude_requirements:
+ # - pywin32
+ # # Specify a list of pip packages to install.
+ # # If any of these packages cannot be installed, the extraction will fail.
+ # requirements:
+ # - Pillow
+ # # Specify a list of requirements text files to use to set up the environment,
+ # # or false for none. Default: any requirements.txt, test-requirements.txt,
+ # # and similarly named files identified in the codebase are used.
+ # requirements_files:
+ # - required-packages.txt
+ # # Specify a setup.py file to use to set up the environment, or false for none.
+ # # Default: any setup.py files identified in the codebase are used in preference
+ # # to any requirements text files.
+ # setup_py: new-setup.py
+ # # Override the version of the Python interpreter used for setup and extraction
+ # # Default: Python 3.
+ # version: 2
+ # # Optional step. You should add a `before_index` step if you need to run commands
+ # # before the `index` step.
+ # before_index:
+ # - antlr4 -Dlanguage=Python3 Grammar.g4
+ # # The `index` step extracts information from the files in the codebase.
+ # index:
+ # # Specify a list of files and folders to exclude from extraction.
+ # # Default: Git submodules and Subversion externals.
+ # exclude:
+ # - legacy-implementation
+ # - thirdparty/libs
+ # filters:
+ # - exclude: "**/documentation/examples/snippets/*.py"
+ # - include: "**/documentation/examples/test_application/*"
+ # include:
+ # - example/to/include
diff --git a/README.md b/README.md
index 522fc0ebc1277684b77589c5c62d061f7b33ce32..36436dd549e22f58caefd82c4a9be4e8aed8d869 100644
--- a/README.md
+++ b/README.md
@@ -83,12 +83,18 @@ sudo dnf install -y maven
## Get the source codes
-- github:
+First of all, you may clone the source codes from github:
```bash
git clone https://github.com/taosdata/TDengine.git
cd TDengine
```
+The connectors for go & grafana have been moved to separated repositories,
+so you should run this command in the TDengine directory to install them:
+```bash
+git submodule update --init --recursive
+```
+
## Build TDengine
### On Linux platform
diff --git a/documentation20/webdocs/markdowndocs/Evaluation-ch.md b/documentation20/webdocs/markdowndocs/Evaluation-ch.md
index 7d09d0dd33a332d4b74dd16bd64cb4e9503fd07d..9e7e0ec6aa8b60bfa9dbe603a45a265a1d1eba00 100644
--- a/documentation20/webdocs/markdowndocs/Evaluation-ch.md
+++ b/documentation20/webdocs/markdowndocs/Evaluation-ch.md
@@ -11,7 +11,7 @@ TDengine的模块之一是时序数据库。但除此之外,为减少研发的
* __全栈时序数据处理引擎__:将数据库、消息队列、缓存、流式计算等功能融为一体,应用无需再集成Kafka/Redis/HBase/Spark/HDFS等软件,大幅降低应用开发和维护的复杂度成本。
* __强大的分析功能__:无论是十年前还是一秒钟前的数据,指定时间范围即可查询。数据可在时间轴上或多个设备上进行聚合。即席查询可通过Shell, Python, R, Matlab随时进行。
* __与第三方工具无缝连接__:不用一行代码,即可与Telegraf, Grafana, EMQ, Prometheus, Matlab, R等集成。后续将支持OPC, Hadoop, Spark等, BI工具也将无缝连接。
-* __零运维成本、零学习成本__:安装、集群一秒搞定,无需分库分表,实时备份。标准SQL,支持JDBC, RESTful, 支持Python/Java/C/C++/Go, 与MySQL相似,零学习成本。
+* __零运维成本、零学习成本__:安装集群简单快捷,无需分库分表,实时备份。类似标准SQL,支持RESTful, 支持Python/Java/C/C++/C#/Go/Node.js, 与MySQL相似,零学习成本。
采用TDengine,可将典型的物联网、车联网、工业互联网大数据平台的总拥有成本大幅降低。但需要指出的是,因充分利用了物联网时序数据的特点,它无法用来处理网络爬虫、微博、微信、电商、ERP、CRM等通用型数据。
diff --git a/documentation20/webdocs/markdowndocs/Getting Started-ch.md b/documentation20/webdocs/markdowndocs/Getting Started-ch.md
index 0e751d8cd59603ddaf85330b0fe309f4373e5c09..beb0c639ae7f5d6b5535b194f70d806305208492 100644
--- a/documentation20/webdocs/markdowndocs/Getting Started-ch.md
+++ b/documentation20/webdocs/markdowndocs/Getting Started-ch.md
@@ -30,13 +30,13 @@ TDengine软件分为服务器、客户端和报警模块三部分,目前2.0版
- TDengine-alert-2.0.0-Linux-x64.tar.gz (8.1M)
-目前,TDengine只支持在使用[`systemd`](https://en.wikipedia.org/wiki/Systemd)做进程服务管理的linux系统上安装。其他linux系统的支持正在开发中。用`which`命令来检测系统中是否存在`systemd`:
+目前,TDengine只支持在使用[`systemd`](https://en.wikipedia.org/wiki/Systemd)做进程服务管理的linux系统上安装。其他linux系统的支持正在开发中。用`which systemctl`命令来检测系统中是否存在`systemd`包:
```cmd
-which systemd
+which systemctl
```
-如果系统中不存在`systemd`命令,请考虑[通过源码安装](#通过源码安装)TDengine。
+如果系统中不存在`systemd`包,请考虑[通过源码安装](#通过源码安装)TDengine。
具体的安装过程,请参见TDengine多种安装包的安装和卸载。
diff --git a/documentation20/webdocs/markdowndocs/Getting Started.md b/documentation20/webdocs/markdowndocs/Getting Started.md
index 00d97d3d9cd3d2ce8317938eb9e46ae74b48dab1..4d34cb49f4a84ac6c9d63e47bc8230c150b9013e 100644
--- a/documentation20/webdocs/markdowndocs/Getting Started.md
+++ b/documentation20/webdocs/markdowndocs/Getting Started.md
@@ -16,13 +16,13 @@ Three different packages are provided, please pick up the one you like.
TDengine DEB package (1.7M)
TDengine Tarball (3.0M)
-For the time being, TDengine only supports installation on Linux systems using [`systemd`](https://en.wikipedia.org/wiki/Systemd) as the service manager. To check if your system has *systemd*, use the _which_ command.
+For the time being, TDengine only supports installation on Linux systems using [`systemd`](https://en.wikipedia.org/wiki/Systemd) as the service manager. To check if your system has *systemd* package, use the _which systemctl_ command.
```cmd
-which systemd
+which systemctl
```
-If the `systemd` command is not found, please [install from source code](#Install-from-Source).
+If the `systemd` package is not found, please [install from source code](#Install-from-Source).
### Running TDengine
diff --git a/documentation20/webdocs/markdowndocs/Queries-ch.md b/documentation20/webdocs/markdowndocs/Queries-ch.md
index 1394338f5420d9b2e2dbc2206879ac36a5c52cf8..97383c78f7b51d1a99c7452593971ba7db48e204 100644
--- a/documentation20/webdocs/markdowndocs/Queries-ch.md
+++ b/documentation20/webdocs/markdowndocs/Queries-ch.md
@@ -29,23 +29,9 @@ Query OK, 2 row(s) in set (0.001100s)
具体的查询语法请看TAOS SQL 。
## 多表聚合查询
+物联网场景中,往往同一个类型的数据采集点有多个。TDengine采用超级表(STable)的概念来描述某一个类型的数据采集点,一张普通的表来描述一个具体的数据采集点。同时TDengine使用标签来描述数据采集点的静态属性,一个具体的数据采集点有具体的标签值。通过指定标签的过滤条件,TDengine提供了一高效的方法将超级表(某一类型的数据采集点)所属的子表进行聚合查询。对普通表的聚合函数以及绝大部分操作都适用于超级表,语法完全一样。
-TDengine对每个数据采集点单独建表,但在实际应用中经常需要对不同的采集点数据进行聚合。为高效的进行聚合操作,TDengine引入超级表(STable)的概念。超级表用来代表一特定类型的数据采集点,它是包含多张表的表集合,集合里每张表的模式(schema)完全一致,但每张表都带有自己的静态标签,标签可以多个,可以随时增加、删除和修改。
-
-应用可通过指定标签的过滤条件,对一个STable下的全部或部分表进行聚合或统计操作,这样大大简化应用的开发。其具体流程如下图所示:
-
-
-
- 多表聚合查询原理图
-
-1:应用将一个查询条件发往系统;2: taosc将超级表的名字发往 Meta Node(管理节点);3:管理节点将超级表所拥有的 vnode 列表发回 taosc;4:taosc将计算的请求连同标签过滤条件发往这些vnode对应的多个数据节点;5:每个vnode先在内存里查找出自己节点里符合标签过滤条件的表的集合,然后扫描存储的时序数据,完成相应的聚合计算,将结果返回给taosc;6:taosc将多个数据节点返回的结果做最后的聚合,将其返回给应用。
-
-由于TDengine在vnode内将标签数据与时序数据分离存储,通过先在内存里过滤标签数据,将需要扫描的数据集大幅减少,大幅提升聚合计算速度。同时,由于数据分布在多个vnode/dnode,聚合计算操作在多个vnode里并发进行,又进一步提升了聚合的速度。
-
-对普通表的聚合函数以及绝大部分操作都适用于超级表,语法完全一样,细节请看 TAOS SQL。
-
-比如:在TAOS Shell,查找所有智能电表采集的电压平均值,并按照location分组
-
+**示例1**:在TAOS Shell,查找北京所有智能电表采集的电压平均值,并按照location分组
```mysql
taos> SELECT AVG(voltage) FROM meters GROUP BY location;
avg(voltage) | location |
@@ -55,6 +41,18 @@ taos> SELECT AVG(voltage) FROM meters GROUP BY location;
Query OK, 2 row(s) in set (0.002136s)
```
+**示例2**:在TAOS shell, 查找groupId为2的所有智能电表过去24小时的记录条数,电流的最大值
+
+```mysql
+taos> SELECT count(*), max(current) FROM meters where groupId = 2 and ts > now - 24h;
+ cunt(*) | max(current) |
+==================================
+ 5 | 13.4 |
+Query OK, 1 row(s) in set (0.002136s)
+```
+
+TDengine仅容许对属于同一个超级表的表之间进行聚合查询,不同超级表之间的聚合查询不支持。在TAOS SQL 一章,查询类操作都会注明是否支持超级表。
+
## 降采样查询、插值
物联网场景里,经常需要通过降采样(down sampling)将采集的数据按时间段进行聚合。TDengine 提供了一个简便的关键词 interval 让按照时间窗口的查询操作变得极为简单。比如,将智能电表 d1001 采集的电流值每10秒钟求和
@@ -66,9 +64,9 @@ taos> SELECT sum(current) FROM d1001 INTERVAL(10s);
2018-10-03 14:38:10.000 | 24.900000572 |
Query OK, 2 row(s) in set (0.000883s)
```
-降采样操作也适用于超级表,比如:将所有智能电表采集的电流值每秒钟求和
+降采样操作也适用于超级表,比如:将北京所有智能电表采集的电流值每秒钟求和
```mysql
-taos> SELECT SUM(current) FROM meters INTERVAL(1s);
+taos> SELECT SUM(current) FROM meters where location like "Beijing%" INTERVAL(1s);
ts | sum(current) |
======================================================
2018-10-03 14:38:04.000 | 10.199999809 |
diff --git a/documentation20/webdocs/markdowndocs/TAOS SQL-ch.md b/documentation20/webdocs/markdowndocs/TAOS SQL-ch.md
index 66d17c6aa686a7ed07ff1b865000f7b4a43f3834..4082d72f112e8ff62d2e8b2c8b15391dd6f39d8a 100644
--- a/documentation20/webdocs/markdowndocs/TAOS SQL-ch.md
+++ b/documentation20/webdocs/markdowndocs/TAOS SQL-ch.md
@@ -124,7 +124,8 @@ TDengine缺省的时间戳是毫秒精度,但通过修改配置参数enableMic
说明:
1) 表的第一个字段必须是TIMESTAMP,并且系统自动将其设为主键;
2) 表名最大长度为193;
- 3) 表的每行长度不能超过16k个字符;
+ 3) 表的每行长度不能超过16k个字符;
+ 4) 子表名只能由字母、数字和下划线组成,且不能以数字开头
5) 使用数据类型binary或nchar,需指定其最长的字节数,如binary(20),表示20字节;
- **删除数据表**
diff --git a/documentation20/webdocs/markdowndocs/architecture-ch.md b/documentation20/webdocs/markdowndocs/architecture-ch.md
index c7f3eba9efa7ff34cafef9b52b32dec5b113da60..ba45bc4796e6f0fb544f7383f74528ee486d94e5 100644
--- a/documentation20/webdocs/markdowndocs/architecture-ch.md
+++ b/documentation20/webdocs/markdowndocs/architecture-ch.md
@@ -65,24 +65,24 @@ TDengine 的设计是基于单个硬件、软件系统不可靠,基于任何
TDengine 分布式架构的逻辑结构图如下:
图 1 TDengine架构示意图
-一个完整的 TDengine 系统是运行在一到多个物理节点上的,逻辑上,它包含数据节点(dnode)、TDengine客户端(taosc)以及应用(app)。系统中存在一到多个数据节点,这些数据节点组成一个集群(cluster)。应用通过taosc的API与TDengine集群进行互动。下面对每个逻辑单元进行简要介绍。
+一个完整的 TDengine 系统是运行在一到多个物理节点上的,逻辑上,它包含数据节点(dnode)、TDengine应用驱动(taosc)以及应用(app)。系统中存在一到多个数据节点,这些数据节点组成一个集群(cluster)。应用通过taosc的API与TDengine集群进行互动。下面对每个逻辑单元进行简要介绍。
-**物理节点(pnode):** pnode是一独立运行、拥有自己的计算、存储和网络能力的计算机,可以是安装有OS的物理机、虚拟机或容器。物理节点由其配置的 FQDN(Fully Qualified Domain Name)来标识。TDengine完全依赖FQDN来进行网络通讯,如果不了解FQDN,请看博文《[一篇文章说清楚TDengine的FQDN](https://www.taosdata.com/blog/2020/09/11/1824.html)》。
+**物理节点(pnode):** pnode是一独立运行、拥有自己的计算、存储和网络能力的计算机,可以是安装有OS的物理机、虚拟机或Docker容器。物理节点由其配置的 FQDN(Fully Qualified Domain Name)来标识。TDengine完全依赖FQDN来进行网络通讯,如果不了解FQDN,请看博文《[一篇文章说清楚TDengine的FQDN](https://www.taosdata.com/blog/2020/09/11/1824.html)》。
**数据节点(dnode):** dnode 是 TDengine 服务器侧执行代码 taosd 在物理节点上的一个运行实例,一个工作的系统必须有至少一个数据节点。dnode包含零到多个逻辑的虚拟节点(VNODE),零或者至多一个逻辑的管理节点(mnode)。dnode在系统中的唯一标识由实例的End Point (EP )决定。EP是dnode所在物理节点的FQDN (Fully Qualified Domain Name)和系统所配置的网络端口号(Port)的组合。通过配置不同的端口,一个物理节点(一台物理机、虚拟机或容器)可以运行多个实例,或有多个数据节点。
-**虚拟节点(vnode)**: 为更好的支持数据分片、负载均衡,防止数据过热或倾斜,数据节点被虚拟化成多个虚拟节点(vnode,图中V2, V3, V4等)。每个 vnode 都是一个相对独立的工作单元,是时序数据存储的基本单元,具有独立的运行线程、内存空间与持久化存储的路径。一个 vnode 包含一定数量的表(数据采集点)。当创建一张新表时,系统会检查是否需要创建新的 vnode。一个数据节点上能创建的 vnode 的数量取决于该数据节点所在物理节点的硬件资源。一个 vnode 只属于一个DB,但一个DB可以有多个 vnode。一个 vnode 除存储的时序数据外,也保存有所包含的表的SCHEMA、标签值等。一个虚拟节点由所属的数据节点的EP,以及所属的VGroup ID在系统内唯一标识,由管理节点创建并管理。
+**虚拟节点(vnode)**: 为更好的支持数据分片、负载均衡,防止数据过热或倾斜,数据节点被虚拟化成多个虚拟节点(vnode,图中V2, V3, V4等)。每个 vnode 都是一个相对独立的工作单元,是时序数据存储的基本单元,具有独立的运行线程、内存空间与持久化存储的路径。一个 vnode 包含一定数量的表(数据采集点)。当创建一张新表时,系统会检查是否需要创建新的 vnode。一个数据节点上能创建的 vnode 的数量取决于该数据节点所在物理节点的硬件资源。一个 vnode 只属于一个DB,但一个DB可以有多个 vnode。一个 vnode 除存储的时序数据外,也保存有所包含的表的schema、标签值等。一个虚拟节点由所属的数据节点的EP,以及所属的VGroup ID在系统内唯一标识,由管理节点创建并管理。
**管理节点(mnode):** 一个虚拟的逻辑单元,负责所有数据节点运行状态的监控和维护,以及节点之间的负载均衡(图中M)。同时,管理节点也负责元数据(包括用户、数据库、表、静态标签等)的存储和管理,因此也称为 Meta Node。TDengine 集群中可配置多个(最多不超过5个) mnode,它们自动构建成为一个虚拟管理节点组(图中M0, M1, M2)。mnode 间采用 master/slave 的机制进行管理,而且采取强一致方式进行数据同步, 任何数据更新操作只能在 Master 上进行。mnode 集群的创建由系统自动完成,无需人工干预。每个dnode上至多有一个mnode,由所属的数据节点的EP来唯一标识。每个dnode通过内部消息交互自动获取整个集群中所有 mnode 所在的 dnode 的EP。
**虚拟节点组(VGroup):** 不同数据节点上的 vnode 可以组成一个虚拟节点组(vnode group)来保证系统的高可靠。虚拟节点组内采取master/slave的方式进行管理。写操作只能在 master vnode 上进行,系统采用异步复制的方式将数据同步到 slave vnode,这样确保了一份数据在多个物理节点上有拷贝。一个 vgroup 里虚拟节点个数就是数据的副本数。如果一个DB的副本数为N,系统必须有至少N个数据节点。副本数在创建DB时通过参数 replica 可以指定,缺省为1。使用 TDengine 的多副本特性,可以不再需要昂贵的磁盘阵列等存储设备,就可以获得同样的数据高可靠性。虚拟节点组由管理节点创建、管理,并且由管理节点分配一个系统唯一的ID,VGroup ID。如果两个虚拟节点的vnode group ID相同,说明他们属于同一个组,数据互为备份。虚拟节点组里虚拟节点的个数是可以动态改变的,容许只有一个,也就是没有数据复制。VGroup ID是永远不变的,即使一个虚拟节点组被删除,它的ID也不会被收回重复利用。
-**TAOSC:** taosc是TDengine给应用提供的驱动程序(driver),负责处理应用与集群的接口交互,内嵌于JDBC、ODBC driver中,或者C、Python、Go语言连接库里。应用都是通过taosc而不是直接连接集群中的数据节点与整个集群进行交互的。这个模块负责获取并缓存元数据;将插入、查询等请求转发到正确的数据节点;在把结果返回给应用时,还需要负责最后一级的聚合、排序、过滤等操作。对于JDBC, ODBC, C/C++接口而言,这个模块是在应用所处的物理节点上运行,但消耗的资源很小。同时,为支持全分布式的RESTful接口,taosc在TDengine集群的每个dnode上都有一运行实例。
+**TAOSC:** taosc是TDengine给应用提供的驱动程序(driver),负责处理应用与集群的接口交互,提供C/C++语言原生接口,内嵌于JDBC、C#、Python、Go、Node.js语言连接库里。应用都是通过taosc而不是直接连接集群中的数据节点与整个集群进行交互的。这个模块负责获取并缓存元数据;将插入、查询等请求转发到正确的数据节点;在把结果返回给应用时,还需要负责最后一级的聚合、排序、过滤等操作。对于JDBC, C/C++/C#/Python/Go/Node.js接口而言,这个模块是在应用所处的物理节点上运行。同时,为支持全分布式的RESTful接口,taosc在TDengine集群的每个dnode上都有一运行实例。
### 节点之间的通讯
-**通讯方式:**TDengine系统的各个节点之间的通讯是通过TCP/UDP进行的。因为考虑到物联网场景,数据写入的包一般不大,因此TDengine 除采用TCP做传输之外,还采用UDP方式,因为UDP 更加高效,而且不受连接数的限制。TDengine实现了自己的超时、重传、确认等机制,以确保UDP的可靠传输。对于数据量不到15K的数据包,采取UDP的方式进行传输,超过15K的,或者是查询类的操作,自动采取TCP的方式进行传输。同时,TDengine根据配置和数据包,会自动对数据进行压缩/解压缩,数字签名/认证等处理。对于数据节点之间的数据复制,只采用TCP方式进行数据传输。
+**通讯方式:**TDengine系统的各个数据节点之间,以及应用驱动与各数据节点之间的通讯是通过TCP/UDP进行的。因为考虑到物联网场景,数据写入的包一般不大,因此TDengine 除采用TCP做传输之外,还采用UDP方式,因为UDP 更加高效,而且不受连接数的限制。TDengine实现了自己的超时、重传、确认等机制,以确保UDP的可靠传输。对于数据量不到15K的数据包,采取UDP的方式进行传输,超过15K的,或者是查询类的操作,自动采取TCP的方式进行传输。同时,TDengine根据配置和数据包,会自动对数据进行压缩/解压缩,数字签名/认证等处理。对于数据节点之间的数据复制,只采用TCP方式进行数据传输。
-**FQDN配置**:一个数据节点有一个或多个FQDN,可以在系统配置文件taos.cfg通过参数“fqdn"进行指定,如果没有指定,系统将自动获取FQDN。如果节点没有配置FQDN,可以直接将该节点的配置参数fqdn设置为它的IP地址。但不建议使用IP,因为IP地址可变,一旦变化,将让集群无法正常工作。一个数据节点的EP(End Point)由FQDN + Port组成。采用FQDN,需要保证DNS服务正常工作,或者在节点以及应用所在的节点配置好hosts文件。
+**FQDN配置**:一个数据节点有一个或多个FQDN,可以在系统配置文件taos.cfg通过参数“fqdn"进行指定,如果没有指定,系统将自动获取计算机的hostname作为其FQDN。如果节点没有配置FQDN,可以直接将该节点的配置参数fqdn设置为它的IP地址。但不建议使用IP,因为IP地址可变,一旦变化,将让集群无法正常工作。一个数据节点的EP(End Point)由FQDN + Port组成。采用FQDN,需要保证DNS服务正常工作,或者在节点以及应用所在的节点配置好hosts文件。
**端口配置:**一个数据节点对外的端口由TDengine的系统配置参数serverPort决定,对集群内部通讯的端口是serverPort+5。集群内数据节点之间的数据复制操作还占有一个TCP端口,是serverPort+10. 为支持多线程高效的处理UDP数据,每个对内和对外的UDP连接,都需要占用5个连续的端口。因此一个数据节点总的端口范围为serverPort到serverPort + 10,总共11个TCP/UDP端口。使用时,需要确保防火墙将这些端口打开。每个数据节点可以配置不同的serverPort。
@@ -153,6 +153,7 @@ TDengine除vnode分片之外,还对时序数据按照时间段进行分区。
当新的数据节点被添加进集群,因为新的计算和存储被添加进来,系统也将自动启动负载均衡流程。
负载均衡过程无需任何人工干预,应用也无需重启,将自动连接新的节点,完全透明。
+**提示:负载均衡由参数balance控制,决定开启/关闭自动负载均衡。**
## 数据写入与复制流程
如果一个数据库有N个副本,那一个虚拟节点组就有N个虚拟节点,但是只有一个是Master,其他都是slave。当应用将新的记录写入系统时,只有Master vnode能接受写的请求。如果slave vnode收到写的请求,系统将通知taosc需要重新定向。
@@ -192,7 +193,8 @@ Master Vnode遵循下面的写入流程:
理论上,只要是异步复制,就无法保证100%不丢失。但是这个窗口极小,mater与slave要同时发生故障,而且发生在刚给应用确认写入成功之后。
-注:异地容灾、IDC无中断迁移,仅仅企业版支持
+注:异地容灾、IDC无中断迁移,仅仅企业版支持。
+**提示:该功能暂未提供**
### 主从选择
Vnode会保持一个数据版本号(Version),对内存数据进行持久化存储时,对该版本号也进行持久化存储。每个数据更新操作,无论是采集的时序数据还是元数据,这个版本号将增一。
@@ -259,6 +261,7 @@ dataDir /mnt/disk6/taos 2
挂载的盘也可以是非本地的网络盘,只要系统能访问即可。
注:多级存储功能仅企业版支持
+**提示:该功能暂未提供**
## 数据查询
TDengine提供了多种多样针对表和超级表的查询处理功能,除了常规的聚合查询之外,还提供针对时序数据的窗口查询、统计聚合等功能。TDengine的查询处理需要客户端、vnode, mnode节点协同完成。
@@ -289,11 +292,18 @@ select count(*) from d1001 interval(1h) fill(prev);
针对d1001设备采集数据统计每小时记录数,如果某一个小时不存在数据,这返回之前一个小时的统计数据。TDengine提供前向插值(prev)、线性插值(linear)、NULL值填充(NULL)、特定值填充(value)。
### 多表聚合查询
-多表聚合查询与单表查询的整体流程相同,但是存在如下的差异:
-
-- 由于多表可能分布在不同的节点(dnode),因此多表的聚合查询需要首先获得表所在的全部数据节点的信息,并且同时向相关的dnode发出查询请求。
-- 每个vnode的计算获得的中间结果(partial results)需要进行第二阶段的聚合才能形成最终结果,第二阶段的聚合过程在客户端完成。
-- 由于表标签信息存储在vnode中,因此针对标签信息的查询也需要vnode完成。客户端将标签的过滤表达式封装在查询请求结构体中发送给vnode,由vnode的查询执行线程从中抽取出标签查询条件,然后执行查询。标签查询与过滤是在针对表的查询之前完成。标签查询完成以后,将符合条件的表纳入到接下来的查询处理流程中。
+TDengine对每个数据采集点单独建表,但在实际应用中经常需要对不同的采集点数据进行聚合。为高效的进行聚合操作,TDengine引入超级表(STable)的概念。超级表用来代表一特定类型的数据采集点,它是包含多张表的表集合,集合里每张表的模式(schema)完全一致,但每张表都带有自己的静态标签,标签可以多个,可以随时增加、删除和修改。 应用可通过指定标签的过滤条件,对一个STable下的全部或部分表进行聚合或统计操作,这样大大简化应用的开发。其具体流程如下图所示:
+
+
+ 图 5 多表聚合查询原理图
+1:应用将一个查询条件发往系统;
+2: taosc将超级表的名字发往 Meta Node(管理节点);
+3:管理节点将超级表所拥有的 vnode 列表发回 taosc;
+4:taosc将计算的请求连同标签过滤条件发往这些vnode对应的多个数据节点;
+5:每个vnode先在内存里查找出自己节点里符合标签过滤条件的表的集合,然后扫描存储的时序数据,完成相应的聚合计算,将结果返回给taosc;
+6:taosc将多个数据节点返回的结果做最后的聚合,将其返回给应用。
+
+由于TDengine在vnode内将标签数据与时序数据分离存储,通过在内存里过滤标签数据,先找到需要参与聚合操作的表的集合,将需要扫描的数据集大幅减少,大幅提升聚合计算速度。同时,由于数据分布在多个vnode/dnode,聚合计算操作在多个vnode里并发进行,又进一步提升了聚合的速度。 对普通表的聚合函数以及绝大部分操作都适用于超级表,语法完全一样,细节请看 TAOS SQL。
### 预计算
为有效提升查询处理的性能,针对物联网数据的不可更改的特点,在数据块头部记录该数据块中存储数据的统计信息:包括最大值、最小值、和。我们称之为预计算单元。如果查询处理涉及整个数据块的全部数据,直接使用预计算结果,完全不需要读取数据块的内容。由于预计算数据量远小于磁盘上存储的数据块数据的大小,对于磁盘IO为瓶颈的查询处理,使用预计算结果可以极大地减小读取IO压力,加速查询处理的流程。预计算机制与Postgre SQL的索引BRIN(block range index)有异曲同工之妙。
diff --git a/documentation20/webdocs/markdowndocs/cluster-ch.md b/documentation20/webdocs/markdowndocs/cluster-ch.md
index 13b773b3e302185009a07d4aa20db620ef702631..0e7a26eb3a8eff7d0c09cbd430bae3c4688293e1 100644
--- a/documentation20/webdocs/markdowndocs/cluster-ch.md
+++ b/documentation20/webdocs/markdowndocs/cluster-ch.md
@@ -8,7 +8,7 @@ TDengine的集群管理极其简单,除添加和删除节点需要人工干预
## 准备工作
-**第零步**:如果没有部署DNS服务,请规划集群所有物理节点的FQDN,然后按照《[一篇文章说清楚TDengine的FQDN](https://www.taosdata.com/blog/2020/09/11/1824.html)》里的步骤,将所有集群物理节点的IP与FQDN的对应关系添加好。
+**第零步**:规划集群所有物理节点的FQDN,将规划好的FQDN分别添加到每个物理节点的/etc/hostname;修改每个物理节点的/etc/hosts,将所有集群物理节点的IP与FQDN的对应添加好。【如部署了DNS,请联系网络管理员在DNS上做好相关配置】
**第一步**:如果搭建集群的物理节点中,存有之前的测试数据、装过1.X的版本,或者装过其他版本的TDengine,请先将其删除,并清空所有数据,具体步骤请参考博客[《TDengine多种安装包的安装和卸载》](https://www.taosdata.com/blog/2019/08/09/566.html )
**注意1:**因为FQDN的信息会写进文件,如果之前没有配置或者更改FQDN,且启动了TDengine。请一定在确保数据无用或者备份的前提下,清理一下之前的数据(rm -rf /var/lib/taos/);
@@ -16,9 +16,9 @@ TDengine的集群管理极其简单,除添加和删除节点需要人工干预
**第二步**:建议关闭所有物理节点的防火墙,至少保证端口:6030 - 6042的TCP和UDP端口都是开放的。**强烈建议**先关闭防火墙,集群搭建完毕之后,再来配置端口;
-**第三步**:在所有节点安装TDengine,且版本必须是一致的,**但不要启动taosd**。安装时,提示输入是否要加入一个已经存在的TDengine集群时,第一个物理节点直接回车创建新集群,后续物理节点则输入该集群任何一个在线的物理节点的FQDN:端口号(默认6030);
+**第三步**:在所有物理节点安装TDengine,且版本必须是一致的,**但不要启动taosd**。安装时,提示输入是否要加入一个已经存在的TDengine集群时,第一个物理节点直接回车创建新集群,后续物理节点则输入该集群任何一个在线的物理节点的FQDN:端口号(默认6030);
-**第四步**:检查所有数据节点,以及应用所在物理节点的网络设置:
+**第四步**:检查所有数据节点,以及应用程序所在物理节点的网络设置:
1. 每个物理节点上执行命令`hostname -f`,查看和确认所有节点的hostname是不相同的(应用驱动所在节点无需做此项检查);
2. 每个物理节点上执行`ping host`, 其中host是其他物理节点的hostname, 看能否ping通其它物理节点; 如果不能ping通,需要检查网络设置, 或/etc/hosts文件(Windows系统默认路径为C:\Windows\system32\drivers\etc\hosts),或DNS的配置。如果无法ping通,是无法组成集群的;
diff --git a/documentation20/webdocs/markdowndocs/insert-ch.md b/documentation20/webdocs/markdowndocs/insert-ch.md
index a84b577622b450089b22a961d6e5fe71627930c6..fa53cbd62b17169c0f54877a62da8c48ac21edcf 100644
--- a/documentation20/webdocs/markdowndocs/insert-ch.md
+++ b/documentation20/webdocs/markdowndocs/insert-ch.md
@@ -22,7 +22,7 @@ INSERT INTO d1001 VALUES (1538548685000, 10.3, 219, 0.31) (1538548695000, 12.6,
**Tips:**
-- 要提高写入效率,需要批量写入。一批写入的记录条数越多,插入效率就越高。但一条记录不能超过16K,一条SQL语句总长度不能超过64K(可通过参数maxSQLLength配置,最大可配置为8M)。
+- 要提高写入效率,需要批量写入。一批写入的记录条数越多,插入效率就越高。但一条记录不能超过16K,一条SQL语句总长度不能超过64K(可通过参数maxSQLLength配置,最大可配置为1M)。
- TDengine支持多线程同时写入,要进一步提高写入速度,一个客户端需要打开20个以上的线程同时写。但线程数达到一定数量后,无法再提高,甚至还会下降,因为线程切频繁切换,带来额外开销。
- 对同一张表,如果新插入记录的时间戳已经存在,新记录将被直接抛弃,也就是说,在一张表里,时间戳必须是唯一的。如果应用自动生成记录,很有可能生成的时间戳是一样的,这样,成功插入的记录条数会小于应用插入的记录条数。
- 写入的数据的时间戳必须大于当前时间减去配置参数keep的时间。如果keep配置为3650天,那么无法写入比3650天还老的数据。写入数据的时间戳也不能大于当前时间加配置参数days。如果days配置为2,那么无法写入比当前时间还晚2天的数据。
diff --git a/src/connector/go b/src/connector/go
index 567b7b12f3fd2775c718d284beffc8c38dd6c219..8c58c512b6acda8bcdfa48fdc7140227b5221766 160000
--- a/src/connector/go
+++ b/src/connector/go
@@ -1 +1 @@
-Subproject commit 567b7b12f3fd2775c718d284beffc8c38dd6c219
+Subproject commit 8c58c512b6acda8bcdfa48fdc7140227b5221766
diff --git a/src/dnode/src/dnodeMgmt.c b/src/dnode/src/dnodeMgmt.c
index 8f87a45fb724b667236e7ebb5a47460975dac362..8f2b687dc4df129d508ba0a1515d5b00d41a57c1 100644
--- a/src/dnode/src/dnodeMgmt.c
+++ b/src/dnode/src/dnodeMgmt.c
@@ -468,8 +468,24 @@ void dnodeUpdateMnodeEpSetForPeer(SRpcEpSet *pEpSet) {
if (!mnodeIsRunning()) {
if (strcmp(pEpSet->fqdn[i], tsLocalFqdn) == 0 && pEpSet->port[i] == tsServerPort) {
- dInfo("mnode index:%d %s:%u should work as master", i, pEpSet->fqdn[i], pEpSet->port[i]);
- sdbUpdateSync();
+ dInfo("mnode index:%d %s:%u should work as mnode", i, pEpSet->fqdn[i], pEpSet->port[i]);
+ bool find = false;
+ for (int i = 0; i < tsDMnodeInfos.nodeNum; ++i) {
+ if (tsDMnodeInfos.nodeInfos[i].nodeId == dnodeGetDnodeId()) {
+ dInfo("localEp found in mnode infos");
+ find = true;
+ break;
+ }
+ }
+
+ if (!find) {
+ dInfo("localEp not found in mnode infos, will set into mnode infos");
+ tstrncpy(tsDMnodeInfos.nodeInfos[tsDMnodeInfos.nodeNum].nodeEp, tsLocalEp, TSDB_EP_LEN);
+ tsDMnodeInfos.nodeInfos[tsDMnodeInfos.nodeNum].nodeId = dnodeGetDnodeId();
+ tsDMnodeInfos.nodeNum++;
+ }
+
+ dnodeStartMnode();
}
}
}
diff --git a/src/dnode/src/dnodeModule.c b/src/dnode/src/dnodeModule.c
index 18a293d41588033a27c4f1bf88e3af0d1d527eec..ba7cdf2664cb641047f5651920925808e5ec530e 100644
--- a/src/dnode/src/dnodeModule.c
+++ b/src/dnode/src/dnodeModule.c
@@ -146,19 +146,16 @@ void dnodeProcessModuleStatus(uint32_t moduleStatus) {
}
}
-bool dnodeCheckMnodeStarting() {
- if (tsModuleStatus & (1 << TSDB_MOD_MNODE)) return false;
-
- SDMMnodeInfos *mnodes = dnodeGetMnodeInfos();
- for (int32_t i = 0; i < mnodes->nodeNum; ++i) {
- SDMMnodeInfo *node = &mnodes->nodeInfos[i];
- if (node->nodeId == dnodeGetDnodeId()) {
- uint32_t moduleStatus = tsModuleStatus | (1 << TSDB_MOD_MNODE);
- dInfo("start mnode module, module status:%d, new status:%d", tsModuleStatus, moduleStatus);
- dnodeProcessModuleStatus(moduleStatus);
- return true;
- }
+bool dnodeStartMnode() {
+ if (tsModuleStatus & (1 << TSDB_MOD_MNODE)) {
+ dDebug("mnode module is already started, module status:%d", tsModuleStatus);
+ return false;
}
- return false;
+ uint32_t moduleStatus = tsModuleStatus | (1 << TSDB_MOD_MNODE);
+ dInfo("start mnode module, module status:%d, new status:%d", tsModuleStatus, moduleStatus);
+ dnodeProcessModuleStatus(moduleStatus);
+
+ sdbUpdateSync();
+ return true;
}
diff --git a/src/dnode/src/dnodeVRead.c b/src/dnode/src/dnodeVRead.c
index d66ebf9772bcf702490b5c780de3223cd1b6a833..fb4ffcdafa3847d1583a58b773738148b53e2c1d 100644
--- a/src/dnode/src/dnodeVRead.c
+++ b/src/dnode/src/dnodeVRead.c
@@ -187,6 +187,7 @@ void dnodeSendRpcReadRsp(void *pVnode, SReadMsg *pRead, int32_t code) {
}
void dnodeDispatchNonRspMsg(void *pVnode, SReadMsg *pRead, int32_t code) {
+ rpcFreeCont(pRead->rpcMsg.pCont);
vnodeRelease(pVnode);
return;
}
diff --git a/src/inc/dnode.h b/src/inc/dnode.h
index fda9c1c1ddd928ccf02bd6fd8a1480b30769bb6b..017241c4f869dcc450dd552c922e72446c8922f7 100644
--- a/src/inc/dnode.h
+++ b/src/inc/dnode.h
@@ -43,7 +43,7 @@ void dnodeGetMnodeEpSetForPeer(void *epSet);
void dnodeGetMnodeEpSetForShell(void *epSet);
void * dnodeGetMnodeInfos();
int32_t dnodeGetDnodeId();
-bool dnodeCheckMnodeStarting();
+bool dnodeStartMnode();
void dnodeAddClientRspHandle(uint8_t msgType, void (*fp)(SRpcMsg *rpcMsg));
void dnodeSendMsgToDnode(SRpcEpSet *epSet, SRpcMsg *rpcMsg);
diff --git a/src/mnode/src/mnodeSdb.c b/src/mnode/src/mnodeSdb.c
index 4c672eb557427d76f0989a4d8975eb7f7856c39e..7654536122873ce3fbc37a300a87f767bd33d415 100644
--- a/src/mnode/src/mnodeSdb.c
+++ b/src/mnode/src/mnodeSdb.c
@@ -91,7 +91,6 @@ typedef struct {
} SSdbWriteWorkerPool;
extern void * tsMnodeTmr;
-static void * tsUpdateSyncTmr;
static SSdbObject tsSdbObj = {0};
static taos_qset tsSdbWriteQset;
static taos_qall tsSdbWriteQall;
@@ -298,16 +297,12 @@ static void sdbConfirmForward(void *ahandle, void *param, int32_t code) {
taosFreeQitem(pOper);
}
-static void sdbUpdateSyncTmrFp(void *param, void *tmrId) { sdbUpdateSync(); }
-
void sdbUpdateSync() {
if (!mnodeIsRunning()) {
mDebug("mnode not start yet, update sync info later");
- if (dnodeCheckMnodeStarting()) {
- taosTmrReset(sdbUpdateSyncTmrFp, 1000, NULL, tsMnodeTmr, &tsUpdateSyncTmr);
- }
return;
}
+
mDebug("update sync info in sdb");
SSyncCfg syncCfg = {0};
diff --git a/src/rpc/src/rpcMain.c b/src/rpc/src/rpcMain.c
index f0b8c996c5aec747e69785c469946f80856e05e5..414d37d8b8c3141784a22bb117a8ec6d92b4096a 100644
--- a/src/rpc/src/rpcMain.c
+++ b/src/rpc/src/rpcMain.c
@@ -195,7 +195,7 @@ static void rpcSendMsgToPeer(SRpcConn *pConn, void *data, int dataLen);
static void rpcSendReqHead(SRpcConn *pConn);
static void *rpcProcessMsgFromPeer(SRecvInfo *pRecv);
-static void rpcProcessIncomingMsg(SRpcConn *pConn, SRpcHead *pHead);
+static void rpcProcessIncomingMsg(SRpcConn *pConn, SRpcHead *pHead, SRpcReqContext *pContext);
static void rpcProcessConnError(void *param, void *id);
static void rpcProcessRetryTimer(void *, void *);
static void rpcProcessIdleTimer(void *param, void *tmrId);
@@ -323,7 +323,7 @@ void *rpcMallocCont(int contLen) {
tError("failed to malloc msg, size:%d", size);
return NULL;
} else {
- tDebug("malloc msg: %p", start);
+ tTrace("malloc mem: %p", start);
}
return start + sizeof(SRpcReqContext) + sizeof(SRpcHead);
@@ -333,7 +333,7 @@ void rpcFreeCont(void *cont) {
if (cont) {
char *temp = ((char *)cont) - sizeof(SRpcHead) - sizeof(SRpcReqContext);
free(temp);
- tDebug("free mem: %p", temp);
+ tTrace("free mem: %p", temp);
}
}
@@ -553,7 +553,7 @@ static void rpcFreeMsg(void *msg) {
if ( msg ) {
char *temp = (char *)msg - sizeof(SRpcReqContext);
free(temp);
- tDebug("free msg: %p", temp);
+ tTrace("free mem: %p", temp);
}
}
@@ -819,9 +819,18 @@ static int rpcProcessReqHead(SRpcConn *pConn, SRpcHead *pHead) {
return TSDB_CODE_RPC_LAST_SESSION_NOT_FINISHED;
}
+ if (rpcContLenFromMsg(pHead->msgLen) <= 0) {
+ tDebug("%s, message body is empty, ignore", pConn->info);
+ return TSDB_CODE_RPC_APP_ERROR;
+ }
+
pConn->inTranId = pHead->tranId;
pConn->inType = pHead->msgType;
+ // start the progress timer to monitor the response from server app
+ if (pConn->connType != RPC_CONN_TCPS)
+ pConn->pTimer = taosTmrStart(rpcProcessProgressTimer, tsProgressTimer, pConn, pConn->pRpc->tmrCtrl);
+
return 0;
}
@@ -881,17 +890,32 @@ static int rpcProcessRspHead(SRpcConn *pConn, SRpcHead *pHead) {
pConn->outType = 0;
pConn->pReqMsg = NULL;
pConn->reqMsgLen = 0;
+ SRpcReqContext *pContext = pConn->pContext;
+
+ if (pHead->code == TSDB_CODE_RPC_REDIRECT) {
+ if (rpcContLenFromMsg(pHead->msgLen) < sizeof(SRpcEpSet)) {
+ // if EpSet is not included in the msg, treat it as NOT_READY
+ pHead->code = TSDB_CODE_RPC_NOT_READY;
+ } else {
+ pContext->redirect++;
+ if (pContext->redirect > TSDB_MAX_REPLICA) {
+ pHead->code = TSDB_CODE_RPC_NETWORK_UNAVAIL;
+ tWarn("%s, too many redirects, quit", pConn->info);
+ }
+ }
+ }
return TSDB_CODE_SUCCESS;
}
-static SRpcConn *rpcProcessMsgHead(SRpcInfo *pRpc, SRecvInfo *pRecv) {
+static SRpcConn *rpcProcessMsgHead(SRpcInfo *pRpc, SRecvInfo *pRecv, SRpcReqContext **ppContext) {
int32_t sid;
SRpcConn *pConn = NULL;
SRpcHead *pHead = (SRpcHead *)pRecv->msg;
sid = htonl(pHead->destId);
+ *ppContext = NULL;
if (pHead->msgType >= TSDB_MSG_TYPE_MAX || pHead->msgType <= 0) {
tDebug("%s sid:%d, invalid message type:%d", pRpc->label, sid, pHead->msgType);
@@ -945,6 +969,7 @@ static SRpcConn *rpcProcessMsgHead(SRpcInfo *pRpc, SRecvInfo *pRecv) {
pConn->pIdleTimer = taosTmrStart(rpcProcessIdleTimer, tsRpcTimer*2, pConn, pRpc->tmrCtrl);
} else {
terrno = rpcProcessRspHead(pConn, pHead);
+ *ppContext = pConn->pContext;
}
}
@@ -1009,7 +1034,8 @@ static void *rpcProcessMsgFromPeer(SRecvInfo *pRecv) {
}
terrno = 0;
- pConn = rpcProcessMsgHead(pRpc, pRecv);
+ SRpcReqContext *pContext;
+ pConn = rpcProcessMsgHead(pRpc, pRecv, &pContext);
if (pHead->msgType >= 1 && pHead->msgType < TSDB_MSG_TYPE_MAX) {
tDebug("%s %p %p, %s received from 0x%x:%hu, parse code:0x%x len:%d sig:0x%08x:0x%08x:%d code:0x%x", pRpc->label,
@@ -1029,7 +1055,7 @@ static void *rpcProcessMsgFromPeer(SRecvInfo *pRecv) {
tDebug("%s %p %p, %s is sent with error code:0x%x", pRpc->label, pConn, (void *)pHead->ahandle, taosMsg[pHead->msgType+1], code);
}
} else { // msg is passed to app only parsing is ok
- rpcProcessIncomingMsg(pConn, pHead);
+ rpcProcessIncomingMsg(pConn, pHead, pContext);
}
}
@@ -1060,7 +1086,7 @@ static void rpcNotifyClient(SRpcReqContext *pContext, SRpcMsg *pMsg) {
rpcFreeCont(pContext->pCont);
}
-static void rpcProcessIncomingMsg(SRpcConn *pConn, SRpcHead *pHead) {
+static void rpcProcessIncomingMsg(SRpcConn *pConn, SRpcHead *pHead, SRpcReqContext *pContext) {
SRpcInfo *pRpc = pConn->pRpc;
SRpcMsg rpcMsg;
@@ -1070,29 +1096,18 @@ static void rpcProcessIncomingMsg(SRpcConn *pConn, SRpcHead *pHead) {
rpcMsg.pCont = pHead->content;
rpcMsg.msgType = pHead->msgType;
rpcMsg.code = pHead->code;
- rpcMsg.ahandle = pConn->ahandle;
if ( rpcIsReq(pHead->msgType) ) {
- if (rpcMsg.contLen > 0) {
- rpcMsg.handle = pConn;
- rpcAddRef(pRpc); // add the refCount for requests
+ rpcMsg.ahandle = pConn->ahandle;
+ rpcMsg.handle = pConn;
+ rpcAddRef(pRpc); // add the refCount for requests
- // start the progress timer to monitor the response from server app
- if (pConn->connType != RPC_CONN_TCPS)
- pConn->pTimer = taosTmrStart(rpcProcessProgressTimer, tsProgressTimer, pConn, pRpc->tmrCtrl);
-
- // notify the server app
- (*(pRpc->cfp))(&rpcMsg, NULL);
- } else {
- tDebug("%s, message body is empty, ignore", pConn->info);
- rpcFreeCont(rpcMsg.pCont);
- }
+ // notify the server app
+ (*(pRpc->cfp))(&rpcMsg, NULL);
} else {
// it's a response
- SRpcReqContext *pContext = pConn->pContext;
rpcMsg.handle = pContext;
- pConn->pContext = NULL;
- pConn->pReqMsg = NULL;
+ rpcMsg.ahandle = pContext->ahandle;
// for UDP, port may be changed by server, the port in epSet shall be used for cache
if (pHead->code != TSDB_CODE_RPC_TOO_SLOW) {
@@ -1101,19 +1116,6 @@ static void rpcProcessIncomingMsg(SRpcConn *pConn, SRpcHead *pHead) {
rpcCloseConn(pConn);
}
- if (pHead->code == TSDB_CODE_RPC_REDIRECT) {
- if (rpcMsg.contLen < sizeof(SRpcEpSet)) {
- // if EpSet is not included in the msg, treat it as NOT_READY
- pHead->code = TSDB_CODE_RPC_NOT_READY;
- } else {
- pContext->redirect++;
- if (pContext->redirect > TSDB_MAX_REPLICA) {
- pHead->code = TSDB_CODE_RPC_NETWORK_UNAVAIL;
- tWarn("%s, too many redirects, quit", pConn->info);
- }
- }
- }
-
if (pHead->code == TSDB_CODE_RPC_REDIRECT) {
pContext->numOfTry = 0;
SRpcEpSet *pEpSet = (SRpcEpSet*)pHead->content;
@@ -1445,7 +1447,7 @@ static SRpcHead *rpcDecompressRpcMsg(SRpcHead *pHead) {
pNewHead->msgLen = rpcMsgLenFromCont(origLen);
rpcFreeMsg(pHead); // free the compressed message buffer
pHead = pNewHead;
- //tTrace("decompress rpc msg, compLen:%d, after:%d", compLen, contLen);
+ tTrace("decomp malloc mem: %p", temp);
} else {
tError("failed to allocate memory to decompress msg, contLen:%d", contLen);
}
diff --git a/src/rpc/src/rpcTcp.c b/src/rpc/src/rpcTcp.c
index 2a3facdb36c0b5ea71aa4b3140245f06404f8bea..dd9e7684e03e5cfc8c44dc3555a4ad1d144b90b6 100644
--- a/src/rpc/src/rpcTcp.c
+++ b/src/rpc/src/rpcTcp.c
@@ -62,7 +62,7 @@ typedef struct {
char label[TSDB_LABEL_LEN];
int numOfThreads;
void * shandle;
- SThreadObj *pThreadObj;
+ SThreadObj **pThreadObj;
pthread_t thread;
} SServerObj;
@@ -90,7 +90,7 @@ void *taosInitTcpServer(uint32_t ip, uint16_t port, char *label, int numOfThread
tstrncpy(pServerObj->label, label, sizeof(pServerObj->label));
pServerObj->numOfThreads = numOfThreads;
- pServerObj->pThreadObj = (SThreadObj *)calloc(sizeof(SThreadObj), numOfThreads);
+ pServerObj->pThreadObj = (SThreadObj **)calloc(sizeof(SThreadObj *), numOfThreads);
if (pServerObj->pThreadObj == NULL) {
tError("TCP:%s no enough memory", label);
terrno = TAOS_SYSTEM_ERROR(errno);
@@ -104,19 +104,28 @@ void *taosInitTcpServer(uint32_t ip, uint16_t port, char *label, int numOfThread
pthread_attr_setdetachstate(&thattr, PTHREAD_CREATE_JOINABLE);
// initialize parameters in case it may encounter error later
- pThreadObj = pServerObj->pThreadObj;
for (int i = 0; i < numOfThreads; ++i) {
+ pThreadObj = (SThreadObj *)calloc(sizeof(SThreadObj), 1);
+ if (pThreadObj == NULL) {
+ tError("TCP:%s no enough memory", label);
+ terrno = TAOS_SYSTEM_ERROR(errno);
+ for (int j=0; jpThreadObj[j]);
+ free(pServerObj->pThreadObj);
+ free(pServerObj);
+ return NULL;
+ }
+
+ pServerObj->pThreadObj[i] = pThreadObj;
pThreadObj->pollFd = -1;
taosResetPthread(&pThreadObj->thread);
pThreadObj->processData = fp;
tstrncpy(pThreadObj->label, label, sizeof(pThreadObj->label));
pThreadObj->shandle = shandle;
- pThreadObj++;
}
// initialize mutex, thread, fd which may fail
- pThreadObj = pServerObj->pThreadObj;
for (int i = 0; i < numOfThreads; ++i) {
+ pThreadObj = pServerObj->pThreadObj[i];
code = pthread_mutex_init(&(pThreadObj->mutex), NULL);
if (code < 0) {
tError("%s failed to init TCP process data mutex(%s)", label, strerror(errno));
@@ -137,7 +146,6 @@ void *taosInitTcpServer(uint32_t ip, uint16_t port, char *label, int numOfThread
}
pThreadObj->threadId = i;
- pThreadObj++;
}
pServerObj->fd = taosOpenTcpServerSocket(pServerObj->ip, pServerObj->port);
@@ -166,6 +174,11 @@ static void taosStopTcpThread(SThreadObj* pThreadObj) {
pThreadObj->stop = true;
eventfd_t fd = -1;
+ if (taosComparePthread(pThreadObj->thread, pthread_self())) {
+ pthread_detach(pthread_self());
+ return;
+ }
+
if (taosCheckPthreadValid(pThreadObj->thread) && pThreadObj->pollFd >= 0) {
// signal the thread to stop, try graceful method first,
// and use pthread_cancel when failed
@@ -183,15 +196,11 @@ static void taosStopTcpThread(SThreadObj* pThreadObj) {
}
}
- if (taosCheckPthreadValid(pThreadObj->thread)) pthread_join(pThreadObj->thread, NULL);
- if (pThreadObj->pollFd >=0) taosCloseSocket(pThreadObj->pollFd);
- if (fd != -1) taosCloseSocket(fd);
-
- while (pThreadObj->pHead) {
- SFdObj *pFdObj = pThreadObj->pHead;
- pThreadObj->pHead = pFdObj->next;
- taosFreeFdObj(pFdObj);
+ if (taosCheckPthreadValid(pThreadObj->thread) && pThreadObj->pollFd >= 0) {
+ pthread_join(pThreadObj->thread, NULL);
}
+
+ if (fd != -1) taosCloseSocket(fd);
}
void taosStopTcpServer(void *handle) {
@@ -199,7 +208,14 @@ void taosStopTcpServer(void *handle) {
if (pServerObj == NULL) return;
if(pServerObj->fd >=0) shutdown(pServerObj->fd, SHUT_RD);
- if (taosCheckPthreadValid(pServerObj->thread)) pthread_join(pServerObj->thread, NULL);
+
+ if (taosCheckPthreadValid(pServerObj->thread)) {
+ if (taosComparePthread(pServerObj->thread, pthread_self())) {
+ pthread_detach(pthread_self());
+ } else {
+ pthread_join(pServerObj->thread, NULL);
+ }
+ }
tDebug("%s TCP server is stopped", pServerObj->label);
}
@@ -210,9 +226,8 @@ void taosCleanUpTcpServer(void *handle) {
if (pServerObj == NULL) return;
for (int i = 0; i < pServerObj->numOfThreads; ++i) {
- pThreadObj = pServerObj->pThreadObj + i;
+ pThreadObj = pServerObj->pThreadObj[i];
taosStopTcpThread(pThreadObj);
- pthread_mutex_destroy(&(pThreadObj->mutex));
}
tDebug("%s TCP server is cleaned up", pServerObj->label);
@@ -249,7 +264,7 @@ static void *taosAcceptTcpConnection(void *arg) {
taosSetSockOpt(connFd, SOL_SOCKET, SO_RCVTIMEO, &to, sizeof(to));
// pick up the thread to handle this connection
- pThreadObj = pServerObj->pThreadObj + threadId;
+ pThreadObj = pServerObj->pThreadObj[threadId];
SFdObj *pFdObj = taosMallocFdObj(pThreadObj, connFd);
if (pFdObj) {
@@ -327,10 +342,8 @@ void taosCleanUpTcpClient(void *chandle) {
SThreadObj *pThreadObj = chandle;
if (pThreadObj == NULL) return;
+ tDebug ("%s TCP client will be cleaned up", pThreadObj->label);
taosStopTcpThread(pThreadObj);
- tDebug ("%s TCP client is cleaned up", pThreadObj->label);
-
- taosTFree(pThreadObj);
}
void *taosOpenTcpClientConnection(void *shandle, void *thandle, uint32_t ip, uint16_t port) {
@@ -365,7 +378,7 @@ void *taosOpenTcpClientConnection(void *shandle, void *thandle, uint32_t ip, uin
void taosCloseTcpConnection(void *chandle) {
SFdObj *pFdObj = chandle;
- if (pFdObj == NULL) return;
+ if (pFdObj == NULL || pFdObj->signature != pFdObj) return;
SThreadObj *pThreadObj = pFdObj->pThreadObj;
tDebug("%s %p TCP connection will be closed, FD:%p", pThreadObj->label, pFdObj->thandle, pFdObj);
@@ -378,7 +391,7 @@ void taosCloseTcpConnection(void *chandle) {
int taosSendTcpData(uint32_t ip, uint16_t port, void *data, int len, void *chandle) {
SFdObj *pFdObj = chandle;
- if (chandle == NULL) return -1;
+ if (pFdObj == NULL || pFdObj->signature != pFdObj) return -1;
return taosWriteMsg(pFdObj->fd, data, len);
}
@@ -425,7 +438,7 @@ static int taosReadTcpData(SFdObj *pFdObj, SRecvInfo *pInfo) {
tError("%s %p TCP malloc(size:%d) fail", pThreadObj->label, pFdObj->thandle, msgLen);
return -1;
} else {
- tDebug("TCP malloc mem: %p", buffer);
+ tTrace("TCP malloc mem: %p", buffer);
}
msg = buffer + tsRpcOverhead;
@@ -503,8 +516,22 @@ static void *taosProcessTcpData(void *param) {
pFdObj->thandle = (*(pThreadObj->processData))(&recvInfo);
if (pFdObj->thandle == NULL) taosFreeFdObj(pFdObj);
}
+
+ if (pThreadObj->stop) break;
+ }
+
+ if (pThreadObj->pollFd >=0) taosCloseSocket(pThreadObj->pollFd);
+
+ while (pThreadObj->pHead) {
+ SFdObj *pFdObj = pThreadObj->pHead;
+ pThreadObj->pHead = pFdObj->next;
+ taosFreeFdObj(pFdObj);
}
+ pthread_mutex_destroy(&(pThreadObj->mutex));
+ tDebug("%s TCP thread exits ...", pThreadObj->label);
+ taosTFree(pThreadObj);
+
return NULL;
}
diff --git a/src/rpc/src/rpcUdp.c b/src/rpc/src/rpcUdp.c
index 4ea47582b9c93fbd483454a50e1bf6aed5237870..6f653046615f162c516b5eebf08995d30c6214d7 100644
--- a/src/rpc/src/rpcUdp.c
+++ b/src/rpc/src/rpcUdp.c
@@ -214,7 +214,7 @@ static void *taosRecvUdpData(void *param) {
tError("%s failed to allocate memory, size:%" PRId64, pConn->label, (int64_t)dataLen);
continue;
} else {
- tDebug("UDP malloc mem: %p", tmsg);
+ tTrace("UDP malloc mem: %p", tmsg);
}
tmsg += tsRpcOverhead; // overhead for SRpcReqContext
diff --git a/src/sync/src/taosTcpPool.c b/src/sync/src/taosTcpPool.c
index eda822b1ec0b66ac984106566e03d5a1131ede8a..6a210a136ffe67b2e1394d26bac4cb5083452c8c 100644
--- a/src/sync/src/taosTcpPool.c
+++ b/src/sync/src/taosTcpPool.c
@@ -219,7 +219,10 @@ static void *taosProcessTcpData(void *param) {
continue;
}
}
+
}
+
+ if (pThread->stop) break;
}
uDebug("%p TCP epoll thread exits", pThread);
@@ -321,5 +324,5 @@ static void taosStopPoolThread(SThreadObj *pThread) {
}
pthread_join(thread, NULL);
- taosClose(fd);
+ if (fd >= 0) taosClose(fd);
}
diff --git a/tests/examples/JDBC/calciteDemo/pom.xml b/tests/examples/JDBC/calciteDemo/pom.xml
new file mode 100644
index 0000000000000000000000000000000000000000..90eea8e2c41a222f2b36967fb759fd250af536cf
--- /dev/null
+++ b/tests/examples/JDBC/calciteDemo/pom.xml
@@ -0,0 +1,53 @@
+
+
+ 4.0.0
+
+ com.taosdata.example.calcite
+ calciteDemo
+ 1.0-SNAPSHOT
+
+
+
+
+ org.slf4j
+ slf4j-simple
+ 1.7.25
+ compile
+
+
+
+ org.apache.calcite
+ calcite-core
+ 1.23.0
+
+
+ org.apache.commons
+ commons-dbcp2
+ 2.7.0
+
+
+ org.apache.calcite.avatica
+ avatica-core
+ 1.17.0
+
+
+
+
+ mysql
+ mysql-connector-java
+ 5.1.47
+
+
+
+
+ com.taosdata.jdbc
+ taos-jdbcdriver
+ 2.0.7
+
+
+
+
+
+
\ No newline at end of file
diff --git a/tests/examples/JDBC/calciteDemo/src/main/java/com/taosdata/example/calcite/CalciteDemo.java b/tests/examples/JDBC/calciteDemo/src/main/java/com/taosdata/example/calcite/CalciteDemo.java
new file mode 100644
index 0000000000000000000000000000000000000000..7e97956b7879c26056b9b0e27cce4786284ff96c
--- /dev/null
+++ b/tests/examples/JDBC/calciteDemo/src/main/java/com/taosdata/example/calcite/CalciteDemo.java
@@ -0,0 +1,67 @@
+package com.taosdata.example.calcite;
+
+import org.apache.calcite.adapter.jdbc.JdbcSchema;
+import org.apache.calcite.jdbc.CalciteConnection;
+import org.apache.calcite.schema.Schema;
+import org.apache.calcite.schema.SchemaPlus;
+import org.apache.calcite.sql.parser.SqlParseException;
+import org.apache.commons.dbcp2.BasicDataSource;
+
+import java.sql.*;
+import java.util.Properties;
+
+public class CalciteDemo {
+
+ private static String url_taos = "jdbc:TAOS://192.168.236.135:6030/test";
+ private static String url_mysql = "jdbc:mysql://master:3306/test?useSSL=false&useUnicode=true&characterEncoding=UTF-8";
+
+ public static void main(String[] args) throws SqlParseException, ClassNotFoundException, SQLException {
+ Class.forName("org.apache.calcite.jdbc.Driver");
+ Properties info = new Properties();
+ info.setProperty("caseSensitive", "false");
+
+ Connection connection = DriverManager.getConnection("jdbc:calcite:", info);
+ CalciteConnection calciteConnection = connection.unwrap(CalciteConnection.class);
+
+ SchemaPlus rootSchema = calciteConnection.getRootSchema();
+
+ //这里hdb是在tdengine中创建的数据库名
+ Schema schema = mysqlTest(rootSchema);
+// Schema schema = tdengineTest(rootSchema);
+
+ //创建新的schema自动映射到原来的hdb数据库
+ rootSchema.add("test", schema);
+
+ Statement stmt = calciteConnection.createStatement();
+ //查询schema test中的表,表名是tdengine中的表
+ ResultSet rs = stmt.executeQuery("select * from test.t");
+ ResultSetMetaData metaData = rs.getMetaData();
+ while (rs.next()) {
+ for (int i = 1; i <= metaData.getColumnCount(); i++) {
+ System.out.println(metaData.getColumnLabel(i) + " : " + rs.getString(i));
+ }
+ }
+ }
+
+
+ private static Schema tdengineTest(SchemaPlus rootSchema) throws ClassNotFoundException {
+ Class.forName("com.taosdata.jdbc.TSDBDriver");
+ BasicDataSource dataSource = new BasicDataSource();
+ dataSource.setUrl(url_taos);
+ dataSource.setUsername("root");
+ dataSource.setPassword("taosdata");
+
+ return JdbcSchema.create(rootSchema, "test", dataSource, "hdb", null);
+ }
+
+ private static Schema mysqlTest(SchemaPlus rootSchema) throws ClassNotFoundException {
+ Class.forName("com.mysql.jdbc.Driver");
+ BasicDataSource dataSource = new BasicDataSource();
+ dataSource.setUrl(url_mysql);
+ dataSource.setUsername("root");
+ dataSource.setPassword("123456");
+
+ //Schema schema = JdbcSchema.create(rootSchema, "test", dataSource, "hdb", null);
+ return JdbcSchema.create(rootSchema, "test", dataSource, "test", null);
+ }
+}
diff --git a/tests/examples/JDBC/calciteDemo/src/main/resources/log4j.properties b/tests/examples/JDBC/calciteDemo/src/main/resources/log4j.properties
new file mode 100644
index 0000000000000000000000000000000000000000..1a77ec520cd3e727ac51acb4b8f647b7cf188d97
--- /dev/null
+++ b/tests/examples/JDBC/calciteDemo/src/main/resources/log4j.properties
@@ -0,0 +1,6 @@
+log4j.rootLogger=info,stdout
+
+#console
+log4j.appender.stdout=org.apache.log4j.ConsoleAppender
+log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
+log4j.appender.stdout.layout.ConversionPattern= [%d{yyyy-MM-dd HH:mm:ss a}]:%p %l%m%n
\ No newline at end of file
diff --git a/tests/pytest/concurrent_inquiry.py b/tests/pytest/concurrent_inquiry.py
new file mode 100644
index 0000000000000000000000000000000000000000..faefc8a1c296c10e8b4fc18c2e72a6b0ff8fda44
--- /dev/null
+++ b/tests/pytest/concurrent_inquiry.py
@@ -0,0 +1,146 @@
+###################################################################
+# Copyright (c) 2016 by TAOS Technologies, Inc.
+# All rights reserved.
+#
+# This file is proprietary and confidential to TAOS Technologies.
+# No part of this file may be reproduced, stored, transmitted,
+# disclosed or used in any form or by any means other than as
+# expressly provided by the written permission from Jianhui Tao
+#
+###################################################################
+
+# -*- coding: utf-8 -*-
+import threading
+import taos
+
+import json
+import time
+import random
+# query sql
+query_sql = [
+# first supertable
+"select count(*) from test.meters where c1 > 50;",
+"select count(*) from test.meters where c2 >= 50 and c2 < 100;",
+"select count(*) from test.meters where c3 != 5;",
+"select count(*) from test.meters where t3 > 2;",
+"select count(*) from test.meters where ts <> '2020-05-13 10:00:00.002';",
+"select count(*) from test.meters where t7 like 'fi%';",
+"select count(*) from test.meters where t7 like '_econd';",
+"select count(*) from test.meters interval(1n) order by ts desc;",
+"select first(*) from test.meters;",
+"select last(*) from test.meters;",
+"select last_row(*) from test.meters;",
+"select twa(c1) from test.t1 where ts > 1500000001000 and ts < 1500000101000" ,
+"select avg(c1) from test.meters;",
+"select bottom(c1, 2) from test.t1;",
+"select diff(c1) from test.t1;",
+"select leastsquares(c1, 1, 1) from test.t1 ;",
+"select max(c1) from test.meters;",
+"select min(c1) from test.meters;",
+"select c1 + c2 * c3 + c1 / c5 + c4 + c2 from test.t1;",
+"select percentile(c1, 50) from test.t1;",
+"select spread(c1) from test.t1 ;",
+"select stddev(c1) from test.t1;",
+"select sum(c1) from test.meters;",
+"select top(c1, 2) from test.meters;"
+"select twa(c6) from test.t1 where ts > 1500000001000 and ts < 1500000101000" ,
+"select avg(c6) from test.meters;",
+"select bottom(c6, 2) from test.t1;",
+"select diff(c6) from test.t1;",
+"select leastsquares(c6, 1, 1) from test.t1 ;",
+"select max(c6) from test.meters;",
+"select min(c6) from test.meters;",
+"select c6 + c2 * c3 + c6 / c5 + c4 + c2 from test.t1;",
+"select percentile(c6, 50) from test.t1;",
+"select spread(c6) from test.t1 ;",
+"select stddev(c6) from test.t1;",
+"select sum(c6) from test.meters;",
+"select top(c6, 2) from test.meters;",
+# second supertable
+"select count(*) from test.meters1 where c1 > 50;",
+"select count(*) from test.meters1 where c2 >= 50 and c2 < 100;",
+"select count(*) from test.meters1 where c3 != 5;",
+"select count(*) from test.meters1 where t3 > 2;",
+"select count(*) from test.meters1 where ts <> '2020-05-13 10:00:00.002';",
+"select count(*) from test.meters1 where t7 like 'fi%';",
+"select count(*) from test.meters1 where t7 like '_econd';",
+"select count(*) from test.meters1 interval(1n) order by ts desc;",
+"select first(*) from test.meters1;",
+"select last(*) from test.meters1;",
+"select last_row(*) from test.meters1;",
+"select twa(c1) from test.m1 where ts > 1500000001000 and ts < 1500000101000" ,
+"select avg(c1) from test.meters1;",
+"select bottom(c1, 2) from test.m1;",
+"select diff(c1) from test.m1;",
+"select leastsquares(c1, 1, 1) from test.m1 ;",
+"select max(c1) from test.meters1;",
+"select min(c1) from test.meters1;",
+"select c1 + c2 * c3 + c1 / c5 + c3 + c2 from test.m1;",
+"select percentile(c1, 50) from test.m1;",
+"select spread(c1) from test.m1 ;",
+"select stddev(c1) from test.m1;",
+"select sum(c1) from test.meters1;",
+"select top(c1, 2) from test.meters1;",
+"select twa(c6) from test.m1 where ts > 1500000001000 and ts < 1500000101000" ,
+"select avg(c6) from test.meters1;",
+"select bottom(c6, 2) from test.m1;",
+"select diff(c6) from test.m1;",
+"select leastsquares(c6, 1, 1) from test.m1 ;",
+"select max(c6) from test.meters1;",
+"select min(c6) from test.meters1;",
+"select c6 + c2 * c3 + c6 / c5 + c3 + c2 from test.m1;",
+"select percentile(c6, 50) from test.m1;",
+"select spread(c6) from test.m1 ;",
+"select stddev(c6) from test.m1;",
+"select sum(c6) from test.meters1;",
+"select top(c6, 2) from test.meters1;"
+]
+
+class ConcurrentInquiry:
+ def initConnection(self):
+ self.numOfTherads = 50
+ self.ts=1500000001000
+
+
+ def query_thread(self,threadID):
+ host = "10.211.55.14"
+ user = "root"
+ password = "taosdata"
+ conn = taos.connect(
+ host,
+ user,
+ password,
+ )
+ cl = conn.cursor()
+
+ print("Thread %d: starting" % threadID)
+
+ while True:
+ ran_query_sql=query_sql
+ random.shuffle(ran_query_sql)
+ for i in ran_query_sql:
+ print("Thread %d : %s"% (threadID,i))
+ try:
+ cl.execute(i)
+ cl.fetchall
+ except Exception as e:
+ print(
+ "Failure thread%d, sql: %s,exception: %s" %
+ (threadID, str(i),str(e)))
+
+
+ print("Thread %d: finishing" % threadID)
+
+
+
+ def run(self):
+
+ threads = []
+ for i in range(50):
+ thread = threading.Thread(target=self.query_thread, args=(i,))
+ threads.append(thread)
+ thread.start()
+
+q = ConcurrentInquiry()
+q.initConnection()
+q.run()
diff --git a/tests/script/general/http/restful_full.sim b/tests/script/general/http/restful_full.sim
index a02140a4199054775c405ec3c6223faa2ef681e4..8d2f1a7c00304c42c91311ae703bcef97aa6ace0 100644
--- a/tests/script/general/http/restful_full.sim
+++ b/tests/script/general/http/restful_full.sim
@@ -119,7 +119,7 @@ endi
system_content curl -H 'Authorization: Taosd /KfeAzX/f9na8qdtNZmtONryp201ma04bEl8LcvLUd7a8qdtNZmtONryp201ma04' -d ' used1' 127.0.0.1:7111/rest/sql
print 17-> $system_content
-if $system_content != @{"status":"error","code":534,"desc":"Syntax errr in SQL"}@ then
+if $system_content != @{"status":"error","code":534,"desc":"Syntax error in SQL"}@ then
return -1
endi
diff --git a/tests/script/unique/mnode/mgmt23.sim b/tests/script/unique/mnode/mgmt23.sim
index 485187286059289f67ab0c82241b049c71f68230..d1820ef8c6a886fdbc55bda6d7b9e79a0ea51e1b 100644
--- a/tests/script/unique/mnode/mgmt23.sim
+++ b/tests/script/unique/mnode/mgmt23.sim
@@ -65,7 +65,7 @@ endi
print ============== step4
sql drop dnode $hostname2
-sleep 16000
+sleep 10000
sql show mnodes
$dnode1Role = $data2_1