Merge branch 'develop' into feature/szhou/schemaless
This commit is contained in:
commit
ae23e50a10
20
.drone.yml
20
.drone.yml
|
@ -15,7 +15,7 @@ steps:
|
|||
- mkdir debug
|
||||
- cd debug
|
||||
- cmake ..
|
||||
- make
|
||||
- make -j4
|
||||
trigger:
|
||||
event:
|
||||
- pull_request
|
||||
|
@ -39,7 +39,7 @@ steps:
|
|||
- mkdir debug
|
||||
- cd debug
|
||||
- cmake .. -DCPUTYPE=aarch64 > /dev/null
|
||||
- make
|
||||
- make -j4
|
||||
trigger:
|
||||
event:
|
||||
- pull_request
|
||||
|
@ -66,7 +66,7 @@ steps:
|
|||
- mkdir debug
|
||||
- cd debug
|
||||
- cmake .. -DCPUTYPE=aarch64 > /dev/null
|
||||
- make
|
||||
- make -j4
|
||||
trigger:
|
||||
event:
|
||||
- pull_request
|
||||
|
@ -91,7 +91,7 @@ steps:
|
|||
- mkdir debug
|
||||
- cd debug
|
||||
- cmake .. -DCPUTYPE=aarch64 > /dev/null
|
||||
- make
|
||||
- make -j4
|
||||
trigger:
|
||||
event:
|
||||
- pull_request
|
||||
|
@ -116,7 +116,7 @@ steps:
|
|||
- mkdir debug
|
||||
- cd debug
|
||||
- cmake .. -DCPUTYPE=aarch64 > /dev/null
|
||||
- make
|
||||
- make -j4
|
||||
trigger:
|
||||
event:
|
||||
- pull_request
|
||||
|
@ -142,7 +142,7 @@ steps:
|
|||
- mkdir debug
|
||||
- cd debug
|
||||
- cmake .. -DCPUTYPE=aarch32 > /dev/null
|
||||
- make
|
||||
- make -j4
|
||||
trigger:
|
||||
event:
|
||||
- pull_request
|
||||
|
@ -168,7 +168,7 @@ steps:
|
|||
- mkdir debug
|
||||
- cd debug
|
||||
- cmake ..
|
||||
- make
|
||||
- make -j4
|
||||
trigger:
|
||||
event:
|
||||
- pull_request
|
||||
|
@ -193,7 +193,7 @@ steps:
|
|||
- mkdir debug
|
||||
- cd debug
|
||||
- cmake ..
|
||||
- make
|
||||
- make -j4
|
||||
trigger:
|
||||
event:
|
||||
- pull_request
|
||||
|
@ -218,7 +218,7 @@ steps:
|
|||
- mkdir debug
|
||||
- cd debug
|
||||
- cmake ..
|
||||
- make
|
||||
- make -j4
|
||||
trigger:
|
||||
event:
|
||||
- pull_request
|
||||
|
@ -241,7 +241,7 @@ steps:
|
|||
- mkdir debug
|
||||
- cd debug
|
||||
- cmake ..
|
||||
- make
|
||||
- make -j4
|
||||
trigger:
|
||||
event:
|
||||
- pull_request
|
||||
|
|
|
@ -4,6 +4,9 @@ properties([pipelineTriggers([githubPush()])])
|
|||
node {
|
||||
git url: 'https://github.com/taosdata/TDengine.git'
|
||||
}
|
||||
|
||||
def skipbuild=0
|
||||
|
||||
def abortPreviousBuilds() {
|
||||
def currentJobName = env.JOB_NAME
|
||||
def currentBuildNumber = env.BUILD_NUMBER.toInteger()
|
||||
|
@ -152,6 +155,7 @@ pipeline {
|
|||
git fetch origin +refs/pull/${CHANGE_ID}/merge
|
||||
git checkout -qf FETCH_HEAD
|
||||
'''
|
||||
|
||||
script{
|
||||
skipbuild='2'
|
||||
skipbuild=sh(script: "git log -2 --pretty=%B | fgrep -ie '[skip ci]' -e '[ci skip]' && echo 1 || echo 2", returnStdout:true)
|
||||
|
@ -220,6 +224,26 @@ pipeline {
|
|||
steps {
|
||||
timeout(time: 55, unit: 'MINUTES'){
|
||||
pre_test()
|
||||
sh '''
|
||||
rm -rf /var/lib/taos/*
|
||||
rm -rf /var/log/taos/*
|
||||
nohup taosd >/dev/null &
|
||||
sleep 10
|
||||
'''
|
||||
sh '''
|
||||
cd ${WKC}/tests/examples/nodejs
|
||||
npm install td2.0-connector > /dev/null 2>&1
|
||||
node nodejsChecker.js host=localhost
|
||||
'''
|
||||
sh '''
|
||||
cd ${WKC}/tests/examples/C#/taosdemo
|
||||
mcs -out:taosdemo *.cs > /dev/null 2>&1
|
||||
echo '' |./taosdemo
|
||||
'''
|
||||
sh '''
|
||||
cd ${WKC}/tests/gotest
|
||||
bash batchtest.sh
|
||||
'''
|
||||
sh '''
|
||||
cd ${WKC}/tests
|
||||
./test-all.sh b1fq
|
||||
|
|
|
@ -180,7 +180,7 @@ IF (TD_WINDOWS)
|
|||
ADD_DEFINITIONS(-D_MBCS -D_CRT_SECURE_NO_DEPRECATE -D_CRT_NONSTDC_NO_DEPRECATE)
|
||||
SET(CMAKE_GENERATOR "NMake Makefiles" CACHE INTERNAL "" FORCE)
|
||||
IF (NOT TD_GODLL)
|
||||
SET(COMMON_FLAGS "/nologo /WX /wd4018 /wd2220 /Oi /Oy- /Gm- /EHsc /MT /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /Gd /errorReport:prompt /analyze-")
|
||||
SET(COMMON_FLAGS "/nologo /WX /wd4018 /wd5999 /Oi /Oy- /Gm- /EHsc /MT /GS /Gy /fp:precise /Zc:wchar_t /Zc:forScope /Gd /errorReport:prompt /analyze-")
|
||||
IF (MSVC AND (MSVC_VERSION GREATER_EQUAL 1900))
|
||||
SET(COMMON_FLAGS "${COMMON_FLAGS} /Wv:18")
|
||||
ENDIF ()
|
||||
|
|
|
@ -34,12 +34,22 @@ ENDIF ()
|
|||
#
|
||||
|
||||
# Set compiler options
|
||||
SET(COMMON_C_FLAGS "${COMMON_FLAGS} -std=gnu99")
|
||||
IF (TD_LINUX)
|
||||
SET(COMMON_C_FLAGS "${COMMON_FLAGS} -std=gnu99")
|
||||
ELSE ()
|
||||
SET(COMMON_C_FLAGS "${COMMON_FLAGS} ")
|
||||
ENDIF ()
|
||||
|
||||
SET(CMAKE_C_FLAGS_DEBUG "${CMAKE_C_FLAGS_DEBUG} ${COMMON_C_FLAGS} ${DEBUG_FLAGS}")
|
||||
SET(CMAKE_C_FLAGS_RELEASE "${CMAKE_C_FLAGS_RELEASE} ${COMMON_C_FLAGS} ${RELEASE_FLAGS}")
|
||||
|
||||
# Set c++ compiler options
|
||||
SET(COMMON_CXX_FLAGS "${COMMON_FLAGS} -std=c++11 -Wno-unused-function")
|
||||
IF (TD_WINDOWS)
|
||||
SET(COMMON_CXX_FLAGS "${COMMON_FLAGS} -std=c++11")
|
||||
ELSE ()
|
||||
SET(COMMON_CXX_FLAGS "${COMMON_FLAGS} -std=c++11 -Wno-unused-function")
|
||||
ENDIF ()
|
||||
|
||||
SET(CMAKE_CXX_FLAGS_DEBUG "${CMAKE_CXX_FLAGS_DEBUG} ${COMMON_CXX_FLAGS} ${DEBUG_FLAGS}")
|
||||
SET(CMAKE_CXX_FLAGS_RELEASE "${CMAKE_CXX_FLAGS_RELEASE} ${COMMON_CXX_FLAGS} ${RELEASE_FLAGS}")
|
||||
|
||||
|
|
|
@ -10,8 +10,8 @@ TDengine的模块之一是时序数据库。但除此之外,为减少研发的
|
|||
* __硬件或云服务成本降至1/5__:由于超强性能,计算资源不到通用大数据方案的1/5;通过列式存储和先进的压缩算法,存储空间不到通用数据库的1/10。
|
||||
* __全栈时序数据处理引擎__:将数据库、消息队列、缓存、流式计算等功能融为一体,应用无需再集成Kafka/Redis/HBase/Spark/HDFS等软件,大幅降低应用开发和维护的复杂度成本。
|
||||
* __强大的分析功能__:无论是十年前还是一秒钟前的数据,指定时间范围即可查询。数据可在时间轴上或多个设备上进行聚合。即席查询可通过Shell, Python, R, MATLAB随时进行。
|
||||
* __与第三方工具无缝连接__:不用一行代码,即可与Telegraf, Grafana, EMQ, HiveMQ, Prometheus, MATLAB, R等集成。后续将支持OPC, Hadoop, Spark等, BI工具也将无缝连接。
|
||||
* __零运维成本、零学习成本__:安装集群简单快捷,无需分库分表,实时备份。类似标准SQL,支持RESTful, 支持Python/Java/C/C++/C#/Go/Node.js, 与MySQL相似,零学习成本。
|
||||
* __与第三方工具无缝连接__:不用一行代码,即可与Telegraf, Grafana, EMQ, HiveMQ, Prometheus, MATLAB, R等集成。后续将支持OPC, Hadoop, Spark等,BI工具也将无缝连接。
|
||||
* __零运维成本、零学习成本__:安装集群简单快捷,无需分库分表,实时备份。类标准SQL,支持RESTful,支持Python/Java/C/C++/C#/Go/Node.js, 与MySQL相似,零学习成本。
|
||||
|
||||
采用TDengine,可将典型的物联网、车联网、工业互联网大数据平台的总拥有成本大幅降低。但需要指出的是,因充分利用了物联网时序数据的特点,它无法用来处理网络爬虫、微博、微信、电商、ERP、CRM等通用型数据。
|
||||
|
||||
|
|
|
@ -22,7 +22,8 @@ TDengine 的安装非常简单,从下载到安装成功仅仅只要几秒钟
|
|||
|
||||
具体的安装过程,请参见 [TDengine 多种安装包的安装和卸载](https://www.taosdata.com/blog/2019/08/09/566.html) 以及 [视频教程](https://www.taosdata.com/blog/2020/11/11/1941.html)。
|
||||
|
||||
## <a class="anchor" id="start"></a>轻松启动
|
||||
<a class="anchor" id="start"></a>
|
||||
## 轻松启动
|
||||
|
||||
安装成功后,用户可使用 `systemctl` 命令来启动 TDengine 的服务进程。
|
||||
|
||||
|
@ -30,7 +31,7 @@ TDengine 的安装非常简单,从下载到安装成功仅仅只要几秒钟
|
|||
$ systemctl start taosd
|
||||
```
|
||||
|
||||
检查服务是否正常工作。
|
||||
检查服务是否正常工作:
|
||||
```bash
|
||||
$ systemctl status taosd
|
||||
```
|
||||
|
@ -40,20 +41,20 @@ $ systemctl status taosd
|
|||
**注意:**
|
||||
|
||||
- systemctl 命令需要 _root_ 权限来运行,如果您非 _root_ 用户,请在命令前添加 sudo 。
|
||||
- 为更好的获得产品反馈,改善产品,TDengine 会采集基本的使用信息,但您可以修改系统配置文件 taos.cfg 里的配置参数 telemetryReporting, 将其设为 0,就可将其关闭。
|
||||
- 为更好的获得产品反馈,改善产品,TDengine 会采集基本的使用信息,但您可以修改系统配置文件 taos.cfg 里的配置参数 telemetryReporting,将其设为 0,就可将其关闭。
|
||||
- TDengine 采用 FQDN (一般就是 hostname )作为节点的 ID,为保证正常运行,需要给运行 taosd 的服务器配置好 hostname,在客户端应用运行的机器配置好 DNS 服务或 hosts 文件,保证 FQDN 能够解析。
|
||||
- `systemctl stop taosd` 指令在执行后并不会马上停止 TDengine 服务,而是会等待系统中必要的落盘工作正常完成。在数据量很大的情况下,这可能会消耗较长时间。
|
||||
|
||||
* TDengine 支持在使用 [`systemd`](https://en.wikipedia.org/wiki/Systemd) 做进程服务管理的 linux 系统上安装,用 `which systemctl` 命令来检测系统中是否存在 `systemd` 包:
|
||||
* TDengine 支持在使用 [`systemd`](https://en.wikipedia.org/wiki/Systemd) 做进程服务管理的 Linux 系统上安装,用 `which systemctl` 命令来检测系统中是否存在 `systemd` 包:
|
||||
|
||||
```bash
|
||||
$ which systemctl
|
||||
```
|
||||
|
||||
如果系统中不支持 systemd,也可以用手动运行 /usr/local/taos/bin/taosd 方式启动 TDengine 服务。
|
||||
如果系统中不支持 `systemd`,也可以用手动运行 /usr/local/taos/bin/taosd 方式启动 TDengine 服务。
|
||||
|
||||
|
||||
## <a class="anchor" id="console"></a>TDengine 命令行程序
|
||||
<a class="anchor" id="console"></a>
|
||||
## TDengine 命令行程序
|
||||
|
||||
执行 TDengine 命令行程序,您只要在 Linux 终端执行 `taos` 即可。
|
||||
|
||||
|
@ -83,14 +84,14 @@ select * from t;
|
|||
Query OK, 2 row(s) in set (0.003128s)
|
||||
```
|
||||
|
||||
除执行 SQL 语句外,系统管理员还可以从 TDengine 终端检查系统运行状态,添加删除用户账号等。
|
||||
除执行 SQL 语句外,系统管理员还可以从 TDengine 终端进行检查系统运行状态、添加删除用户账号等操作。
|
||||
|
||||
### 命令行参数
|
||||
**命令行参数**
|
||||
|
||||
您可通过配置命令行参数来改变 TDengine 终端的行为。以下为常用的几个命令行参数:
|
||||
|
||||
- -c, --config-dir: 指定配置文件目录,默认为 _/etc/taos_
|
||||
- -h, --host: 指定服务的 FQDN 地址(也可以使用 IP),默认为连接本地服务
|
||||
- -c, --config-dir: 指定配置文件目录,默认为 `/etc/taos`
|
||||
- -h, --host: 指定服务的 FQDN 地址或 IP 地址,默认为连接本地服务
|
||||
- -s, --commands: 在不进入终端的情况下运行 TDengine 命令
|
||||
- -u, --user: 连接 TDengine 服务器的用户名,缺省为 root
|
||||
- -p, --password: 连接TDengine服务器的密码,缺省为 taosdata
|
||||
|
@ -99,24 +100,25 @@ Query OK, 2 row(s) in set (0.003128s)
|
|||
示例:
|
||||
|
||||
```bash
|
||||
$ taos -h 192.168.0.1 -s "use db; show tables;"
|
||||
$ taos -h h1.taos.com -s "use db; show tables;"
|
||||
```
|
||||
|
||||
### 运行 SQL 命令脚本
|
||||
**运行 SQL 命令脚本**
|
||||
|
||||
TDengine 终端可以通过 `source` 命令来运行 SQL 命令脚本.
|
||||
TDengine 终端可以通过 `source` 命令来运行 SQL 命令脚本。
|
||||
|
||||
```mysql
|
||||
taos> source <filename>;
|
||||
```
|
||||
|
||||
### Shell 小技巧
|
||||
**Shell 小技巧**
|
||||
|
||||
- 可以使用上下光标键查看历史输入的指令
|
||||
- 修改用户密码,在 shell 中使用 alter user 指令
|
||||
- 修改用户密码:在 shell 中使用 `alter user` 命令,缺省密码为 taosdata
|
||||
- ctrl+c 中止正在进行中的查询
|
||||
- 执行 `RESET QUERY CACHE` 清空本地缓存的表 schema
|
||||
|
||||
- 执行 `RESET QUERY CACHE` 可清除本地缓存的表 schema
|
||||
- 批量执行 SQL 语句。可以将一系列的 shell 命令(以英文 ; 结尾,每个 SQL 语句为一行)按行存放在文件里,在 shell 里执行命令 `source <file-name>` 自动执行该文件里所有的 SQL 语句
|
||||
- 输入 q 回车,退出 taos shell
|
||||
|
||||
## <a class="anchor" id="demo"></a>TDengine 极速体验
|
||||
|
||||
|
@ -164,14 +166,12 @@ taos> select avg(current), max(voltage), min(phase) from test.d10 interval(10s);
|
|||
|
||||
**Note:** taosdemo 命令本身带有很多选项,配置表的数目、记录条数等等,请执行 `taosdemo --help` 详细列出。您可以设置不同参数进行体验。
|
||||
|
||||
|
||||
## 客户端和报警模块
|
||||
|
||||
如果客户端和服务端运行在不同的电脑上,可以单独安装客户端。Linux 和 Windows 安装包可以在 [这里](https://www.taosdata.com/cn/getting-started/#客户端) 下载。
|
||||
|
||||
报警模块的 Linux 和 Windows 安装包请在 [所有下载链接](https://www.taosdata.com/cn/all-downloads/) 页面搜索“TDengine Alert Linux”章节或“TDengine Alert Windows”章节进行下载。使用方法请参考 [报警模块的使用方法](https://github.com/taosdata/TDengine/blob/master/alert/README_cn.md)。
|
||||
|
||||
|
||||
## <a class="anchor" id="platforms"></a>支持平台列表
|
||||
|
||||
### TDengine 服务器支持的平台列表
|
||||
|
@ -191,8 +191,6 @@ taos> select avg(current), max(voltage), min(phase) from test.d10 interval(10s);
|
|||
|
||||
注: ● 表示经过官方测试验证, ○ 表示非官方测试验证。
|
||||
|
||||
|
||||
|
||||
### TDengine 客户端和连接器支持的平台列表
|
||||
|
||||
目前 TDengine 的连接器可支持的平台广泛,目前包括:X64/X86/ARM64/ARM32/MIPS/Alpha 等硬件平台,以及 Linux/Win64/Win32 等开发环境。
|
||||
|
|
|
@ -6,14 +6,15 @@
|
|||
|
||||
在典型的物联网、车联网、运维监测场景中,往往有多种不同类型的数据采集设备,采集一个到多个不同的物理量。而同一种采集设备类型,往往又有多个具体的采集设备分布在不同的地点。大数据处理系统就是要将各种采集的数据汇总,然后进行计算和分析。对于同一类设备,其采集的数据都是很规则的。以智能电表为例,假设每个智能电表采集电流、电压、相位三个量,其采集的数据类似如下的表格:
|
||||
|
||||
<figure><table>
|
||||
<a class="anchor" id="model_table1"></a>
|
||||
|
||||
<table>
|
||||
<thead><tr>
|
||||
<th style="text-align:center;">设备ID</th>
|
||||
<th style="text-align:center;">时间戳</th>
|
||||
<th style="text-align:center;" colspan="3">采集量</th>
|
||||
<th style="text-align:center;" colspan="2">标签</th>
|
||||
</tr>
|
||||
|
||||
<tr>
|
||||
<th style="text-align:center;">Device ID</th>
|
||||
<th style="text-align:center;">Time Stamp</th>
|
||||
|
@ -98,11 +99,11 @@
|
|||
<td style="text-align:center;">2</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table></figure>
|
||||
</table>
|
||||
|
||||
<center> 表1:智能电表数据示例</center>
|
||||
|
||||
每一条记录都有设备ID,时间戳,采集的物理量(如上图中的电流、电压、相位),还有与每个设备相关的静态标签(如上述表一中的位置Location和分组groupId)。每个设备是受外界的触发,或按照设定的周期采集数据。采集的数据点是时序的,是一个数据流。
|
||||
每一条记录都有设备ID,时间戳,采集的物理量(如上图中的电流、电压、相位),还有与每个设备相关的静态标签(如上述表1中的位置Location和分组groupId)。每个设备是受外界的触发,或按照设定的周期采集数据。采集的数据点是时序的,是一个数据流。
|
||||
|
||||
### 数据特征
|
||||
|
||||
|
@ -141,7 +142,7 @@ TDengine 建议用数据采集点的名字(如上表中的D1001)来做表名。
|
|||
|
||||
由于一个数据采集点一张表,导致表的数量巨增,难以管理,而且应用经常需要做采集点之间的聚合操作,聚合的操作也变得复杂起来。为解决这个问题,TDengine引入超级表(Super Table,简称为STable)的概念。
|
||||
|
||||
超级表是指某一特定类型的数据采集点的集合。同一类型的数据采集点,其表的结构是完全一样的,但每个表(数据采集点)的静态属性(标签)是不一样的。描述一个超级表(某一特定类型的数据采集点的结合),除需要定义采集量的表结构之外,还需要定义其标签的schema,标签的数据类型可以是整数、浮点数、字符串,标签可以有多个,可以事后增加、删除或修改。 如果整个系统有N个不同类型的数据采集点,就需要建立N个超级表。
|
||||
超级表是指某一特定类型的数据采集点的集合。同一类型的数据采集点,其表的结构是完全一样的,但每个表(数据采集点)的静态属性(标签)是不一样的。描述一个超级表(某一特定类型的数据采集点的集合),除需要定义采集量的表结构之外,还需要定义其标签的schema,标签的数据类型可以是整数、浮点数、字符串,标签可以有多个,可以事后增加、删除或修改。如果整个系统有N个不同类型的数据采集点,就需要建立N个超级表。
|
||||
|
||||
在TDengine的设计里,**表用来代表一个具体的数据采集点,超级表用来代表一组相同类型的数据采集点集合**。当为某个具体数据采集点创建表时,用户使用超级表的定义做模板,同时指定该具体采集点(表)的标签值。与传统的关系型数据库相比,表(一个数据采集点)是带有静态标签的,而且这些标签可以事后增加、删除、修改。**一张超级表包含有多张表,这些表具有相同的时序数据schema,但带有不同的标签值**。
|
||||
|
||||
|
@ -160,39 +161,51 @@ TDengine 分布式架构的逻辑结构图如下:
|
|||
|
||||
一个完整的 TDengine 系统是运行在一到多个物理节点上的,逻辑上,它包含数据节点(dnode)、TDengine应用驱动(taosc)以及应用(app)。系统中存在一到多个数据节点,这些数据节点组成一个集群(cluster)。应用通过taosc的API与TDengine集群进行互动。下面对每个逻辑单元进行简要介绍。
|
||||
|
||||
**物理节点(pnode):** pnode是一独立运行、拥有自己的计算、存储和网络能力的计算机,可以是安装有OS的物理机、虚拟机或Docker容器。物理节点由其配置的 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)的组合。通过配置不同的端口,一个物理节点(一台物理机、虚拟机或容器)可以运行多个实例,或有多个数据节点。
|
||||
**数据节点(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 集群中可配置多个(开源版最多不超过3个) mnode,它们自动构建成为一个虚拟管理节点组(图中M0, M1, M2)。mnode 间采用 master/slave 的机制进行管理,而且采取强一致方式进行数据同步, 任何数据更新操作只能在 Master 上进行。mnode 集群的创建由系统自动完成,无需人工干预。每个dnode上至多有一个mnode,由所属的数据节点的EP来唯一标识。每个dnode通过内部消息交互自动获取整个集群中所有 mnode 所在的 dnode 的EP。
|
||||
**管理节点(mnode):** 一个虚拟的逻辑单元,负责所有数据节点运行状态的监控和维护,以及节点之间的负载均衡(图中M)。同时,管理节点也负责元数据(包括用户、数据库、表、静态标签等)的存储和管理,因此也称为 Meta Node。TDengine 集群中可配置多个(开源版最多不超过3个) 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也不会被收回重复利用。
|
||||
**虚拟节点组(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),负责处理应用与集群的接口交互,提供C/C++语言原生接口,内嵌于JDBC、C#、Python、Go、Node.js语言连接库里。应用都是通过taosc而不是直接连接集群中的数据节点与整个集群进行交互的。这个模块负责获取并缓存元数据;将插入、查询等请求转发到正确的数据节点;在把结果返回给应用时,还需要负责最后一级的聚合、排序、过滤等操作。对于JDBC, C/C++/C#/Python/Go/Node.js接口而言,这个模块是在应用所处的物理节点上运行。同时,为支持全分布式的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方式进行数据传输。
|
||||
|
||||
**FQDN配置**:一个数据节点有一个或多个FQDN,可以在系统配置文件taos.cfg通过参数“fqdn"进行指定,如果没有指定,系统将自动获取计算机的hostname作为其FQDN。如果节点没有配置FQDN,可以直接将该节点的配置参数fqdn设置为它的IP地址。但不建议使用IP,因为IP地址可变,一旦变化,将让集群无法正常工作。一个数据节点的EP(End Point)由FQDN + Port组成。采用FQDN,需要保证DNS服务正常工作,或者在节点以及应用所在的节点配置好hosts文件。另外,这个参数值的长度需要控制在 96 个字符以内。
|
||||
**FQDN配置:**一个数据节点有一个或多个FQDN,可以在系统配置文件taos.cfg通过参数"fqdn"进行指定,如果没有指定,系统将自动获取计算机的hostname作为其FQDN。如果节点没有配置FQDN,可以直接将该节点的配置参数fqdn设置为它的IP地址。但不建议使用IP,因为IP地址可变,一旦变化,将让集群无法正常工作。一个数据节点的EP(End Point)由FQDN + Port组成。采用FQDN,需要保证DNS服务正常工作,或者在节点以及应用所在的节点配置好hosts文件。另外,这个参数值的长度需要控制在 96 个字符以内。
|
||||
|
||||
**端口配置:**一个数据节点对外的端口由TDengine的系统配置参数serverPort决定,对集群内部通讯的端口是serverPort+5。集群内数据节点之间的数据复制操作还占有一个TCP端口,是serverPort+10. 为支持多线程高效的处理UDP数据,每个对内和对外的UDP连接,都需要占用5个连续的端口。因此一个数据节点总的端口范围为serverPort到serverPort + 10,总共11个TCP/UDP端口。(另外还可能有 RESTful、Arbitrator 所使用的端口,那样的话就一共是 13 个。)使用时,需要确保防火墙将这些端口打开,以备使用。每个数据节点可以配置不同的serverPort。(详细的端口情况请参见 [TDengine 2.0 端口说明](https://www.taosdata.com/cn/documentation/faq#port))
|
||||
**端口配置:**一个数据节点对外的端口由TDengine的系统配置参数serverPort决定,对集群内部通讯的端口是serverPort+5。为支持多线程高效的处理UDP数据,每个对内和对外的UDP连接,都需要占用5个连续的端口。
|
||||
|
||||
**集群对外连接:** TDengine集群可以容纳单个、多个甚至几千个数据节点。应用只需要向集群中任何一个数据节点发起连接即可,连接需要提供的网络参数是一数据节点的End Point(FQDN加配置的端口号)。通过命令行CLI启动应用taos时,可以通过选项-h来指定数据节点的FQDN, -P来指定其配置的端口号,如果端口不配置,将采用TDengine的系统配置参数serverPort。
|
||||
- 集群内数据节点之间的数据复制操作占用一个TCP端口,是serverPort+10。
|
||||
- 集群数据节点对外提供RESTful服务占用一个TCP端口,是serverPort+11。
|
||||
- 集群内数据节点与Arbitrator节点之间通讯占用一个TCP端口,是serverPort+12。
|
||||
|
||||
**集群内部通讯**: 各个数据节点之间通过TCP/UDP进行连接。一个数据节点启动时,将获取mnode所在的dnode的EP信息,然后与系统中的mnode建立起连接,交换信息。获取mnode的EP信息有三步,1:检查mnodeEpSet文件是否存在,如果不存在或不能正常打开获得mnode EP信息,进入第二步;2:检查系统配置文件taos.cfg, 获取节点配置参数firstEp, secondEp,(这两个参数指定的节点可以是不带mnode的普通节点,这样的话,节点被连接时会尝试重定向到mnode节点)如果不存在或者taos.cfg里没有这两个配置参数,或无效,进入第三步;3:将自己的EP设为mnode EP, 并独立运行起来。获取mnode EP列表后,数据节点发起连接,如果连接成功,则成功加入进工作的集群,如果不成功,则尝试mnode EP列表中的下一个。如果都尝试了,但连接都仍然失败,则休眠几秒后,再进行尝试。
|
||||
因此一个数据节点总的端口范围为serverPort到serverPort+12,总共13个TCP/UDP端口。使用时,需要确保防火墙将这些端口打开。每个数据节点可以配置不同的serverPort。(详细的端口情况请参见 [TDengine 2.0 端口说明](https://www.taosdata.com/cn/documentation/faq#port))
|
||||
|
||||
**MNODE的选择:** TDengine逻辑上有管理节点,但没有单独的执行代码,服务器侧只有一套执行代码taosd。那么哪个数据节点会是管理节点呢?这是系统自动决定的,无需任何人工干预。原则如下:一个数据节点启动时,会检查自己的End Point, 并与获取的mnode EP List进行比对,如果在其中,该数据节点认为自己应该启动mnode模块,成为mnode。如果自己的EP不在mnode EP List里,则不启动mnode模块。在系统的运行过程中,由于负载均衡、宕机等原因,mnode有可能迁移至新的dnode,但一切都是透明的,无需人工干预,配置参数的修改,是mnode自己根据资源做出的决定。
|
||||
**集群对外连接:**TDengine集群可以容纳单个、多个甚至几千个数据节点。应用只需要向集群中任何一个数据节点发起连接即可,连接需要提供的网络参数是一数据节点的End Point(FQDN加配置的端口号)。通过命令行CLI启动应用taos时,可以通过选项-h来指定数据节点的FQDN, -P来指定其配置的端口号,如果端口不配置,将采用TDengine的系统配置参数serverPort。
|
||||
|
||||
**新数据节点的加入**:系统有了一个数据节点后,就已经成为一个工作的系统。添加新的节点进集群时,有两个步骤,第一步:使用TDengine CLI连接到现有工作的数据节点,然后用命令”create dnode"将新的数据节点的End Point添加进去; 第二步:在新的数据节点的系统配置参数文件taos.cfg里,将firstEp, secondEp参数设置为现有集群中任意两个数据节点的EP即可。具体添加的详细步骤请见详细的用户手册。这样就把集群一步一步的建立起来。
|
||||
**集群内部通讯:**各个数据节点之间通过TCP/UDP进行连接。一个数据节点启动时,将获取mnode所在的dnode的EP信息,然后与系统中的mnode建立起连接,交换信息。获取mnode的EP信息有三步:
|
||||
|
||||
**重定向**:无论是dnode还是taosc,最先都是要发起与mnode的连接,但mnode是系统自动创建并维护的,因此对于用户来说,并不知道哪个dnode在运行mnode。TDengine只要求向系统中任何一个工作的dnode发起连接即可。因为任何一个正在运行的dnode,都维护有目前运行的mnode EP List。当收到一个来自新启动的dnode或taosc的连接请求,如果自己不是mnode,则将mnode EP List回复给对方,taosc或新启动的dnode收到这个list, 就重新尝试建立连接。当mnode EP List发生改变,通过节点之间的消息交互,各个数据节点就很快获取最新列表,并通知taosc。
|
||||
1. 检查mnodeEpSet.json文件是否存在,如果不存在或不能正常打开获得mnode EP信息,进入第二步;
|
||||
2. 检查系统配置文件taos.cfg,获取节点配置参数firstEp、secondEp(这两个参数指定的节点可以是不带mnode的普通节点,这样的话,节点被连接时会尝试重定向到mnode节点),如果不存在或者taos.cfg里没有这两个配置参数,或无效,进入第三步;
|
||||
3. 将自己的EP设为mnode EP,并独立运行起来。
|
||||
|
||||
获取mnode EP列表后,数据节点发起连接,如果连接成功,则成功加入进工作的集群,如果不成功,则尝试mnode EP列表中的下一个。如果都尝试了,但连接都仍然失败,则休眠几秒后,再进行尝试。
|
||||
|
||||
**MNODE的选择:**TDengine逻辑上有管理节点,但没有单独的执行代码,服务器侧只有一套执行代码taosd。那么哪个数据节点会是管理节点呢?这是系统自动决定的,无需任何人工干预。原则如下:一个数据节点启动时,会检查自己的End Point, 并与获取的mnode EP List进行比对,如果在其中,该数据节点认为自己应该启动mnode模块,成为mnode。如果自己的EP不在mnode EP List里,则不启动mnode模块。在系统的运行过程中,由于负载均衡、宕机等原因,mnode有可能迁移至新的dnode,但一切都是透明的,无需人工干预,配置参数的修改,是mnode自己根据资源做出的决定。
|
||||
|
||||
**新数据节点的加入:**系统有了一个数据节点后,就已经成为一个工作的系统。添加新的节点进集群时,有两个步骤,第一步:使用TDengine CLI连接到现有工作的数据节点,然后用命令”create dnode"将新的数据节点的End Point添加进去; 第二步:在新的数据节点的系统配置参数文件taos.cfg里,将firstEp, secondEp参数设置为现有集群中任意两个数据节点的EP即可。具体添加的详细步骤请见详细的用户手册。这样就把集群一步一步的建立起来。
|
||||
|
||||
**重定向:**无论是dnode还是taosc,最先都是要发起与mnode的连接,但mnode是系统自动创建并维护的,因此对于用户来说,并不知道哪个dnode在运行mnode。TDengine只要求向系统中任何一个工作的dnode发起连接即可。因为任何一个正在运行的dnode,都维护有目前运行的mnode EP List。当收到一个来自新启动的dnode或taosc的连接请求,如果自己不是mnode,则将mnode EP List回复给对方,taosc或新启动的dnode收到这个list, 就重新尝试建立连接。当mnode EP List发生改变,通过节点之间的消息交互,各个数据节点就很快获取最新列表,并通知taosc。
|
||||
|
||||
### 一个典型的消息流程
|
||||
|
||||
为解释vnode, mnode, taosc和应用之间的关系以及各自扮演的角色,下面对写入数据这个典型操作的流程进行剖析。
|
||||
为解释vnode、mnode、taosc和应用之间的关系以及各自扮演的角色,下面对写入数据这个典型操作的流程进行剖析。
|
||||
|
||||

|
||||
<center> 图 2 TDengine典型的操作流程 </center>
|
||||
|
@ -249,64 +262,62 @@ TDengine除vnode分片之外,还对时序数据按照时间段进行分区。
|
|||
|
||||
每个dnode都定时向 mnode(虚拟管理节点)报告其状态(包括硬盘空间、内存大小、CPU、网络、虚拟节点个数等),因此mnode了解整个集群的状态。基于整体状态,当mnode发现某个dnode负载过重,它会将dnode上的一个或多个vnode挪到其他dnode。在挪动过程中,对外服务继续进行,数据插入、查询和计算操作都不受影响。
|
||||
|
||||
如果mnode一段时间没有收到dnode的状态报告,mnode会认为这个dnode已经离线。如果离线时间超过一定时长(时长由配置参数offlineThreshold决定),该dnode将被mnode强制剔除出集群。该dnode上的vnodes如果副本数大于一,系统将自动在其他dnode上创建新的副本,以保证数据的副本数。如果该dnode上还有mnode, 而且mnode的副本数大于一,系统也将自动在其他dnode上创建新的mnode, 以保证mnode的副本数。
|
||||
如果mnode一段时间没有收到dnode的状态报告,mnode会认为这个dnode已经离线。如果离线时间超过一定时长(时长由配置参数offlineThreshold决定),该dnode将被mnode强制剔除出集群。该dnode上的vnodes如果副本数大于1,系统将自动在其他dnode上创建新的副本,以保证数据的副本数。如果该dnode上还有mnode, 而且mnode的副本数大于1,系统也将自动在其他dnode上创建新的mnode, 以保证mnode的副本数。
|
||||
|
||||
当新的数据节点被添加进集群,因为新的计算和存储被添加进来,系统也将自动启动负载均衡流程。
|
||||
|
||||
负载均衡过程无需任何人工干预,应用也无需重启,将自动连接新的节点,完全透明。
|
||||
|
||||
**提示:负载均衡由参数balance控制,决定开启/关闭自动负载均衡。**
|
||||
|
||||
## <a class="anchor" id="replication"></a>数据写入与复制流程
|
||||
|
||||
如果一个数据库有N个副本,那一个虚拟节点组就有N个虚拟节点,但是只有一个是Master,其他都是slave。当应用将新的记录写入系统时,只有Master vnode能接受写的请求。如果slave vnode收到写的请求,系统将通知taosc需要重新定向。
|
||||
如果一个数据库有N个副本,那一个虚拟节点组就有N个虚拟节点,但是只有一个是master,其他都是slave。当应用将新的记录写入系统时,只有master vnode能接受写的请求。如果slave vnode收到写的请求,系统将通知taosc需要重新定向。
|
||||
|
||||
### Master vnode写入流程
|
||||
### Master Vnode写入流程
|
||||
|
||||
Master Vnode遵循下面的写入流程:
|
||||
|
||||

|
||||
<center> 图 3 TDengine Master写入流程 </center>
|
||||
|
||||
1. Master vnode收到应用的数据插入请求,验证OK,进入下一步;
|
||||
1. master vnode收到应用的数据插入请求,验证OK,进入下一步;
|
||||
2. 如果系统配置参数walLevel大于0,vnode将把该请求的原始数据包写入数据库日志文件WAL。如果walLevel设置为2,而且fsync设置为0,TDengine还将WAL数据立即落盘,以保证即使宕机,也能从数据库日志文件中恢复数据,避免数据的丢失;
|
||||
3. 如果有多个副本,vnode将把数据包转发给同一虚拟节点组内slave vnodes, 该转发包带有数据的版本号(version);
|
||||
3. 如果有多个副本,vnode将把数据包转发给同一虚拟节点组内的slave vnodes, 该转发包带有数据的版本号(version);
|
||||
4. 写入内存,并将记录加入到skip list;
|
||||
5. Master vnode返回确认信息给应用,表示写入成功。
|
||||
5. master vnode返回确认信息给应用,表示写入成功。
|
||||
6. 如果第2,3,4步中任何一步失败,将直接返回错误给应用。
|
||||
|
||||
### Slave vnode写入流程
|
||||
### Slave Vnode写入流程
|
||||
|
||||
对于slave vnode, 写入流程是:
|
||||
对于slave vnode,写入流程是:
|
||||
|
||||

|
||||
<center> 图 4 TDengine Slave写入流程 </center>
|
||||
|
||||
1. Slave vnode收到Master vnode转发了的数据插入请求。
|
||||
2. 如果系统配置参数walLevel大于0,vnode将把该请求的原始数据包写入数据库日志文件WAL。如果walLevel设置为2,而且fsync设置为0,TDengine还将WAL数据立即落盘,以保证即使宕机,也能从数据库日志文件中恢复数据,避免数据的丢失;
|
||||
1. slave vnode收到Master vnode转发了的数据插入请求。检查last version是否与master一致,如果一致,进入下一步。如果不一致,需要进入同步状态。
|
||||
2. 如果系统配置参数walLevel大于0,vnode将把该请求的原始数据包写入数据库日志文件WAL。如果walLevel设置为2,而且fsync设置为0,TDengine还将WAL数据立即落盘,以保证即使宕机,也能从数据库日志文件中恢复数据,避免数据的丢失。
|
||||
3. 写入内存,更新内存中的skip list。
|
||||
|
||||
与Master vnode相比,slave vnode不存在转发环节,也不存在回复确认环节,少了两步。但写内存与WAL是完全一样的。
|
||||
与master vnode相比,slave vnode不存在转发环节,也不存在回复确认环节,少了两步。但写内存与WAL是完全一样的。
|
||||
|
||||
### 异地容灾、IDC迁移
|
||||
|
||||
从上述Master和Slave流程可以看出,TDengine采用的是异步复制的方式进行数据同步。这种方式能够大幅提高写入性能,网络延时对写入速度不会有大的影响。通过配置每个物理节点的IDC和机架号,可以保证对于一个虚拟节点组,虚拟节点由来自不同IDC、不同机架的物理节点组成,从而实现异地容灾。因此TDengine原生支持异地容灾,无需再使用其他工具。
|
||||
从上述master和slave流程可以看出,TDengine采用的是异步复制的方式进行数据同步。这种方式能够大幅提高写入性能,网络延时对写入速度不会有大的影响。通过配置每个物理节点的IDC和机架号,可以保证对于一个虚拟节点组,虚拟节点由来自不同IDC、不同机架的物理节点组成,从而实现异地容灾。因此TDengine原生支持异地容灾,无需再使用其他工具。
|
||||
|
||||
另外一方面,TDengine支持动态修改副本数,一旦副本数增加,新加入的虚拟节点将立即进入数据同步流程,同步结束后,新加入的虚拟节点即可提供服务。而在同步过程中,master以及其他已经同步的虚拟节点都可以对外提供服务。利用这一特性,TDengine可以实现无服务中断的IDC机房迁移。只需要将新IDC的物理节点加入现有集群,等数据同步完成后,再将老的IDC的物理节点从集群中剔除即可。
|
||||
另一方面,TDengine支持动态修改副本数,一旦副本数增加,新加入的虚拟节点将立即进入数据同步流程,同步结束后,新加入的虚拟节点即可提供服务。而在同步过程中,master以及其他已经同步的虚拟节点都可以对外提供服务。利用这一特性,TDengine可以实现无服务中断的IDC机房迁移。只需要将新IDC的物理节点加入现有集群,等数据同步完成后,再将老的IDC的物理节点从集群中剔除即可。
|
||||
|
||||
但是,这种异步复制的方式,存在极小的时间窗口,丢失写入的数据。具体场景如下:
|
||||
|
||||
1. Master vnode完成了它的5步操作,已经给APP确认写入成功,然后宕机;
|
||||
2. Slave vnode收到写入请求后,在第2步写入日志之前,处理失败
|
||||
3. Slave vnode将成为新的master, 从而丢失了一条记录
|
||||
1. master vnode完成了它的5步操作,已经给APP确认写入成功,然后宕机
|
||||
2. slave vnode收到写入请求后,在第2步写入日志之前,处理失败
|
||||
3. slave vnode将成为新的master,从而丢失了一条记录
|
||||
|
||||
理论上,只要是异步复制,就无法保证100%不丢失。但是这个窗口极小,mater与slave要同时发生故障,而且发生在刚给应用确认写入成功之后。
|
||||
|
||||
注:异地容灾、IDC无中断迁移,仅仅企业版支持。
|
||||
**提示:该功能暂未提供**
|
||||
理论上,只要是异步复制,就无法保证100%不丢失。但是这个窗口极小,master与slave要同时发生故障,而且发生在刚给应用确认写入成功之后。
|
||||
|
||||
### 主从选择
|
||||
|
||||
Vnode会保持一个数据版本号(Version),对内存数据进行持久化存储时,对该版本号也进行持久化存储。每个数据更新操作,无论是采集的时序数据还是元数据,这个版本号将增一。
|
||||
Vnode会保持一个数据版本号(version),对内存数据进行持久化存储时,对该版本号也进行持久化存储。每个数据更新操作,无论是采集的时序数据还是元数据,这个版本号将增加1。
|
||||
|
||||
一个vnode启动时,角色(master、slave) 是不定的,数据是处于未同步状态,它需要与虚拟节点组内其他节点建立TCP连接,并互相交换status,其中包括version和自己的角色。通过status的交换,系统进入选主流程,规则如下:
|
||||
|
||||
|
@ -319,7 +330,7 @@ Vnode会保持一个数据版本号(Version),对内存数据进行持久化存
|
|||
|
||||
### 同步复制
|
||||
|
||||
对于数据一致性要求更高的场景,异步数据复制无法满足要求,因为有极小的概率丢失数据,因此TDengine提供同步复制的机制供用户选择。在创建数据库时,除指定副本数replica之外,用户还需要指定新的参数quorum。如果quorum大于一,它表示每次Master转发给副本时,需要等待quorum-1个回复确认,才能通知应用,数据在slave已经写入成功。如果在一定的时间内,得不到quorum-1个回复确认,master vnode将返回错误给应用。
|
||||
对于数据一致性要求更高的场景,异步数据复制无法满足要求,因为有极小的概率丢失数据,因此TDengine提供同步复制的机制供用户选择。在创建数据库时,除指定副本数replica之外,用户还需要指定新的参数quorum。如果quorum大于1,它表示每次master转发给副本时,需要等待quorum-1个回复确认,才能通知应用,数据在slave已经写入成功。如果在一定的时间内,得不到quorum-1个回复确认,master vnode将返回错误给应用。
|
||||
|
||||
采用同步复制,系统的性能会有所下降,而且latency会增加。因为元数据要强一致,mnode之间的数据同步缺省就是采用的同步复制。
|
||||
|
||||
|
@ -329,19 +340,19 @@ Vnode会保持一个数据版本号(Version),对内存数据进行持久化存
|
|||
|
||||
TDengine采用时间驱动缓存管理策略(First-In-First-Out,FIFO),又称为写驱动的缓存管理机制。这种策略有别于读驱动的数据缓存模式(Least-Recent-Used,LRU),直接将最近写入的数据保存在系统的缓存中。当缓存达到临界值的时候,将最早的数据批量写入磁盘。一般意义上来说,对于物联网数据的使用,用户最为关心的是刚产生的数据,即当前状态。TDengine充分利用这一特性,将最近到达的(当前状态)数据保存在缓存中。
|
||||
|
||||
TDengine通过查询函数向用户提供毫秒级的数据获取能力。直接将最近到达的数据保存在缓存中,可以更加快速地响应用户针对最近一条或一批数据的查询分析,整体上提供更快的数据库查询响应能力。从这个意义上来说,**可通过设置合适的配置参数将TDengine作为数据缓存来使用,而不需要再部署Redis或其他额外的缓存系统**,可有效地简化系统架构,降低运维的成本。需要注意的是,TDengine重启以后系统的缓存将被清空,之前缓存的数据均会被批量写入磁盘,缓存的数据将不会像专门的Key-value缓存系统再将之前缓存的数据重新加载到缓存中。
|
||||
TDengine通过查询函数向用户提供毫秒级的数据获取能力。直接将最近到达的数据保存在缓存中,可以更加快速地响应用户针对最近一条或一批数据的查询分析,整体上提供更快的数据库查询响应能力。从这个意义上来说,**可通过设置合适的配置参数将TDengine作为数据缓存来使用,而不需要再部署Redis或其他额外的缓存系统**,可有效地简化系统架构,降低运维的成本。需要注意的是,TDengine重启以后系统的缓存将被清空,之前缓存的数据均会被批量写入磁盘,缓存的数据将不会像专门的key-value缓存系统再将之前缓存的数据重新加载到缓存中。
|
||||
|
||||
每个vnode有自己独立的内存,而且由多个固定大小的内存块组成,不同vnode之间完全隔离。数据写入时,类似于日志的写法,数据被顺序追加写入内存,但每个vnode维护有自己的skip list,便于迅速查找。当三分之一以上的内存块写满时,启动落盘操作,而且后续写的操作在新的内存块进行。这样,一个vnode里有三分之一内存块是保留有最近的数据的,以达到缓存、快速查找的目的。一个vnode的内存块的个数由配置参数blocks决定,内存块的大小由配置参数cache决定。
|
||||
|
||||
### 持久化存储
|
||||
|
||||
TDengine采用数据驱动的方式让缓存中的数据写入硬盘进行持久化存储。当vnode中缓存的数据达到一定规模时,为了不阻塞后续数据的写入,TDengine也会拉起落盘线程将缓存的数据写入持久化存储。TDengine在数据落盘时会打开新的数据库日志文件,在落盘成功后则会删除老的数据库日志文件,避免日志文件无限制的增长。
|
||||
TDengine采用数据驱动的方式让缓存中的数据写入硬盘进行持久化存储。当vnode中缓存的数据达到一定规模时,为了不阻塞后续数据的写入,TDengine也会拉起落盘线程将缓存的数据写入持久化存储。TDengine在数据落盘时会打开新的数据库日志文件,在落盘成功后则会删除老的数据库日志文件,避免日志文件无限制地增长。
|
||||
|
||||
为充分利用时序数据特点,TDengine将一个vnode保存在持久化存储的数据切分成多个文件,每个文件只保存固定天数的数据,这个天数由系统配置参数days决定。切分成多个文件后,给定查询的起止日期,无需任何索引,就可以立即定位需要打开哪些数据文件,大大加快读取速度。
|
||||
|
||||
对于采集的数据,一般有保留时长,这个时长由系统配置参数keep决定。超过这个设置天数的数据文件,将被系统自动删除,释放存储空间。
|
||||
|
||||
给定days与keep两个参数,一个典型工作状态的vnode中总的数据文件数为:`向上取整(keep/days)+1`个。总的数据文件个数不宜过大,也不宜过小。10到100以内合适。基于这个原则,可以设置合理的days。 目前的版本,参数keep可以修改,但对于参数days,一但设置后,不可修改。
|
||||
给定days与keep两个参数,一个典型工作状态的vnode中总的数据文件数为:`向上取整(keep/days)+1`个。总的数据文件个数不宜过大,也不宜过小。10到100以内合适。基于这个原则,可以设置合理的days。目前的版本,参数keep可以修改,但对于参数days,一旦设置后,不可修改。
|
||||
|
||||
在每个数据文件里,一张表的数据是一块一块存储的。一张表可以有一到多个数据文件块。在一个文件块里,数据是列式存储的,占用的是一片连续的存储空间,这样大大提高读取速度。文件块的大小由系统参数maxRows(每块最大记录条数)决定,缺省值为4096。这个值不宜过大,也不宜过小。过大,定位具体时间段的数据的搜索时间会变长,影响读取速度;过小,数据块的索引太大,压缩效率偏低,也影响读取速度。
|
||||
|
||||
|
@ -351,32 +362,47 @@ TDengine采用数据驱动的方式让缓存中的数据写入硬盘进行持久
|
|||
|
||||
### 多级存储
|
||||
|
||||
在默认配置下,TDengine会将所有数据保存在/var/lib/taos目录下,而且每个vnode的数据文件保存在该目录下的不同目录。为扩大存储空间,尽量减少文件读取的瓶颈,提高数据吞吐率 TDengine可通过配置系统参数dataDir让多个挂载的硬盘被系统同时使用。除此之外,TDengine也提供了数据分级存储的功能,即根据数据文件的新老程度存储在不同的存储介质上。比如最新的数据存储在SSD上,超过一周的数据存储在本地硬盘上,超过4周的数据存储在网络存储设备上,这样来降低存储成本,而又保证高效的访问数据。数据在不同存储介质上的移动是由系统自动完成的,对应用是完全透明的。数据的分级存储也是通过系统参数dataDir来配置。
|
||||
说明:多级存储功能仅企业版支持,从 2.0.16.0 版本开始提供。
|
||||
|
||||
dataDir的配置格式如下:
|
||||
```
|
||||
dataDir data_path [tier_level]
|
||||
```
|
||||
其中data_path为挂载点的文件夹路径,tier_level为介质存储等级。介质存储等级越高,盛放数据文件越老。同一存储等级可挂载多个硬盘,同一存储等级上的数据文件分布在该存储等级的所有硬盘上。TDengine最多支持3级存储,所以tier_level的取值为0、1和2。在配置dataDir时,必须存在且只有一个挂载路径不指定tier_level,称之为特殊挂载盘(路径)。该挂载路径默认为0级存储介质,且包含特殊文件链接,不可被移除,否则会对写入的数据产生毁灭性影响。
|
||||
在默认配置下,TDengine会将所有数据保存在/var/lib/taos目录下,而且每个vnode的数据文件保存在该目录下的不同目录。为扩大存储空间,尽量减少文件读取的瓶颈,提高数据吞吐率 TDengine可通过配置系统参数dataDir让多个挂载的硬盘被系统同时使用。
|
||||
|
||||
假设一物理节点有六个可挂载的硬盘/mnt/disk1、/mnt/disk2、…、/mnt/disk6,其中disk1和disk2需要被指定为0级存储介质,disk3和disk4为1级存储介质, disk5和disk6为2级存储介质。disk1为特殊挂载盘,则可在/etc/taos/taos.cfg中做如下配置:
|
||||
除此之外,TDengine也提供了数据分级存储的功能,将不同时间段的数据存储在挂载的不同介质上的目录里,从而实现不同“热度”的数据存储在不同的存储介质上,充分利用存储,节约成本。比如,最新采集的数据需要经常访问,对硬盘的读取性能要求高,那么用户可以配置将这些数据存储在SSD盘上。超过一定期限的数据,查询需求量没有那么高,那么可以存储在相对便宜的HDD盘上。
|
||||
|
||||
多级存储支持3级,每级最多可配置16个挂载点。
|
||||
|
||||
TDengine多级存储配置方式如下(在配置文件/etc/taos/taos.cfg中):
|
||||
|
||||
```
|
||||
dataDir /mnt/disk1/taos
|
||||
dataDir /mnt/disk2/taos 0
|
||||
dataDir /mnt/disk3/taos 1
|
||||
dataDir /mnt/disk4/taos 1
|
||||
dataDir /mnt/disk5/taos 2
|
||||
dataDir /mnt/disk6/taos 2
|
||||
dataDir [path] <level> <primary>
|
||||
```
|
||||
|
||||
挂载的盘也可以是非本地的网络盘,只要系统能访问即可。
|
||||
- path: 挂载点的文件夹路径
|
||||
- level: 介质存储等级,取值为0,1,2。
|
||||
0级存储最新的数据,1级存储次新的数据,2级存储最老的数据,省略默认为0。
|
||||
各级存储之间的数据流向:0级存储 -> 1级存储 -> 2级存储。
|
||||
同一存储等级可挂载多个硬盘,同一存储等级上的数据文件分布在该存储等级的所有硬盘上。
|
||||
需要说明的是,数据在不同级别的存储介质上的移动,是由系统自动完成的,用户无需干预。
|
||||
- primary: 是否为主挂载点,0(是)或1(否),省略默认为1。
|
||||
|
||||
注:多级存储功能仅企业版支持
|
||||
在配置中,只允许一个主挂载点的存在(level=0, primary=0),例如采用如下的配置方式:
|
||||
|
||||
```
|
||||
dataDir /mnt/data1 0 0
|
||||
dataDir /mnt/data2 0 1
|
||||
dataDir /mnt/data3 1 1
|
||||
dataDir /mnt/data4 1 1
|
||||
dataDir /mnt/data5 2 1
|
||||
dataDir /mnt/data6 2 1
|
||||
```
|
||||
|
||||
注意:
|
||||
1. 多级存储不允许跨级配置,合法的配置方案有:仅0级,仅0级+1级,以及0级+1级+2级。而不允许只配置level=0和level=2,而不配置level=1。
|
||||
2. 禁止手动移除使用中的挂载盘,挂载盘目前不支持非本地的网络盘。
|
||||
3. 多级存储目前不支持删除已经挂载的硬盘的功能。
|
||||
|
||||
## <a class="anchor" id="query"></a>数据查询
|
||||
|
||||
TDengine提供了多种多样针对表和超级表的查询处理功能,除了常规的聚合查询之外,还提供针对时序数据的窗口查询、统计聚合等功能。TDengine的查询处理需要客户端、vnode, mnode节点协同完成。
|
||||
TDengine提供了多种多样针对表和超级表的查询处理功能,除了常规的聚合查询之外,还提供针对时序数据的窗口查询、统计聚合等功能。TDengine的查询处理需要客户端、vnode、mnode节点协同完成。
|
||||
|
||||
### 单表查询
|
||||
|
||||
|
@ -388,31 +414,31 @@ SQL语句的解析和校验工作在客户端完成。解析SQL语句并生成
|
|||
|
||||
### 按时间轴聚合、降采样、插值
|
||||
|
||||
时序数据有别于普通数据的显著特征是每条记录均具有时间戳,因此针对具有时间戳数据在时间轴上进行聚合是不同于普通数据库的重要功能。从这点上来看,与流计算引擎的窗口查询有相似的地方。
|
||||
时序数据有别于普通数据的显著特征是每条记录均具有时间戳,因此针对具有时间戳的数据在时间轴上进行聚合是不同于普通数据库的重要功能。从这点上来看,与流计算引擎的窗口查询有相似的地方。
|
||||
|
||||
在TDengine中引入关键词interval来进行时间轴上固定长度时间窗口的切分,并按照时间窗口对数据进行聚合,对窗口范围内的数据按需进行聚合。例如:
|
||||
```mysql
|
||||
select count(*) from d1001 interval(1h);
|
||||
```sql
|
||||
SELECT COUNT(*) FROM d1001 INTERVAL(1h);
|
||||
```
|
||||
|
||||
针对d1001设备采集的数据,按照1小时的时间窗口返回每小时存储的记录数量。
|
||||
|
||||
在需要连续获得查询结果的应用场景下,如果给定的时间区间存在数据缺失,会导致该区间数据结果也丢失。TDengine提供策略针对时间轴聚合计算的结果进行插值,通过使用关键词Fill就能够对时间轴聚合结果进行插值。例如:
|
||||
```mysql
|
||||
select count(*) from d1001 interval(1h) fill(prev);
|
||||
在需要连续获得查询结果的应用场景下,如果给定的时间区间存在数据缺失,会导致该区间数据结果也丢失。TDengine提供策略针对时间轴聚合计算的结果进行插值,通过使用关键词fill就能够对时间轴聚合结果进行插值。例如:
|
||||
```sql
|
||||
SELECT COUNT(*) FROM d1001 WHERE ts >= '2017-7-14 00:00:00' AND ts < '2017-7-14 23:59:59' INTERVAL(1h) FILL(PREV);
|
||||
```
|
||||
|
||||
针对d1001设备采集数据统计每小时记录数,如果某一个小时不存在数据,则返回之前一个小时的统计数据。TDengine提供前向插值(prev)、线性插值(linear)、NULL值填充(NULL)、特定值填充(value)。
|
||||
|
||||
### 多表聚合查询
|
||||
|
||||
TDengine对每个数据采集点单独建表,但在实际应用中经常需要对不同的采集点数据进行聚合。为高效的进行聚合操作,TDengine引入超级表(STable)的概念。超级表用来代表一特定类型的数据采集点,它是包含多张表的表集合,集合里每张表的模式(schema)完全一致,但每张表都带有自己的静态标签,标签可以多个,可以随时增加、删除和修改。 应用可通过指定标签的过滤条件,对一个STable下的全部或部分表进行聚合或统计操作,这样大大简化应用的开发。其具体流程如下图所示:
|
||||
TDengine对每个数据采集点单独建表,但在实际应用中经常需要对不同的采集点数据进行聚合。为高效的进行聚合操作,TDengine引入超级表(STable)的概念。超级表用来代表一特定类型的数据采集点,它是包含多张表的表集合,集合里每张表的模式(schema)完全一致,但每张表都带有自己的静态标签,标签可以有多个,可以随时增加、删除和修改。应用可通过指定标签的过滤条件,对一个STable下的全部或部分表进行聚合或统计操作,这样大大简化应用的开发。其具体流程如下图所示:
|
||||
|
||||

|
||||
<center> 图 5 多表聚合查询原理图 </center>
|
||||
|
||||
1. 应用将一个查询条件发往系统;
|
||||
2. taosc将超级表的名字发往 Meta Node(管理节点);
|
||||
2. taosc将超级表的名字发往 meta node(管理节点);
|
||||
3. 管理节点将超级表所拥有的 vnode 列表发回 taosc;
|
||||
4. taosc将计算的请求连同标签过滤条件发往这些vnode对应的多个数据节点;
|
||||
5. 每个vnode先在内存里查找出自己节点里符合标签过滤条件的表的集合,然后扫描存储的时序数据,完成相应的聚合计算,将结果返回给taosc;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
|
||||
|
||||
# 数据建模
|
||||
# TDengine数据建模
|
||||
|
||||
TDengine采用关系型数据模型,需要建库、建表。因此对于一个具体的应用场景,需要考虑库的设计,超级表和普通表的设计。本节不讨论细致的语法规则,只介绍概念。
|
||||
|
||||
|
@ -8,10 +8,10 @@ TDengine采用关系型数据模型,需要建库、建表。因此对于一个
|
|||
|
||||
## <a class="anchor" id="create-db"></a>创建库
|
||||
|
||||
不同类型的数据采集点往往具有不同的数据特征,包括数据采集频率的高低,数据保留时间的长短,副本的数目,数据块的大小,是否允许更新数据等等。为让各种场景下TDengine都能最大效率的工作,TDengine建议将不同数据特征的表创建在不同的库里,因为每个库可以配置不同的存储策略。创建一个库时,除SQL标准的选项外,应用还可以指定保留时长、副本数、内存块个数、时间精度、文件块里最大最小记录条数、是否压缩、一个数据文件覆盖的天数等多种参数。比如:
|
||||
不同类型的数据采集点往往具有不同的数据特征,包括数据采集频率的高低,数据保留时间的长短,副本的数目,数据块的大小,是否允许更新数据等等。为了在各种场景下TDengine都能最大效率的工作,TDengine建议将不同数据特征的表创建在不同的库里,因为每个库可以配置不同的存储策略。创建一个库时,除SQL标准的选项外,应用还可以指定保留时长、副本数、内存块个数、时间精度、文件块里最大最小记录条数、是否压缩、一个数据文件覆盖的天数等多种参数。比如:
|
||||
|
||||
```mysql
|
||||
CREATE DATABASE power KEEP 365 DAYS 10 BLOCKS 4 UPDATE 1;
|
||||
CREATE DATABASE power KEEP 365 DAYS 10 BLOCKS 6 UPDATE 1;
|
||||
```
|
||||
上述语句将创建一个名为power的库,这个库的数据将保留365天(超过365天将被自动删除),每10天一个数据文件,内存块数为4,允许更新数据。详细的语法及参数请见 [TAOS SQL 的数据管理](https://www.taosdata.com/cn/documentation/taos-sql#management) 章节。
|
||||
|
||||
|
@ -21,16 +21,17 @@ CREATE DATABASE power KEEP 365 DAYS 10 BLOCKS 4 UPDATE 1;
|
|||
USE power;
|
||||
```
|
||||
|
||||
就当前连接里操作的库换为power,否则对具体表操作前,需要使用“库名.表名”来指定库的名字。
|
||||
将当前连接里操作的库换为power,否则对具体表操作前,需要使用“库名.表名”来指定库的名字。
|
||||
|
||||
**注意:**
|
||||
|
||||
- 任何一张表或超级表是属于一个库的,在创建表之前,必须先创建库。
|
||||
- 处于两个不同库的表是不能进行JOIN操作的。
|
||||
- 创建并插入记录、查询历史记录的时候,均需要指定时间戳。
|
||||
|
||||
## <a class="anchor" id="create-stable"></a>创建超级表
|
||||
|
||||
一个物联网系统,往往存在多种类型的设备,比如对于电网,存在智能电表、变压器、母线、开关等等。为便于多表之间的聚合,使用TDengine, 需要对每个类型的数据采集点创建一超级表。以表一中的智能电表为例,可以使用如下的SQL命令创建超级表:
|
||||
一个物联网系统,往往存在多种类型的设备,比如对于电网,存在智能电表、变压器、母线、开关等等。为便于多表之间的聚合,使用TDengine, 需要对每个类型的数据采集点创建一个超级表。以[表1](https://www.taosdata.com/cn/documentation/architecture#model_table1)中的智能电表为例,可以使用如下的SQL命令创建超级表:
|
||||
|
||||
```mysql
|
||||
CREATE STABLE meters (ts timestamp, current float, voltage int, phase float) TAGS (location binary(64), groupId int);
|
||||
|
@ -46,7 +47,7 @@ CREATE STABLE meters (ts timestamp, current float, voltage int, phase float) TAG
|
|||
|
||||
## <a class="anchor" id="create-table"></a>创建表
|
||||
|
||||
TDengine对每个数据采集点需要独立建表。与标准的关系型数据一样,一张表有表名,Schema,但除此之外,还可以带有一到多个标签。创建时,需要使用超级表做模板,同时指定标签的具体值。以表一中的智能电表为例,可以使用如下的SQL命令建表:
|
||||
TDengine对每个数据采集点需要独立建表。与标准的关系型数据库一样,一张表有表名,Schema,但除此之外,还可以带有一到多个标签。创建时,需要使用超级表做模板,同时指定标签的具体值。以[表1](https://www.taosdata.com/cn/documentation/architecture#model_table1)中的智能电表为例,可以使用如下的SQL命令建表:
|
||||
|
||||
```mysql
|
||||
CREATE TABLE d1001 USING meters TAGS ("Beijing.Chaoyang", 2);
|
||||
|
@ -61,10 +62,10 @@ TDengine建议将数据采集点的全局唯一ID作为表名(比如设备序列
|
|||
**自动建表**:在某些特殊场景中,用户在写数据时并不确定某个数据采集点的表是否存在,此时可在写入数据时使用自动建表语法来创建不存在的表,若该表已存在则不会建立新表。比如:
|
||||
|
||||
```mysql
|
||||
INSERT INTO d1001 USING METERS TAGS ("Beijng.Chaoyang", 2) VALUES (now, 10.2, 219, 0.32);
|
||||
INSERT INTO d1001 USING meters TAGS ("Beijng.Chaoyang", 2) VALUES (now, 10.2, 219, 0.32);
|
||||
```
|
||||
|
||||
上述SQL语句将记录 (now, 10.2, 219, 0.32) 插入表d1001。如果表d1001还未创建,则使用超级表meters做模板自动创建,同时打上标签值“Beijing.Chaoyang", 2。
|
||||
上述SQL语句将记录 (now, 10.2, 219, 0.32) 插入表d1001。如果表d1001还未创建,则使用超级表meters做模板自动创建,同时打上标签值 `“Beijing.Chaoyang", 2`。
|
||||
|
||||
关于自动建表的详细语法请参见 [插入记录时自动建表](https://www.taosdata.com/cn/documentation/taos-sql#auto_create_table) 章节。
|
||||
|
||||
|
@ -72,5 +73,5 @@ INSERT INTO d1001 USING METERS TAGS ("Beijng.Chaoyang", 2) VALUES (now, 10.2, 21
|
|||
|
||||
TDengine支持多列模型,只要物理量是一个数据采集点同时采集的(时间戳一致),这些量就可以作为不同列放在一张超级表里。但还有一种极限的设计,单列模型,每个采集的物理量都单独建表,因此每种类型的物理量都单独建立一超级表。比如电流、电压、相位,就建三张超级表。
|
||||
|
||||
TDengine建议尽可能采用多列模型,因为插入效率以及存储效率更高。但对于有些场景,一个采集点的采集量的种类经常变化,这个时候,如果采用多列模型,就需要频繁修改超级表的结构定义,让应用变的复杂,这个时候,采用单列模型会显得简单。
|
||||
TDengine建议尽可能采用多列模型,因为插入效率以及存储效率更高。但对于有些场景,一个采集点的采集量的种类经常变化,这个时候,如果采用多列模型,就需要频繁修改超级表的结构定义,让应用变的复杂,这个时候,采用单列模型会显得更简单。
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ TDengine支持多种接口写入数据,包括SQL, Prometheus, Telegraf, EMQ MQ
|
|||
|
||||
## <a class="anchor" id="sql"></a>SQL写入
|
||||
|
||||
应用通过C/C++, JDBC, GO, 或Python Connector 执行SQL insert语句来插入数据,用户还可以通过TAOS Shell,手动输入SQL insert语句插入数据。比如下面这条insert 就将一条记录写入到表d1001中:
|
||||
应用通过C/C++、JDBC、GO、C#或Python Connector 执行SQL insert语句来插入数据,用户还可以通过TAOS Shell,手动输入SQL insert语句插入数据。比如下面这条insert 就将一条记录写入到表d1001中:
|
||||
```mysql
|
||||
INSERT INTO d1001 VALUES (1538548685000, 10.3, 219, 0.31);
|
||||
```
|
||||
|
@ -23,20 +23,20 @@ INSERT INTO d1001 VALUES (1538548685000, 10.3, 219, 0.31) (1538548695000, 12.6,
|
|||
**Tips:**
|
||||
|
||||
- 要提高写入效率,需要批量写入。一批写入的记录条数越多,插入效率就越高。但一条记录不能超过16K,一条SQL语句总长度不能超过64K(可通过参数maxSQLLength配置,最大可配置为1M)。
|
||||
- TDengine支持多线程同时写入,要进一步提高写入速度,一个客户端需要打开20个以上的线程同时写。但线程数达到一定数量后,无法再提高,甚至还会下降,因为线程切频繁切换,带来额外开销。
|
||||
- 对同一张表,如果新插入记录的时间戳已经存在,默认(没有使用 UPDATE 1 创建数据库)新记录将被直接抛弃,也就是说,在一张表里,时间戳必须是唯一的。如果应用自动生成记录,很有可能生成的时间戳是一样的,这样,成功插入的记录条数会小于应用插入的记录条数。如果在创建数据库时使用 UPDATE 1 选项,插入相同时间戳的新记录将覆盖原有记录。
|
||||
- 写入的数据的时间戳必须大于当前时间减去配置参数keep的时间。如果keep配置为3650天,那么无法写入比3650天还老的数据。写入数据的时间戳也不能大于当前时间加配置参数days。如果days配置为2,那么无法写入比当前时间还晚2天的数据。
|
||||
- TDengine支持多线程同时写入,要进一步提高写入速度,一个客户端需要打开20个以上的线程同时写。但线程数达到一定数量后,无法再提高,甚至还会下降,因为线程频繁切换,带来额外开销。
|
||||
- 对同一张表,如果新插入记录的时间戳已经存在,默认情形下(UPDATE=0)新记录将被直接抛弃,也就是说,在一张表里,时间戳必须是唯一的。如果应用自动生成记录,很有可能生成的时间戳是一样的,这样,成功插入的记录条数会小于应用插入的记录条数。如果在创建数据库时使用了 UPDATE 1 选项,插入相同时间戳的新记录将覆盖原有记录。
|
||||
- 写入的数据的时间戳必须大于当前时间减去配置参数keep的时间。如果keep配置为3650天,那么无法写入比3650天还早的数据。写入数据的时间戳也不能大于当前时间加配置参数days。如果days为2,那么无法写入比当前时间还晚2天的数据。
|
||||
|
||||
## <a class="anchor" id="prometheus"></a>Prometheus直接写入
|
||||
|
||||
[Prometheus](https://www.prometheus.io/)作为Cloud Native Computing Fundation毕业的项目,在性能监控以及K8S性能监控领域有着非常广泛的应用。TDengine提供一个小工具[Bailongma](https://github.com/taosdata/Bailongma),只需在Prometheus做简单配置,无需任何代码,就可将Prometheus采集的数据直接写入TDengine,并按规则在TDengine自动创建库和相关表项。博文[用Docker容器快速搭建一个Devops监控Demo](https://www.taosdata.com/blog/2020/02/03/1189.html)即是采用bailongma将Prometheus和Telegraf的数据写入TDengine中的示例,可以参考。
|
||||
[Prometheus](https://www.prometheus.io/)作为Cloud Native Computing Fundation毕业的项目,在性能监控以及K8S性能监控领域有着非常广泛的应用。TDengine提供一个小工具[Bailongma](https://github.com/taosdata/Bailongma),只需对Prometheus做简单配置,无需任何代码,就可将Prometheus采集的数据直接写入TDengine,并按规则在TDengine自动创建库和相关表项。博文[用Docker容器快速搭建一个Devops监控Demo](https://www.taosdata.com/blog/2020/02/03/1189.html)即是采用Bailongma将Prometheus和Telegraf的数据写入TDengine中的示例,可以参考。
|
||||
|
||||
### 从源代码编译blm_prometheus
|
||||
|
||||
用户需要从github下载[Bailongma](https://github.com/taosdata/Bailongma)的源码,使用Golang语言编译器编译生成可执行文件。在开始编译前,需要准备好以下条件:
|
||||
- Linux操作系统的服务器
|
||||
- 安装好Golang, 1.10版本以上
|
||||
- 对应的TDengine版本。因为用到了TDengine的客户端动态链接库,因此需要安装好和服务端相同版本的TDengine程序;比如服务端版本是TDengine 2.0.0, 则在bailongma所在的linux服务器(可以与TDengine在同一台服务器,或者不同服务器)
|
||||
- 安装好Golang,1.10版本以上
|
||||
- 对应的TDengine版本。因为用到了TDengine的客户端动态链接库,因此需要安装好和服务端相同版本的TDengine程序;比如服务端版本是TDengine 2.0.0, 则在Bailongma所在的Linux服务器(可以与TDengine在同一台服务器,或者不同服务器)
|
||||
|
||||
Bailongma项目中有一个文件夹blm_prometheus,存放了prometheus的写入API程序。编译过程如下:
|
||||
```bash
|
||||
|
@ -48,21 +48,23 @@ go build
|
|||
|
||||
### 安装Prometheus
|
||||
|
||||
通过Prometheus的官网下载安装。[下载地址](https://prometheus.io/download/)
|
||||
通过Prometheus的官网下载安装。具体请见:[下载地址](https://prometheus.io/download/)。
|
||||
|
||||
### 配置Prometheus
|
||||
|
||||
参考Prometheus的[配置文档](https://prometheus.io/docs/prometheus/latest/configuration/configuration/),在Prometheus的配置文件中的<remote_write>部分,增加以下配置
|
||||
参考Prometheus的[配置文档](https://prometheus.io/docs/prometheus/latest/configuration/configuration/),在Prometheus的配置文件中的<remote_write>部分,增加以下配置:
|
||||
|
||||
- url: bailongma API服务提供的URL, 参考下面的blm_prometheus启动示例章节
|
||||
```
|
||||
- url: "bailongma API服务提供的URL"(参考下面的blm_prometheus启动示例章节)
|
||||
```
|
||||
|
||||
启动Prometheus后,可以通过taos客户端查询确认数据是否成功写入。
|
||||
|
||||
### 启动blm_prometheus程序
|
||||
blm_prometheus程序有以下选项,在启动blm_prometheus程序时可以通过设定这些选项来设定blm_prometheus的配置。
|
||||
```sh
|
||||
```bash
|
||||
--tdengine-name
|
||||
如果TDengine安装在一台具备域名的服务器上,也可以通过配置TDengine的域名来访问TDengine。在K8S环境下,可以配置成TDengine所运行的service name
|
||||
如果TDengine安装在一台具备域名的服务器上,也可以通过配置TDengine的域名来访问TDengine。在K8S环境下,可以配置成TDengine所运行的service name。
|
||||
|
||||
--batch-size
|
||||
blm_prometheus会将收到的prometheus的数据拼装成TDengine的写入请求,这个参数控制一次发给TDengine的写入请求中携带的数据条数。
|
||||
|
@ -71,10 +73,10 @@ blm_prometheus会将收到的prometheus的数据拼装成TDengine的写入请求
|
|||
设置在TDengine中创建的数据库名称,blm_prometheus会自动在TDengine中创建一个以dbname为名称的数据库,缺省值是prometheus。
|
||||
|
||||
--dbuser
|
||||
设置访问TDengine的用户名,缺省值是'root'
|
||||
设置访问TDengine的用户名,缺省值是'root'。
|
||||
|
||||
--dbpassword
|
||||
设置访问TDengine的密码,缺省值是'taosdata'
|
||||
设置访问TDengine的密码,缺省值是'taosdata'。
|
||||
|
||||
--port
|
||||
blm_prometheus对prometheus提供服务的端口号。
|
||||
|
@ -125,8 +127,8 @@ select * from apiserver_request_latencies_bucket;
|
|||
用户需要从github下载[Bailongma](https://github.com/taosdata/Bailongma)的源码,使用Golang语言编译器编译生成可执行文件。在开始编译前,需要准备好以下条件:
|
||||
|
||||
- Linux操作系统的服务器
|
||||
- 安装好Golang, 1.10版本以上
|
||||
- 对应的TDengine版本。因为用到了TDengine的客户端动态链接库,因此需要安装好和服务端相同版本的TDengine程序;比如服务端版本是TDengine 2.0.0, 则在bailongma所在的linux服务器(可以与TDengine在同一台服务器,或者不同服务器)
|
||||
- 安装好Golang,1.10版本以上
|
||||
- 对应的TDengine版本。因为用到了TDengine的客户端动态链接库,因此需要安装好和服务端相同版本的TDengine程序;比如服务端版本是TDengine 2.0.0, 则在Bailongma所在的Linux服务器(可以与TDengine在同一台服务器,或者不同服务器)
|
||||
|
||||
Bailongma项目中有一个文件夹blm_telegraf,存放了Telegraf的写入API程序。编译过程如下:
|
||||
|
||||
|
@ -139,7 +141,7 @@ go build
|
|||
|
||||
### 安装Telegraf
|
||||
|
||||
目前TDengine支持Telegraf 1.7.4以上的版本。用户可以根据当前的操作系统,到Telegraf官网下载安装包,并执行安装。下载地址如下:https://portal.influxdata.com/downloads
|
||||
目前TDengine支持Telegraf 1.7.4以上的版本。用户可以根据当前的操作系统,到Telegraf官网下载安装包,并执行安装。下载地址如下:https://portal.influxdata.com/downloads 。
|
||||
|
||||
### 配置Telegraf
|
||||
|
||||
|
@ -147,13 +149,13 @@ go build
|
|||
|
||||
在output plugins部分,增加[[outputs.http]]配置项:
|
||||
|
||||
- url: bailongma API服务提供的URL, 参考下面的启动示例章节
|
||||
- data_format: "json"
|
||||
- json_timestamp_units: "1ms"
|
||||
- url:Bailongma API服务提供的URL,参考下面的启动示例章节
|
||||
- data_format:"json"
|
||||
- json_timestamp_units:"1ms"
|
||||
|
||||
在agent部分:
|
||||
|
||||
- hostname: 区分不同采集设备的机器名称,需确保其唯一性
|
||||
- hostname: 区分不同采集设备的机器名称,需确保其唯一性。
|
||||
- metric_batch_size: 100,允许Telegraf每批次写入记录最大数量,增大其数量可以降低Telegraf的请求发送频率。
|
||||
|
||||
关于如何使用Telegraf采集数据以及更多有关使用Telegraf的信息,请参考Telegraf官方的[文档](https://docs.influxdata.com/telegraf/v1.11/)。
|
||||
|
@ -161,9 +163,9 @@ go build
|
|||
### 启动blm_telegraf程序
|
||||
blm_telegraf程序有以下选项,在启动blm_telegraf程序时可以通过设定这些选项来设定blm_telegraf的配置。
|
||||
|
||||
```sh
|
||||
```bash
|
||||
--host
|
||||
TDengine服务端的IP地址,缺省值为空
|
||||
TDengine服务端的IP地址,缺省值为空。
|
||||
|
||||
--batch-size
|
||||
blm_telegraf会将收到的telegraf的数据拼装成TDengine的写入请求,这个参数控制一次发给TDengine的写入请求中携带的数据条数。
|
||||
|
@ -172,10 +174,10 @@ blm_telegraf会将收到的telegraf的数据拼装成TDengine的写入请求,
|
|||
设置在TDengine中创建的数据库名称,blm_telegraf会自动在TDengine中创建一个以dbname为名称的数据库,缺省值是prometheus。
|
||||
|
||||
--dbuser
|
||||
设置访问TDengine的用户名,缺省值是'root'
|
||||
设置访问TDengine的用户名,缺省值是'root'。
|
||||
|
||||
--dbpassword
|
||||
设置访问TDengine的密码,缺省值是'taosdata'
|
||||
设置访问TDengine的密码,缺省值是'taosdata'。
|
||||
|
||||
--port
|
||||
blm_telegraf对telegraf提供服务的端口号。
|
||||
|
@ -183,12 +185,12 @@ blm_telegraf对telegraf提供服务的端口号。
|
|||
|
||||
### 启动示例
|
||||
|
||||
通过以下命令启动一个blm_telegraf的API服务
|
||||
通过以下命令启动一个blm_telegraf的API服务:
|
||||
```bash
|
||||
./blm_telegraf -host 127.0.0.1 -port 8089
|
||||
```
|
||||
|
||||
假设blm_telegraf所在服务器的IP地址为"10.1.2.3",则在telegraf的配置文件中, 在output plugins部分,增加[[outputs.http]]配置项:
|
||||
假设blm_telegraf所在服务器的IP地址为"10.1.2.3",则在telegraf的配置文件中, 在output plugins部分,增加[[outputs.http]]配置项:
|
||||
|
||||
```yaml
|
||||
url = "http://10.1.2.3:8089/telegraf"
|
||||
|
@ -221,18 +223,16 @@ telegraf产生的数据格式如下:
|
|||
}
|
||||
```
|
||||
|
||||
其中,name字段为telegraf采集的时序数据的名称,tags字段为该时序数据的标签。blm_telegraf会以时序数据的名称在TDengine中自动创建一个超级表,并将tags字段中的标签转换成TDengine的tag值,Timestamp作为时间戳,fields字段中的值作为该时序数据的值。因此在TDengine的客户端中,可以通过以下指令查到这个数据是否成功写入。
|
||||
其中,name字段为telegraf采集的时序数据的名称,tags字段为该时序数据的标签。blm_telegraf会以时序数据的名称在TDengine中自动创建一个超级表,并将tags字段中的标签转换成TDengine的tag值,timestamp作为时间戳,fields字段中的值作为该时序数据的值。因此在TDengine的客户端中,可以通过以下指令查到这个数据是否成功写入。
|
||||
|
||||
```mysql
|
||||
use telegraf;
|
||||
select * from cpu;
|
||||
```
|
||||
|
||||
MQTT是一流行的物联网数据传输协议,TDengine 可以很方便的接入 MQTT Broker 接受的数据并写入到 TDengine。
|
||||
|
||||
## <a class="anchor" id="emq"></a>EMQ Broker 直接写入
|
||||
|
||||
[EMQ](https://github.com/emqx/emqx)是一开源的MQTT Broker软件,无需任何代码,只需要在EMQ Dashboard里使用“规则”做简单配置,即可将MQTT的数据直接写入TDengine。EMQ X 支持通过 发送到 Web 服务 的方式保存数据到 TDengine,也在企业版上提供原生的 TDengine 驱动实现直接保存。详细使用方法请参考[EMQ 官方文档](https://docs.emqx.io/broker/latest/cn/rule/rule-example.html#%E4%BF%9D%E5%AD%98%E6%95%B0%E6%8D%AE%E5%88%B0-tdengine)。
|
||||
MQTT是流行的物联网数据传输协议,[EMQ](https://github.com/emqx/emqx)是一开源的MQTT Broker软件,无需任何代码,只需要在EMQ Dashboard里使用“规则”做简单配置,即可将MQTT的数据直接写入TDengine。EMQ X 支持通过 发送到 Web 服务的方式保存数据到 TDEngine,也在企业版上提供原生的 TDEngine 驱动实现直接保存。详细使用方法请参考 [EMQ 官方文档](https://docs.emqx.io/broker/latest/cn/rule/rule-example.html#%E4%BF%9D%E5%AD%98%E6%95%B0%E6%8D%AE%E5%88%B0-tdengine)。
|
||||
|
||||
## <a class="anchor" id="hivemq"></a>HiveMQ Broker 直接写入
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
TDengine 采用 SQL 作为查询语言。应用程序可以通过 C/C++, Java, Go, Python 连接器发送 SQL 语句,用户可以通过 TDengine 提供的命令行(Command Line Interface, CLI)工具 TAOS Shell 手动执行 SQL 即席查询(Ad-Hoc Query)。TDengine 支持如下查询功能:
|
||||
|
||||
- 单列、多列数据查询
|
||||
- 标签和数值的多种过滤条件:>, <, =, <>, like 等
|
||||
- 标签和数值的多种过滤条件:>, <, =, <>, like 等
|
||||
- 聚合结果的分组(Group by)、排序(Order by)、约束输出(Limit/Offset)
|
||||
- 数值列及聚合结果的四则运算
|
||||
- 时间戳对齐的连接查询(Join Query: 隐式连接)操作
|
||||
|
|
|
@ -35,13 +35,13 @@ select avg(voltage) from meters interval(1m) sliding(30s);
|
|||
select avg(voltage) from meters where ts > {startTime} interval(1m) sliding(30s);
|
||||
```
|
||||
|
||||
这样做没有问题,但TDengine提供了更简单的方法,只要在最初的查询语句前面加上 `create table {tableName} as ` 就可以了, 例如:
|
||||
这样做没有问题,但TDengine提供了更简单的方法,只要在最初的查询语句前面加上 `create table {tableName} as ` 就可以了,例如:
|
||||
|
||||
```sql
|
||||
create table avg_vol as select avg(voltage) from meters interval(1m) sliding(30s);
|
||||
```
|
||||
|
||||
会自动创建一个名为 `avg_vol` 的新表,然后每隔30秒,TDengine会增量执行 `as` 后面的 SQL 语句,并将查询结果写入这个表中,用户程序后续只要从 `avg_vol` 中查询数据即可。 例如:
|
||||
会自动创建一个名为 `avg_vol` 的新表,然后每隔30秒,TDengine会增量执行 `as` 后面的 SQL 语句,并将查询结果写入这个表中,用户程序后续只要从 `avg_vol` 中查询数据即可。例如:
|
||||
|
||||
```mysql
|
||||
taos> select * from avg_vol;
|
||||
|
@ -138,7 +138,7 @@ select * from meters where ts > now - 1d and current > 10;
|
|||
|
||||
订阅的`topic`实际上是它的名字,因为订阅功能是在客户端API中实现的,所以没必要保证它全局唯一,但需要它在一台客户端机器上唯一。
|
||||
|
||||
如果名`topic`的订阅不存在,参数`restart`没有意义;但如果用户程序创建这个订阅后退出,当它再次启动并重新使用这个`topic`时,`restart`就会被用于决定是从头开始读取数据,还是接续上次的位置进行读取。本例中,如果`restart`是 **true**(非零值),用户程序肯定会读到所有数据。但如果这个订阅之前就存在了,并且已经读取了一部分数据,且`restart`是 **false**(**0**),用户程序就不会读到之前已经读取的数据了。
|
||||
如果名为`topic`的订阅不存在,参数`restart`没有意义;但如果用户程序创建这个订阅后退出,当它再次启动并重新使用这个`topic`时,`restart`就会被用于决定是从头开始读取数据,还是接续上次的位置进行读取。本例中,如果`restart`是 **true**(非零值),用户程序肯定会读到所有数据。但如果这个订阅之前就存在了,并且已经读取了一部分数据,且`restart`是 **false**(**0**),用户程序就不会读到之前已经读取的数据了。
|
||||
|
||||
`taos_subscribe`的最后一个参数是以毫秒为单位的轮询周期。在同步模式下,如果前后两次调用`taos_consume`的时间间隔小于此时间,`taos_consume`会阻塞,直到间隔超过此时间。异步模式下,这个时间是两次调用回调函数的最小时间间隔。
|
||||
|
||||
|
@ -179,7 +179,8 @@ void print_result(TAOS_RES* res, int blockFetch) {
|
|||
} else {
|
||||
while ((row = taos_fetch_row(res))) {
|
||||
char temp[256];
|
||||
taos_print_row(temp, row, fields, num_fields);puts(temp);
|
||||
taos_print_row(temp, row, fields, num_fields);
|
||||
puts(temp);
|
||||
nRows++;
|
||||
}
|
||||
}
|
||||
|
@ -211,14 +212,14 @@ taos_unsubscribe(tsub, keep);
|
|||
|
||||
则可以在示例代码所在目录执行以下命令来编译并启动示例程序:
|
||||
|
||||
```shell
|
||||
```bash
|
||||
$ make
|
||||
$ ./subscribe -sql='select * from meters where current > 10;'
|
||||
```
|
||||
|
||||
示例程序启动后,打开另一个终端窗口,启动 TDengine 的 shell 向 **D1001** 插入一条电流为 12A 的数据:
|
||||
|
||||
```shell
|
||||
```sql
|
||||
$ taos
|
||||
> use test;
|
||||
> insert into D1001 values(now, 12, 220, 1);
|
||||
|
@ -313,7 +314,7 @@ public class SubscribeDemo {
|
|||
|
||||
运行示例程序,首先,它会消费符合查询条件的所有历史数据:
|
||||
|
||||
```shell
|
||||
```bash
|
||||
# java -jar subscribe.jar
|
||||
|
||||
ts: 1597464000000 current: 12.0 voltage: 220 phase: 1 location: Beijing.Chaoyang groupid : 2
|
||||
|
@ -333,16 +334,16 @@ taos> insert into d1001 values("2020-08-15 12:40:00.000", 12.4, 220, 1);
|
|||
|
||||
因为这条数据的电流大于10A,示例程序会将其消费:
|
||||
|
||||
```shell
|
||||
```
|
||||
ts: 1597466400000 current: 12.4 voltage: 220 phase: 1 location: Beijing.Chaoyang groupid: 2
|
||||
```
|
||||
|
||||
|
||||
## <a class="anchor" id="cache"></a>缓存(Cache)
|
||||
|
||||
TDengine采用时间驱动缓存管理策略(First-In-First-Out,FIFO),又称为写驱动的缓存管理机制。这种策略有别于读驱动的数据缓存模式(Least-Recent-Use,LRU),直接将最近写入的数据保存在系统的缓存中。当缓存达到临界值的时候,将最早的数据批量写入磁盘。一般意义上来说,对于物联网数据的使用,用户最为关心最近产生的数据,即当前状态。TDengine充分利用了这一特性,将最近到达的(当前状态)数据保存在缓存中。
|
||||
TDengine采用时间驱动缓存管理策略(First-In-First-Out,FIFO),又称为写驱动的缓存管理机制。这种策略有别于读驱动的数据缓存模式(Least-Recent-Used,LRU),直接将最近写入的数据保存在系统的缓存中。当缓存达到临界值的时候,将最早的数据批量写入磁盘。一般意义上来说,对于物联网数据的使用,用户最为关心最近产生的数据,即当前状态。TDengine充分利用了这一特性,将最近到达的(当前状态)数据保存在缓存中。
|
||||
|
||||
TDengine通过查询函数向用户提供毫秒级的数据获取能力。直接将最近到达的数据保存在缓存中,可以更加快速地响应用户针对最近一条或一批数据的查询分析,整体上提供更快的数据库查询响应能力。从这个意义上来说,可通过设置合适的配置参数将TDengine作为数据缓存来使用,而不需要再部署额外的缓存系统,可有效地简化系统架构,降低运维的成本。需要注意的是,TDengine重启以后系统的缓存将被清空,之前缓存的数据均会被批量写入磁盘,缓存的数据将不会像专门的Key-value缓存系统再将之前缓存的数据重新加载到缓存中。
|
||||
TDengine通过查询函数向用户提供毫秒级的数据获取能力。直接将最近到达的数据保存在缓存中,可以更加快速地响应用户针对最近一条或一批数据的查询分析,整体上提供更快的数据库查询响应能力。从这个意义上来说,可通过设置合适的配置参数将TDengine作为数据缓存来使用,而不需要再部署额外的缓存系统,可有效地简化系统架构,降低运维的成本。需要注意的是,TDengine重启以后系统的缓存将被清空,之前缓存的数据均会被批量写入磁盘,缓存的数据将不会像专门的key-value缓存系统再将之前缓存的数据重新加载到缓存中。
|
||||
|
||||
TDengine分配固定大小的内存空间作为缓存空间,缓存空间可根据应用的需求和硬件资源配置。通过适当的设置缓存空间,TDengine可以提供极高性能的写入和查询的支持。TDengine中每个虚拟节点(virtual node)创建时分配独立的缓存池。每个虚拟节点管理自己的缓存池,不同虚拟节点间不共享缓存池。每个虚拟节点内部所属的全部表共享该虚拟节点的缓存池。
|
||||
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
# Java Connector
|
||||
|
||||
TDengine 提供了遵循 JDBC 标准(3.0)API 规范的 `taos-jdbcdriver` 实现,可在 maven 的中央仓库 [Sonatype Repository][1] 搜索下载。
|
||||
## 总体介绍
|
||||
|
||||
TDengine 提供了遵循 JDBC 标准(3.0)API 规范的 `taos-jdbcdriver` 实现,可在 maven 的中央仓库 [Sonatype Repository](https://search.maven.org/artifact/com.taosdata.jdbc/taos-jdbcdriver) 搜索下载。
|
||||
|
||||
`taos-jdbcdriver` 的实现包括 2 种形式: JDBC-JNI 和 JDBC-RESTful(taos-jdbcdriver-2.0.18 开始支持 JDBC-RESTful)。 JDBC-JNI 通过调用客户端 libtaos.so(或 taos.dll )的本地方法实现, JDBC-RESTful 则在内部封装了 RESTful 接口实现。
|
||||
|
||||
|
@ -19,65 +21,132 @@ TDengine 的 JDBC 驱动实现尽可能与关系型数据库驱动保持一致
|
|||
* 目前不支持嵌套查询(nested query)。
|
||||
* 对每个 Connection 的实例,至多只能有一个打开的 ResultSet 实例;如果在 ResultSet 还没关闭的情况下执行了新的查询,taos-jdbcdriver 会自动关闭上一个 ResultSet。
|
||||
|
||||
### JDBC-JNI和JDBC-RESTful的对比
|
||||
|
||||
## JDBC-JNI和JDBC-RESTful的对比
|
||||
|
||||
<table >
|
||||
<table>
|
||||
<tr align="center"><th>对比项</th><th>JDBC-JNI</th><th>JDBC-RESTful</th></tr>
|
||||
<tr align="center">
|
||||
<td>支持的操作系统</td>
|
||||
<td>linux、windows</td>
|
||||
<td>全平台</td>
|
||||
<td>支持的操作系统</td>
|
||||
<td>linux、windows</td>
|
||||
<td>全平台</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td>是否需要安装 client</td>
|
||||
<td>需要</td>
|
||||
<td>不需要</td>
|
||||
<td>是否需要安装 client</td>
|
||||
<td>需要</td>
|
||||
<td>不需要</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td>server 升级后是否需要升级 client</td>
|
||||
<td>需要</td>
|
||||
<td>不需要</td>
|
||||
<td>server 升级后是否需要升级 client</td>
|
||||
<td>需要</td>
|
||||
<td>不需要</td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td>写入性能</td>
|
||||
<td colspan="2">JDBC-RESTful 是 JDBC-JNI 的 50%~90% </td>
|
||||
<td>写入性能</td>
|
||||
<td colspan="2">JDBC-RESTful 是 JDBC-JNI 的 50%~90% </td>
|
||||
</tr>
|
||||
<tr align="center">
|
||||
<td>查询性能</td>
|
||||
<td colspan="2">JDBC-RESTful 与 JDBC-JNI 没有差别</td>
|
||||
<td>查询性能</td>
|
||||
<td colspan="2">JDBC-RESTful 与 JDBC-JNI 没有差别</td>
|
||||
</tr>
|
||||
</table>
|
||||
|
||||
注意:与 JNI 方式不同,RESTful 接口是无状态的,因此 `USE db_name` 指令没有效果,RESTful 下所有对表名、超级表名的引用都需要指定数据库名前缀。
|
||||
|
||||
## 如何获取 taos-jdbcdriver
|
||||
### <a class="anchor" id="version"></a>TAOS-JDBCDriver 版本以及支持的 TDengine 版本和 JDK 版本
|
||||
|
||||
### maven 仓库
|
||||
| taos-jdbcdriver 版本 | TDengine 版本 | JDK 版本 |
|
||||
| -------------------- | ----------------- | -------- |
|
||||
| 2.0.33 - 2.0.34 | 2.0.3.0 及以上 | 1.8.x |
|
||||
| 2.0.31 - 2.0.32 | 2.1.3.0 及以上 | 1.8.x |
|
||||
| 2.0.22 - 2.0.30 | 2.0.18.0 - 2.1.2.x | 1.8.x |
|
||||
| 2.0.12 - 2.0.21 | 2.0.8.0 - 2.0.17.x | 1.8.x |
|
||||
| 2.0.4 - 2.0.11 | 2.0.0.0 - 2.0.7.x | 1.8.x |
|
||||
| 1.0.3 | 1.6.1.x 及以上 | 1.8.x |
|
||||
| 1.0.2 | 1.6.1.x 及以上 | 1.8.x |
|
||||
| 1.0.1 | 1.6.1.x 及以上 | 1.8.x |
|
||||
|
||||
目前 taos-jdbcdriver 已经发布到 [Sonatype Repository][1] 仓库,且各大仓库都已同步。
|
||||
### TDengine DataType 和 Java DataType
|
||||
|
||||
* [sonatype][8]
|
||||
* [mvnrepository][9]
|
||||
* [maven.aliyun][10]
|
||||
TDengine 目前支持时间戳、数字、字符、布尔类型,与 Java 对应类型转换如下:
|
||||
|
||||
| TDengine DataType | Java DataType |
|
||||
| ----------------- | ------------------ |
|
||||
| TIMESTAMP | java.sql.Timestamp |
|
||||
| INT | java.lang.Integer |
|
||||
| BIGINT | java.lang.Long |
|
||||
| FLOAT | java.lang.Float |
|
||||
| DOUBLE | java.lang.Double |
|
||||
| SMALLINT | java.lang.Short |
|
||||
| TINYINT | java.lang.Byte |
|
||||
| BOOL | java.lang.Boolean |
|
||||
| BINARY | byte array |
|
||||
| NCHAR | java.lang.String |
|
||||
|
||||
## 安装
|
||||
|
||||
Java连接器支持的系统有: Linux 64/Windows x64/Windows x86。
|
||||
|
||||
**安装前准备:**
|
||||
|
||||
- 已安装TDengine服务器端
|
||||
- 已安装好TDengine应用驱动,具体请参照 [安装连接器驱动步骤](https://www.taosdata.com/cn/documentation/connector#driver) 章节
|
||||
|
||||
TDengine 为了方便 Java 应用使用,遵循 JDBC 标准(3.0)API 规范提供了 `taos-jdbcdriver` 实现。可以通过 [Sonatype Repository](https://search.maven.org/artifact/com.taosdata.jdbc/taos-jdbcdriver) 搜索并下载。
|
||||
|
||||
由于 TDengine 的应用驱动是使用C语言开发的,使用 taos-jdbcdriver 驱动包时需要依赖系统对应的本地函数库。
|
||||
|
||||
- libtaos.so 在 Linux 系统中成功安装 TDengine 后,依赖的本地函数库 libtaos.so 文件会被自动拷贝至 /usr/lib/libtaos.so,该目录包含在 Linux 自动扫描路径上,无需单独指定。
|
||||
|
||||
- taos.dll 在 Windows 系统中安装完客户端之后,驱动包依赖的 taos.dll 文件会自动拷贝到系统默认搜索路径 C:/Windows/System32 下,同样无需要单独指定。
|
||||
|
||||
注意:在 Windows 环境开发时需要安装 TDengine 对应的 [windows 客户端](https://www.taosdata.com/cn/all-downloads/#TDengine-Windows-Client),Linux 服务器安装完 TDengine 之后默认已安装 client,也可以单独安装 [Linux 客户端](https://www.taosdata.com/cn/getting-started/#快速上手) 连接远程 TDengine Server。
|
||||
|
||||
### 如何获取 TAOS-JDBCDriver
|
||||
|
||||
**maven仓库**
|
||||
|
||||
目前 taos-jdbcdriver 已经发布到 [Sonatype Repository](https://search.maven.org/artifact/com.taosdata.jdbc/taos-jdbcdriver) 仓库,且各大仓库都已同步。
|
||||
|
||||
- [sonatype](https://search.maven.org/artifact/com.taosdata.jdbc/taos-jdbcdriver)
|
||||
- [mvnrepository](https://mvnrepository.com/artifact/com.taosdata.jdbc/taos-jdbcdriver)
|
||||
- [maven.aliyun](https://maven.aliyun.com/mvn/search)
|
||||
|
||||
maven 项目中使用如下 pom.xml 配置即可:
|
||||
|
||||
```xml
|
||||
```xml-dtd
|
||||
<dependency>
|
||||
<groupId>com.taosdata.jdbc</groupId>
|
||||
<artifactId>taos-jdbcdriver</artifactId>
|
||||
<version>2.0.18</version>
|
||||
<groupId>com.taosdata.jdbc</groupId>
|
||||
<artifactId>taos-jdbcdriver</artifactId>
|
||||
<version>2.0.18</version>
|
||||
</dependency>
|
||||
```
|
||||
**源码编译打包**
|
||||
|
||||
### 源码编译打包
|
||||
下载 TDengine 源码之后,进入 taos-jdbcdriver 源码目录 `src/connector/jdbc` 执行 `mvn clean package -Dmaven.test.skip=true` 即可生成相应 jar 包。
|
||||
|
||||
下载 [TDengine][3] 源码之后,进入 taos-jdbcdriver 源码目录 `src/connector/jdbc` 执行 `mvn clean package -Dmaven.test.skip=true` 即可生成相应 jar 包。
|
||||
### 示例程序
|
||||
|
||||
示例程序源码位于install_directory/examples/JDBC,有如下目录:
|
||||
|
||||
JDBCDemo JDBC示例源程序
|
||||
|
||||
## JDBC的使用说明
|
||||
JDBCConnectorChecker JDBC安装校验源程序及jar包
|
||||
|
||||
Springbootdemo springboot示例源程序
|
||||
|
||||
SpringJdbcTemplate SpringJDBC模板
|
||||
|
||||
### 安装验证
|
||||
|
||||
运行如下指令:
|
||||
|
||||
```Bash
|
||||
cd {install_directory}/examples/JDBC/JDBCConnectorChecker
|
||||
java -jar JDBCConnectorChecker.jar -host <fqdn>
|
||||
```
|
||||
|
||||
验证通过将打印出成功信息。
|
||||
|
||||
## Java连接器的使用
|
||||
|
||||
### 获取连接
|
||||
|
||||
|
@ -112,12 +181,12 @@ Connection conn = DriverManager.getConnection(jdbcUrl);
|
|||
**注意**:使用 JDBC-JNI 的 driver,taos-jdbcdriver 驱动包时需要依赖系统对应的本地函数库。
|
||||
|
||||
* libtaos.so
|
||||
在 linux 系统中成功安装 TDengine 后,依赖的本地函数库 libtaos.so 文件会被自动拷贝至 /usr/lib/libtaos.so,该目录包含在 Linux 自动扫描路径上,无需单独指定。
|
||||
在 Linux 系统中成功安装 TDengine 后,依赖的本地函数库 libtaos.so 文件会被自动拷贝至 /usr/lib/libtaos.so,该目录包含在 Linux 自动扫描路径上,无需单独指定。
|
||||
|
||||
* taos.dll
|
||||
在 windows 系统中安装完客户端之后,驱动包依赖的 taos.dll 文件会自动拷贝到系统默认搜索路径 C:/Windows/System32 下,同样无需要单独指定。
|
||||
在 Windows 系统中安装完客户端之后,驱动包依赖的 taos.dll 文件会自动拷贝到系统默认搜索路径 C:/Windows/System32 下,同样无需要单独指定。
|
||||
|
||||
> 在 windows 环境开发时需要安装 TDengine 对应的 [windows 客户端][14],Linux 服务器安装完 TDengine 之后默认已安装 client,也可以单独安装 [Linux 客户端][15] 连接远程 TDengine Server。
|
||||
> 在 Windows 环境开发时需要安装 TDengine 对应的 [windows 客户端][14],Linux 服务器安装完 TDengine 之后默认已安装 client,也可以单独安装 [Linux 客户端][15] 连接远程 TDengine Server。
|
||||
|
||||
JDBC-JNI 的使用请参见[视频教程](https://www.taosdata.com/blog/2020/11/11/1955.html)。
|
||||
|
||||
|
@ -132,8 +201,6 @@ url中的配置参数如下:
|
|||
* locale:客户端语言环境,默认值系统当前 locale。
|
||||
* timezone:客户端使用的时区,默认值为系统当前时区。
|
||||
|
||||
|
||||
|
||||
#### 指定URL和Properties获取连接
|
||||
|
||||
除了通过指定的 URL 获取连接,还可以使用 Properties 指定建立连接时的参数,如下所示:
|
||||
|
@ -162,12 +229,9 @@ properties 中的配置参数如下:
|
|||
* TSDBDriver.PROPERTY_KEY_LOCALE:客户端语言环境,默认值系统当前 locale。
|
||||
* TSDBDriver.PROPERTY_KEY_TIME_ZONE:客户端使用的时区,默认值为系统当前时区。
|
||||
|
||||
|
||||
|
||||
#### 使用客户端配置文件建立连接
|
||||
|
||||
当使用 JDBC-JNI 连接 TDengine 集群时,可以使用客户端配置文件,在客户端配置文件中指定集群的 firstEp、secondEp参数。
|
||||
如下所示:
|
||||
当使用 JDBC-JNI 连接 TDengine 集群时,可以使用客户端配置文件,在客户端配置文件中指定集群的 firstEp、secondEp参数。如下所示:
|
||||
|
||||
1. 在 Java 应用中不指定 hostname 和 port
|
||||
|
||||
|
@ -214,7 +278,7 @@ TDengine 中,只要保证 firstEp 和 secondEp 中一个节点有效,就可
|
|||
|
||||
例如:在 url 中指定了 password 为 taosdata,在 Properties 中指定了 password 为 taosdemo,那么,JDBC 会使用 url 中的 password 建立连接。
|
||||
|
||||
> 更多详细配置请参考[客户端配置][13]
|
||||
> 更多详细配置请参考[客户端配置](https://www.taosdata.com/cn/documentation/administrator/#client)
|
||||
|
||||
### 创建数据库和表
|
||||
|
||||
|
@ -242,8 +306,8 @@ int affectedRows = stmt.executeUpdate("insert into tb values(now, 23, 10.3) (now
|
|||
System.out.println("insert " + affectedRows + " rows.");
|
||||
```
|
||||
|
||||
> now 为系统内部函数,默认为服务器当前时间。
|
||||
> `now + 1s` 代表服务器当前时间往后加 1 秒,数字后面代表时间单位:a(毫秒), s(秒), m(分), h(小时), d(天),w(周), n(月), y(年)。
|
||||
> now 为系统内部函数,默认为客户端所在计算机当前时间。
|
||||
> `now + 1s` 代表客户端当前时间往后加 1 秒,数字后面代表时间单位:a(毫秒),s(秒),m(分),h(小时),d(天),w(周),n(月),y(年)。
|
||||
|
||||
### 查询数据
|
||||
|
||||
|
@ -418,8 +482,6 @@ conn.close();
|
|||
|
||||
> `注意务必要将 connection 进行关闭`,否则会出现连接泄露。
|
||||
|
||||
|
||||
|
||||
## 与连接池使用
|
||||
|
||||
**HikariCP**
|
||||
|
@ -464,7 +526,7 @@ conn.close();
|
|||
```
|
||||
|
||||
> 通过 HikariDataSource.getConnection() 获取连接后,使用完成后需要调用 close() 方法,实际上它并不会关闭连接,只是放回连接池中。
|
||||
> 更多 HikariCP 使用问题请查看[官方说明][5]
|
||||
> 更多 HikariCP 使用问题请查看[官方说明](https://github.com/brettwooldridge/HikariCP)。
|
||||
|
||||
**Druid**
|
||||
|
||||
|
@ -505,13 +567,13 @@ public static void main(String[] args) throws Exception {
|
|||
}
|
||||
```
|
||||
|
||||
> 更多 druid 使用问题请查看[官方说明][6]
|
||||
> 更多 druid 使用问题请查看[官方说明](https://github.com/alibaba/druid)。
|
||||
|
||||
**注意事项**
|
||||
**注意事项:**
|
||||
* TDengine `v1.6.4.1` 版本开始提供了一个专门用于心跳检测的函数 `select server_status()`,所以在使用连接池时推荐使用 `select server_status()` 进行 Validation Query。
|
||||
|
||||
如下所示,`select server_status()` 执行成功会返回 `1`。
|
||||
```shell
|
||||
```sql
|
||||
taos> select server_status();
|
||||
server_status()|
|
||||
================
|
||||
|
@ -519,47 +581,10 @@ server_status()|
|
|||
Query OK, 1 row(s) in set (0.000141s)
|
||||
```
|
||||
|
||||
## 在框架中使用
|
||||
|
||||
|
||||
## 与框架使用
|
||||
|
||||
* Spring JdbcTemplate 中使用 taos-jdbcdriver,可参考 [SpringJdbcTemplate][11]
|
||||
* Springboot + Mybatis 中使用,可参考 [springbootdemo][12]
|
||||
|
||||
|
||||
|
||||
## <a class="anchor" id="version"></a>TAOS-JDBCDriver 版本以及支持的 TDengine 版本和 JDK 版本
|
||||
|
||||
| taos-jdbcdriver 版本 | TDengine 版本 | JDK 版本 |
|
||||
| -------------------- | ----------------- | -------- |
|
||||
| 2.0.31 | 2.1.3.0 及以上 | 1.8.x |
|
||||
| 2.0.22 - 2.0.30 | 2.0.18.0 - 2.1.2.x | 1.8.x |
|
||||
| 2.0.12 - 2.0.21 | 2.0.8.0 - 2.0.17.x | 1.8.x |
|
||||
| 2.0.4 - 2.0.11 | 2.0.0.0 - 2.0.7.x | 1.8.x |
|
||||
| 1.0.3 | 1.6.1.x 及以上 | 1.8.x |
|
||||
| 1.0.2 | 1.6.1.x 及以上 | 1.8.x |
|
||||
| 1.0.1 | 1.6.1.x 及以上 | 1.8.x |
|
||||
|
||||
|
||||
|
||||
## TDengine DataType 和 Java DataType
|
||||
|
||||
TDengine 目前支持时间戳、数字、字符、布尔类型,与 Java 对应类型转换如下:
|
||||
|
||||
| TDengine DataType | Java DataType |
|
||||
| ----------------- | ------------------ |
|
||||
| TIMESTAMP | java.sql.Timestamp |
|
||||
| INT | java.lang.Integer |
|
||||
| BIGINT | java.lang.Long |
|
||||
| FLOAT | java.lang.Float |
|
||||
| DOUBLE | java.lang.Double |
|
||||
| SMALLINT | java.lang.Short |
|
||||
| TINYINT | java.lang.Byte |
|
||||
| BOOL | java.lang.Boolean |
|
||||
| BINARY | byte array |
|
||||
| NCHAR | java.lang.String |
|
||||
|
||||
|
||||
* Spring JdbcTemplate 中使用 taos-jdbcdriver,可参考 [SpringJdbcTemplate](https://github.com/taosdata/TDengine/tree/develop/tests/examples/JDBC/SpringJdbcTemplate)
|
||||
* Springboot + Mybatis 中使用,可参考 [springbootdemo](https://github.com/taosdata/TDengine/tree/develop/tests/examples/JDBC/springbootdemo)
|
||||
|
||||
## 常见问题
|
||||
|
||||
|
@ -567,7 +592,7 @@ TDengine 目前支持时间戳、数字、字符、布尔类型,与 Java 对
|
|||
|
||||
**原因**:程序没有找到依赖的本地函数库 taos。
|
||||
|
||||
**解决方法**:windows 下可以将 C:\TDengine\driver\taos.dll 拷贝到 C:\Windows\System32\ 目录下,linux 下将建立如下软链 `ln -s /usr/local/taos/driver/libtaos.so.x.x.x.x /usr/lib/libtaos.so` 即可。
|
||||
**解决方法**:Windows 下可以将 C:\TDengine\driver\taos.dll 拷贝到 C:\Windows\System32\ 目录下,Linux 下将建立如下软链 `ln -s /usr/local/taos/driver/libtaos.so.x.x.x.x /usr/lib/libtaos.so` 即可。
|
||||
|
||||
* java.lang.UnsatisfiedLinkError: taos.dll Can't load AMD 64 bit on a IA 32-bit platform
|
||||
|
||||
|
@ -575,21 +600,5 @@ TDengine 目前支持时间戳、数字、字符、布尔类型,与 Java 对
|
|||
|
||||
**解决方法**:重新安装 64 位 JDK。
|
||||
|
||||
* 其它问题请参考 [Issues][7]
|
||||
|
||||
[1]: https://search.maven.org/artifact/com.taosdata.jdbc/taos-jdbcdriver
|
||||
[2]: https://mvnrepository.com/artifact/com.taosdata.jdbc/taos-jdbcdriver
|
||||
[3]: https://github.com/taosdata/TDengine
|
||||
[4]: https://www.taosdata.com/blog/2019/12/03/jdbcdriver%e6%89%be%e4%b8%8d%e5%88%b0%e5%8a%a8%e6%80%81%e9%93%be%e6%8e%a5%e5%ba%93/
|
||||
[5]: https://github.com/brettwooldridge/HikariCP
|
||||
[6]: https://github.com/alibaba/druid
|
||||
[7]: https://github.com/taosdata/TDengine/issues
|
||||
[8]: https://search.maven.org/artifact/com.taosdata.jdbc/taos-jdbcdriver
|
||||
[9]: https://mvnrepository.com/artifact/com.taosdata.jdbc/taos-jdbcdriver
|
||||
[10]: https://maven.aliyun.com/mvn/search
|
||||
[11]: https://github.com/taosdata/TDengine/tree/develop/tests/examples/JDBC/SpringJdbcTemplate
|
||||
[12]: https://github.com/taosdata/TDengine/tree/develop/tests/examples/JDBC/springbootdemo
|
||||
[13]: https://www.taosdata.com/cn/documentation/administrator/#client
|
||||
[14]: https://www.taosdata.com/cn/all-downloads/#TDengine-Windows-Client
|
||||
[15]: https://www.taosdata.com/cn/getting-started/#%E5%AE%A2%E6%88%B7%E7%AB%AF
|
||||
* 其它问题请参考 [Issues](https://github.com/taosdata/TDengine/issues)
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ TDengine提供了丰富的应用程序开发接口,其中包括C/C++、Java、
|
|||
|
||||
* 在没有安装TDengine服务端软件的系统中使用连接器(除RESTful外)访问 TDengine 数据库,需要安装相应版本的客户端安装包来使应用驱动(Linux系统中文件名为libtaos.so,Windows系统中为taos.dll)被安装在系统中,否则会产生无法找到相应库文件的错误。
|
||||
* 所有执行 SQL 语句的 API,例如 C/C++ Connector 中的 `tao_query`、`taos_query_a`、`taos_subscribe` 等,以及其它语言中与它们对应的API,每次都只能执行一条 SQL 语句,如果实际参数中包含了多条语句,它们的行为是未定义的。
|
||||
* 升级到TDengine到2.0.8.0版本的用户,必须更新JDBC连接TDengine必须升级taos-jdbcdriver到2.0.12及以上。详细的版本依赖关系请参见 [taos-jdbcdriver 文档](https://www.taosdata.com/cn/documentation/connector/java#version)。
|
||||
* 升级 TDengine 到 2.0.8.0 版本的用户,必须更新 JDBC。连接 TDengine 必须升级 taos-jdbcdriver 到 2.0.12 及以上。详细的版本依赖关系请参见 [taos-jdbcdriver 文档](https://www.taosdata.com/cn/documentation/connector/java#version)。
|
||||
* 无论选用何种编程语言的连接器,2.0 及以上版本的 TDengine 推荐数据库应用的每个线程都建立一个独立的连接,或基于线程建立连接池,以避免连接内的“USE statement”状态量在线程之间相互干扰(但连接的查询和写入操作都是线程安全的)。
|
||||
|
||||
## <a class="anchor" id="driver"></a>安装连接器驱动步骤
|
||||
|
@ -32,7 +32,7 @@ TDengine提供了丰富的应用程序开发接口,其中包括C/C++、Java、
|
|||
|
||||
**Linux**
|
||||
|
||||
**1. 从[涛思官网](https://www.taosdata.com/cn/all-downloads/)下载**
|
||||
**1. 从[涛思官网](https://www.taosdata.com/cn/all-downloads/)下载<!-- REPLACE_OPEN_TO_ENTERPRISE__YOU_CAN_GET_CONNECTOR_DRIVER_FROM_TAOS -->:**
|
||||
|
||||
* X64硬件环境:TDengine-client-2.x.x.x-Linux-x64.tar.gz
|
||||
|
||||
|
@ -46,7 +46,7 @@ TDengine提供了丰富的应用程序开发接口,其中包括C/C++、Java、
|
|||
|
||||
`tar -xzvf TDengine-client-xxxxxxxxx.tar.gz`
|
||||
|
||||
其中xxxxxxx需要替换为实际版本的字符串。
|
||||
其中xxxxxxxxx需要替换为实际版本的字符串。
|
||||
|
||||
**3. 执行安装脚本**
|
||||
|
||||
|
@ -58,7 +58,7 @@ TDengine提供了丰富的应用程序开发接口,其中包括C/C++、Java、
|
|||
*connector*: 各种编程语言连接器(go/grafanaplugin/nodejs/python/JDBC)
|
||||
*examples*: 各种编程语言的示例程序(c/C#/go/JDBC/MATLAB/python/R)
|
||||
|
||||
运行install_client.sh进行安装
|
||||
运行install_client.sh进行安装。
|
||||
|
||||
**4. 配置taos.cfg**
|
||||
|
||||
|
@ -68,7 +68,7 @@ TDengine提供了丰富的应用程序开发接口,其中包括C/C++、Java、
|
|||
|
||||
**Windows x64/x86**
|
||||
|
||||
**1. 从[涛思官网](https://www.taosdata.com/cn/all-downloads/)下载 :**
|
||||
**1. 从[涛思官网](https://www.taosdata.com/cn/all-downloads/)下载<!-- REPLACE_OPEN_TO_ENTERPRISE__YOU_CAN_GET_CONNECTOR_DRIVER_WINDOWS_FROM_TAOS -->:**
|
||||
|
||||
* X64硬件环境:TDengine-client-2.X.X.X-Windows-x64.exe
|
||||
|
||||
|
@ -95,17 +95,16 @@ TDengine提供了丰富的应用程序开发接口,其中包括C/C++、Java、
|
|||
|
||||
**提示:**
|
||||
|
||||
**1. 如利用FQDN连接服务器,必须确认本机网络环境DNS已配置好,或在hosts文件中添加FQDN寻址记录,如编辑C:\Windows\system32\drivers\etc\hosts,添加如下的记录:** **192.168.1.99 h1.taos.com**
|
||||
1. **如利用FQDN连接服务器,必须确认本机网络环境DNS已配置好,或在hosts文件中添加FQDN寻址记录,如编辑C:\Windows\system32\drivers\etc\hosts,添加如下的记录:`192.168.1.99 h1.taos.com` **
|
||||
2.**卸载:运行unins000.exe可卸载TDengine应用驱动。**
|
||||
|
||||
**2.卸载:运行unins000.exe可卸载TDengine应用驱动。**
|
||||
|
||||
**安装验证**
|
||||
### 安装验证
|
||||
|
||||
以上安装和配置完成后,并确认TDengine服务已经正常启动运行,此时可以执行taos客户端进行登录。
|
||||
|
||||
**Linux环境:**
|
||||
|
||||
在linux shell下直接执行 taos,应该就能正常链接到tdegine服务,进入到taos shell界面,示例如下:
|
||||
在Linux shell下直接执行 taos,应该就能正常连接到TDegine服务,进入到taos shell界面,示例如下:
|
||||
|
||||
```mysql
|
||||
$ taos
|
||||
|
@ -146,7 +145,10 @@ taos>
|
|||
| **OS类型** | Linux | Win64 | Win32 | Linux | Linux |
|
||||
| **支持与否** | **支持** | **支持** | **支持** | **支持** | **开发中** |
|
||||
|
||||
C/C++的API类似于MySQL的C API。应用程序使用时,需要包含TDengine头文件 _taos.h_(安装后,位于 _/usr/local/taos/include_):
|
||||
C/C++的API类似于MySQL的C API。应用程序使用时,需要包含TDengine头文件 *taos.h*,里面列出了提供的API的函数原型。安装后,taos.h位于:
|
||||
|
||||
- Linux:`/usr/local/taos/include`
|
||||
- Windows:`C:\TDengine\include`
|
||||
|
||||
```C
|
||||
#include <taos.h>
|
||||
|
@ -156,9 +158,22 @@ C/C++的API类似于MySQL的C API。应用程序使用时,需要包含TDengine
|
|||
|
||||
* 在编译时需要链接TDengine动态库。Linux 为 *libtaos.so* ,安装后,位于 _/usr/local/taos/driver_。Windows为 taos.dll,安装后位于 *C:\TDengine*。
|
||||
* 如未特别说明,当API的返回值是整数时,_0_ 代表成功,其它是代表失败原因的错误码,当返回值是指针时, _NULL_ 表示失败。
|
||||
* 在 taoserror.h中有所有的错误码,以及对应的原因描述。
|
||||
|
||||
### 示例程序
|
||||
|
||||
使用C/C++连接器的示例代码请参见 https://github.com/taosdata/TDengine/tree/develop/tests/examples/c 。
|
||||
|
||||
示例程序源码也可以在安装目录下的 examples/c 路径下找到:
|
||||
|
||||
**apitest.c、asyncdemo.c、demo.c、prepare.c、stream.c、subscribe.c**
|
||||
|
||||
该目录下有makefile,在Linux环境下,直接执行make就可以编译得到执行文件。
|
||||
|
||||
在一台机器上启动TDengine服务,执行这些示例程序,按照提示输入TDengine服务的FQDN,就可以正常运行,并打印出信息。
|
||||
|
||||
**提示:**在ARM环境下编译时,请将makefile中的-msse4.2打开,这个选项只有在x64/x86硬件平台上才能支持。
|
||||
|
||||
### 基础API
|
||||
|
||||
基础API用于完成创建数据库连接等工作,为其它API的执行提供运行时环境。
|
||||
|
@ -173,7 +188,7 @@ C/C++的API类似于MySQL的C API。应用程序使用时,需要包含TDengine
|
|||
|
||||
- `int taos_options(TSDB_OPTION option, const void * arg, ...)`
|
||||
|
||||
设置客户端选项,目前只支持时区设置(_TSDB_OPTION_TIMEZONE_)和编码设置(_TSDB_OPTION_LOCALE_)。时区和编码默认为操作系统当前设置。
|
||||
设置客户端选项,目前支持区域设置(`TSDB_OPTION_LOCALE`)、字符集设置(`TSDB_OPTION_CHARSET`)、时区设置(`TSDB_OPTION_TIMEZONE`)、配置文件路径设置(`TSDB_OPTION_CONFIGDIR`)。区域设置、字符集、时区默认为操作系统当前设置。
|
||||
|
||||
- `char *taos_get_client_info()`
|
||||
|
||||
|
@ -187,7 +202,7 @@ C/C++的API类似于MySQL的C API。应用程序使用时,需要包含TDengine
|
|||
- user:用户名
|
||||
- pass:密码
|
||||
- db:数据库名字,如果用户没有提供,也可以正常连接,用户可以通过该连接创建新的数据库,如果用户提供了数据库名字,则说明该数据库用户已经创建好,缺省使用该数据库
|
||||
- port:端口号
|
||||
- port:TDengine管理主节点的端口号
|
||||
|
||||
返回值为空表示失败。应用程序需要保存返回的参数,以便后续API调用。
|
||||
|
||||
|
@ -201,7 +216,7 @@ C/C++的API类似于MySQL的C API。应用程序使用时,需要包含TDengine
|
|||
|
||||
- `void taos_close(TAOS *taos)`
|
||||
|
||||
关闭连接, 其中`taos`是`taos_connect`函数返回的指针。
|
||||
关闭连接,其中`taos`是`taos_connect`函数返回的指针。
|
||||
|
||||
### 同步查询API
|
||||
|
||||
|
@ -213,7 +228,7 @@ C/C++的API类似于MySQL的C API。应用程序使用时,需要包含TDengine
|
|||
|
||||
- `int taos_result_precision(TAOS_RES *res)`
|
||||
|
||||
返回结果集时间戳字段的精度,`0` 代表毫秒,`1` 代表微秒。
|
||||
返回结果集时间戳字段的精度,`0` 代表毫秒,`1` 代表微秒,`2` 代表纳秒。
|
||||
|
||||
- `TAOS_ROW taos_fetch_row(TAOS_RES *res)`
|
||||
|
||||
|
@ -237,13 +252,13 @@ C/C++的API类似于MySQL的C API。应用程序使用时,需要包含TDengine
|
|||
|
||||
- `TAOS_FIELD *taos_fetch_fields(TAOS_RES *res)`
|
||||
|
||||
获取查询结果集每列数据的属性(数据类型、名字、字节数),与taos_num_fileds配合使用,可用来解析`taos_fetch_row`返回的一个元组(一行)的数据。 `TAOS_FIELD` 的结构如下:
|
||||
获取查询结果集每列数据的属性(列的名称、列的数据类型、列的长度),与taos_num_fileds配合使用,可用来解析`taos_fetch_row`返回的一个元组(一行)的数据。 `TAOS_FIELD` 的结构如下:
|
||||
|
||||
```c
|
||||
typedef struct taosField {
|
||||
char name[65]; // 列名
|
||||
uint8_t type; // 数据类型
|
||||
int16_t bytes; // 字节数
|
||||
int16_t bytes; // 长度,单位是字节
|
||||
} TAOS_FIELD;
|
||||
```
|
||||
|
||||
|
@ -271,7 +286,7 @@ typedef struct taosField {
|
|||
|
||||
异步API都需要应用提供相应的回调函数,回调函数参数设置如下:前两个参数都是一致的,第三个参数依不同的API而定。第一个参数param是应用调用异步API时提供给系统的,用于回调时,应用能够找回具体操作的上下文,依具体实现而定。第二个参数是SQL操作的结果集,如果为空,比如insert操作,表示没有记录返回,如果不为空,比如select操作,表示有记录返回。
|
||||
|
||||
异步API对于使用者的要求相对较高,用户可根据具体应用场景选择性使用。下面是三个重要的异步API:
|
||||
异步API对于使用者的要求相对较高,用户可根据具体应用场景选择性使用。下面是两个重要的异步API:
|
||||
|
||||
- `void taos_query_a(TAOS *taos, const char *sql, void (*fp)(void *param, TAOS_RES *, int code), void *param);`
|
||||
|
||||
|
@ -392,11 +407,11 @@ TDengine提供时间驱动的实时流式计算API。可以每隔一指定的时
|
|||
- `TAOS_STREAM *taos_open_stream(TAOS *taos, const char *sql, void (*fp)(void *param, TAOS_RES *, TAOS_ROW row), int64_t stime, void *param, void (*callback)(void *))`
|
||||
|
||||
该API用来创建数据流,其中:
|
||||
* taos:已经建立好的数据库连接
|
||||
* sql:SQL查询语句(仅能使用查询语句)
|
||||
* taos:已经建立好的数据库连接。
|
||||
* sql:SQL查询语句(仅能使用查询语句)。
|
||||
* fp:用户定义的回调函数指针,每次流式计算完成后,TDengine将查询的结果(TAOS_ROW)、查询状态(TAOS_RES)、用户定义参数(PARAM)传递给回调函数,在回调函数内,用户可以使用taos_num_fields获取结果集列数,taos_fetch_fields获取结果集每列数据的类型。
|
||||
* stime:是流式计算开始的时间。如果是“64位整数最小值”,表示从现在开始;如果不为“64位整数最小值”,表示从指定的时间开始计算(UTC时间从1970/1/1算起的毫秒数)。
|
||||
* param:是应用提供的用于回调的一个参数,回调时,提供给应用
|
||||
* param:是应用提供的用于回调的一个参数,回调时,提供给应用。
|
||||
* callback: 第二个回调函数,会在连续查询自动停止时被调用。
|
||||
|
||||
返回值为NULL,表示创建失败;返回值不为空,表示成功。
|
||||
|
@ -440,18 +455,29 @@ TDengine提供时间驱动的实时流式计算API。可以每隔一指定的时
|
|||
|
||||
取消订阅。 如参数 `keepProgress` 不为0,API会保留订阅的进度信息,后续调用 `taos_subscribe` 时可以基于此进度继续;否则将删除进度信息,后续只能重新开始读取数据。
|
||||
|
||||
<!-- REPLACE_OPEN_TO_ENTERPRISE__JAVA_CONNECTOR_DOC -->
|
||||
|
||||
## <a class="anchor" id="python"></a>Python Connector
|
||||
|
||||
Python连接器的使用参见[视频教程](https://www.taosdata.com/blog/2020/11/11/1963.html)
|
||||
|
||||
### 安装准备
|
||||
* 应用驱动安装请参考[安装连接器驱动步骤](https://www.taosdata.com/cn/documentation/connector#driver)。
|
||||
* 已安装python 2.7 or >= 3.4
|
||||
* 已安装pip 或 pip3
|
||||
**安装**:参见下面具体步骤
|
||||
|
||||
### Python客户端安装
|
||||
**示例程序**:位于install_directory/examples/python
|
||||
|
||||
#### Linux
|
||||
### 安装
|
||||
|
||||
Python连接器支持的系统有:Linux 64/Windows x64
|
||||
|
||||
安装前准备:
|
||||
|
||||
- 已安装好TDengine应用驱动,请参考[安装连接器驱动步骤](https://www.taosdata.com/cn/documentation/connector#driver)
|
||||
- 已安装python 2.7 or >= 3.4
|
||||
- 已安装pip
|
||||
|
||||
### Python连接器安装
|
||||
|
||||
**Linux**
|
||||
|
||||
用户可以在源代码的src/connector/python(或者tar.gz的/connector/python)文件夹下找到connector安装包。用户可以通过pip命令安装:
|
||||
|
||||
|
@ -461,9 +487,10 @@ Python连接器的使用参见[视频教程](https://www.taosdata.com/blog/2020/
|
|||
|
||||
`pip3 install src/connector/python/`
|
||||
|
||||
#### Windows
|
||||
在已安装Windows TDengine 客户端的情况下, 将文件"C:\TDengine\driver\taos.dll" 拷贝到 "C:\windows\system32" 目录下, 然后进入Windwos <em>cmd</em> 命令行界面
|
||||
```cmd
|
||||
**Windows**
|
||||
|
||||
在已安装Windows TDengine 客户端的情况下, 将文件"C:\TDengine\driver\taos.dll" 拷贝到 "C:\Windows\system32" 目录下, 然后进入Windows *cmd* 命令行界面
|
||||
```bash
|
||||
cd C:\TDengine\connector\python
|
||||
python -m pip install .
|
||||
```
|
||||
|
@ -471,7 +498,37 @@ python -m pip install .
|
|||
* 如果机器上没有pip命令,用户可将src/connector/python下的taos文件夹拷贝到应用程序的目录使用。
|
||||
对于windows 客户端,安装TDengine windows 客户端后,将C:\TDengine\driver\taos.dll拷贝到C:\windows\system32目录下即可。
|
||||
|
||||
### 使用
|
||||
### 示例程序
|
||||
|
||||
示例程序源码位于install_directory/examples/Python,有:
|
||||
**read_example.py Python示例源程序**
|
||||
|
||||
用户可以参考read_example.py这个程序来设计用户自己的写入、查询程序。
|
||||
|
||||
在安装了对应的应用驱动后,通过import taos引入taos类。主要步骤如下:
|
||||
|
||||
- 通过taos.connect获取TDengineConnection对象,这个对象可以一个程序只申请一个,在多线程中共享。
|
||||
|
||||
- 通过TDengineConnection对象的 .cursor()方法获取一个新的游标对象,这个游标对象必须保证每个线程独享。
|
||||
|
||||
- 通过游标对象的execute()方法,执行写入或查询的SQL语句。
|
||||
|
||||
- 如果执行的是写入语句,execute返回的是成功写入的行数信息affected rows。
|
||||
|
||||
- 如果执行的是查询语句,则execute执行成功后,需要通过fetchall方法去拉取结果集。 具体方法可以参考示例代码。
|
||||
|
||||
### 安装验证
|
||||
|
||||
运行如下指令:
|
||||
|
||||
```bash
|
||||
cd {install_directory}/examples/python/PYTHONConnectorChecker/`
|
||||
python3 PythonChecker.py -host <fqdn>
|
||||
```
|
||||
|
||||
验证通过将打印出成功信息。
|
||||
|
||||
### Python连接器的使用
|
||||
|
||||
#### 代码示例
|
||||
|
||||
|
@ -486,7 +543,7 @@ import taos
|
|||
conn = taos.connect(host="127.0.0.1", user="root", password="taosdata", config="/etc/taos")
|
||||
c1 = conn.cursor()
|
||||
```
|
||||
* <em>host</em> 是TDengine 服务端所有IP, <em>config</em> 为客户端配置文件所在目录
|
||||
* *host* 是TDengine 服务端所有IP, *config* 为客户端配置文件所在目录
|
||||
|
||||
* 写入数据
|
||||
|
||||
|
@ -588,8 +645,8 @@ conn.close()
|
|||
|
||||
- 通过taos.connect获取TDengineConnection对象,这个对象可以一个程序只申请一个,在多线程中共享。
|
||||
- 通过TDengineConnection对象的 .cursor()方法获取一个新的游标对象,这个游标对象必须保证每个线程独享。
|
||||
- 通过游标对象的execute()方法,执行写入或查询的SQL语句
|
||||
- 如果执行的是写入语句,execute返回的是成功写入的行数信息affected rows
|
||||
- 通过游标对象的execute()方法,执行写入或查询的SQL语句。
|
||||
- 如果执行的是写入语句,execute返回的是成功写入的行数信息affected rows。
|
||||
- 如果执行的是查询语句,则execute执行成功后,需要通过fetchall方法去拉取结果集。
|
||||
具体方法可以参考示例代码。
|
||||
|
||||
|
@ -599,18 +656,46 @@ conn.close()
|
|||
|
||||
注意:与标准连接器的一个区别是,RESTful 接口是无状态的,因此 `USE db_name` 指令没有效果,所有对表名、超级表名的引用都需要指定数据库名前缀。
|
||||
|
||||
### HTTP请求格式
|
||||
### 安装
|
||||
|
||||
RESTful接口不依赖于任何TDengine的库,因此客户端不需要安装任何TDengine的库,只要客户端的开发语言支持HTTP协议即可。
|
||||
|
||||
### 验证
|
||||
|
||||
在已经安装TDengine服务器端的情况下,可以按照如下方式进行验证。
|
||||
|
||||
下面以Ubuntu环境中使用curl工具(确认已经安装)来验证RESTful接口的正常。
|
||||
|
||||
下面示例是列出所有的数据库,请把h1.taosdata.com和6041(缺省值)替换为实际运行的TDengine服务fqdn和端口号:
|
||||
```html
|
||||
curl -H 'Authorization: Basic cm9vdDp0YW9zZGF0YQ==' -d 'show databases;' h1.taosdata.com:6041/rest/sql
|
||||
```
|
||||
返回值结果如下表示验证通过:
|
||||
```json
|
||||
{
|
||||
"status": "succ",
|
||||
"head": ["name","created_time","ntables","vgroups","replica","quorum","days","keep1,keep2,keep(D)","cache(MB)","blocks","minrows","maxrows","wallevel","fsync","comp","precision","status"],
|
||||
"data": [
|
||||
["log","2020-09-02 17:23:00.039",4,1,1,1,10,"30,30,30",1,3,100,4096,1,3000,2,"us","ready"],
|
||||
],
|
||||
"rows": 1
|
||||
}
|
||||
```
|
||||
|
||||
### RESTful连接器的使用
|
||||
|
||||
#### HTTP请求格式
|
||||
|
||||
```
|
||||
http://<ip>:<PORT>/rest/sql
|
||||
http://<fqdn>:<port>/rest/sql
|
||||
```
|
||||
|
||||
参数说明:
|
||||
|
||||
- IP: 集群中的任一台主机
|
||||
- PORT: 配置文件中httpPort配置项,缺省为6041
|
||||
- fqnd: 集群中的任一台主机FQDN或IP地址
|
||||
- port: 配置文件中httpPort配置项,缺省为6041
|
||||
|
||||
例如:http://192.168.0.1:6041/rest/sql 是指向IP地址为192.168.0.1的URL.
|
||||
例如:http://h1.taos.com:6041/rest/sql 是指向地址为h1.taos.com:6041的url。
|
||||
|
||||
HTTP请求的Header里需带有身份认证信息,TDengine支持Basic认证与自定义认证两种机制,后续版本将提供标准安全的数字签名机制来做身份验证。
|
||||
|
||||
|
@ -662,8 +747,8 @@ curl -u username:password -d '<SQL>' <ip>:<PORT>/rest/sql
|
|||
说明:
|
||||
|
||||
- status: 告知操作结果是成功还是失败。
|
||||
- head: 表的定义,如果不返回结果集,则仅有一列“affected_rows”。(从 2.0.17 版本开始,建议不要依赖 head 返回值来判断数据列类型,而推荐使用 column_meta。在未来版本中,有可能会从返回值中去掉 head 这一项。)
|
||||
- column_meta: 从 2.0.17 版本开始,返回值中增加这一项来说明 data 里每一列的数据类型。具体每个列会用三个值来说明,分别为:列名、列类型、类型长度。例如`["current",6,4]`表示列名为“current”;列类型为 6,也即 float 类型;类型长度为 4,也即对应 4 个字节表示的 float。如果列类型为 binary 或 nchar,则类型长度表示该列最多可以保存的内容长度,而不是本次返回值中的具体数据长度。当列类型是 nchar 的时候,其类型长度表示可以保存的 unicode 字符数量,而不是 bytes。
|
||||
- head: 表的定义,如果不返回结果集,则仅有一列“affected_rows”。(从 2.0.17.0 版本开始,建议不要依赖 head 返回值来判断数据列类型,而推荐使用 column_meta。在未来版本中,有可能会从返回值中去掉 head 这一项。)
|
||||
- column_meta: 从 2.0.17.0 版本开始,返回值中增加这一项来说明 data 里每一列的数据类型。具体每个列会用三个值来说明,分别为:列名、列类型、类型长度。例如`["current",6,4]`表示列名为“current”;列类型为 6,也即 float 类型;类型长度为 4,也即对应 4 个字节表示的 float。如果列类型为 binary 或 nchar,则类型长度表示该列最多可以保存的内容长度,而不是本次返回值中的具体数据长度。当列类型是 nchar 的时候,其类型长度表示可以保存的 unicode 字符数量,而不是 bytes。
|
||||
- data: 具体返回的数据,一行一行的呈现,如果不返回结果集,那么就仅有[[affected_rows]]。data 中每一行的数据列顺序,与 column_meta 中描述数据列的顺序完全一致。
|
||||
- rows: 表明总共多少行数据。
|
||||
|
||||
|
@ -684,16 +769,16 @@ column_meta 中的列类型说明:
|
|||
HTTP请求中需要带有授权码`<TOKEN>`,用于身份识别。授权码通常由管理员提供,可简单的通过发送`HTTP GET`请求来获取授权码,操作如下:
|
||||
|
||||
```bash
|
||||
curl http://<ip>:6041/rest/login/<username>/<password>
|
||||
curl http://<fqnd>:<port>/rest/login/<username>/<password>
|
||||
```
|
||||
|
||||
其中,`ip`是TDengine数据库的IP地址,`username`为数据库用户名,`password`为数据库密码,返回值为`JSON`格式,各字段含义如下:
|
||||
其中,`fqdn`是TDengine数据库的fqdn或ip地址,port是TDengine服务的端口号,`username`为数据库用户名,`password`为数据库密码,返回值为`JSON`格式,各字段含义如下:
|
||||
|
||||
- status:请求结果的标志位
|
||||
|
||||
- code:返回值代码
|
||||
|
||||
- desc: 授权码
|
||||
- desc:授权码
|
||||
|
||||
获取授权码示例:
|
||||
|
||||
|
@ -799,13 +884,13 @@ HTTP请求URL采用`sqlutc`时,返回结果集的时间戳将采用UTC时间
|
|||
|
||||
### 重要配置项
|
||||
|
||||
下面仅列出一些与RESTful接口有关的配置参数,其他系统参数请看配置文件里的说明。注意:配置修改后,需要重启taosd服务才能生效
|
||||
下面仅列出一些与RESTful接口有关的配置参数,其他系统参数请看配置文件里的说明。(注意:配置修改后,需要重启taosd服务才能生效)
|
||||
|
||||
- 对外提供RESTful服务的端口号,默认绑定到 6041(实际取值是 serverPort + 11,因此可以通过修改 serverPort 参数的设置来修改)
|
||||
- httpMaxThreads: 启动的线程数量,默认为2(2.0.17版本开始,默认值改为CPU核数的一半向下取整)
|
||||
- httpMaxThreads: 启动的线程数量,默认为2(2.0.17.0版本开始,默认值改为CPU核数的一半向下取整)
|
||||
- restfulRowLimit: 返回结果集(JSON格式)的最大条数,默认值为10240
|
||||
- httpEnableCompress: 是否支持压缩,默认不支持,目前TDengine仅支持gzip压缩格式
|
||||
- httpDebugFlag: 日志开关,131:仅错误和报警信息,135:调试信息,143:非常详细的调试信息,默认131
|
||||
- httpDebugFlag: 日志开关,默认131。131:仅错误和报警信息,135:调试信息,143:非常详细的调试信息,默认131
|
||||
|
||||
## <a class="anchor" id="csharp"></a>CSharp Connector
|
||||
|
||||
|
@ -814,9 +899,15 @@ C#连接器支持的系统有:Linux 64/Windows x64/Windows x86
|
|||
### 安装准备
|
||||
|
||||
* 应用驱动安装请参考[安装连接器驱动步骤](https://www.taosdata.com/cn/documentation/connector#driver)。
|
||||
* .NET接口文件TDengineDrivercs.cs和参考程序示例TDengineTest.cs均位于Windows客户端install_directory/examples/C#目录下。
|
||||
* 接口文件TDengineDrivercs.cs和参考程序示例TDengineTest.cs均位于Windows客户端install_directory/examples/C#目录下。
|
||||
* 在Windows系统上,C#应用程序可以使用TDengine的原生C接口来执行所有数据库操作,后续版本将提供ORM(Dapper)框架驱动。
|
||||
|
||||
### 示例程序
|
||||
|
||||
示例程序源码位于install_directory/examples/C#,有:
|
||||
|
||||
TDengineTest.cs C#示例源程序
|
||||
|
||||
### 安装验证
|
||||
|
||||
运行install_directory/examples/C#/C#Checker/C#Checker.exe
|
||||
|
@ -829,17 +920,17 @@ C#Checker.exe -h <fqdn>
|
|||
|
||||
### C#连接器的使用
|
||||
|
||||
在Windows系统上,.NET应用程序可以使用TDengine的.NET接口来执行所有数据库的操作。使用.NET接口的步骤如下所示:
|
||||
在Windows系统上,C#应用程序可以使用TDengine的C#连接器接口来执行所有数据库的操作。使用的具体步骤如下所示:
|
||||
|
||||
1. 将.NET接口文件TDengineDrivercs.cs加入到应用程序所在.NET项目中。
|
||||
2. 用户可以参考TDengineTest.cs来定义数据库连接参数,以及如何执行数据插入、查询等操作;
|
||||
1. 将接口文件TDengineDrivercs.cs加入到应用程序所在的项目空间中。
|
||||
2. 用户可以参考TDengineTest.cs来定义数据库连接参数,以及如何执行数据插入、查询等操作。
|
||||
|
||||
此.NET接口需要用到taos.dll文件,所以在执行应用程序前,拷贝Windows客户端install_directory/driver目录中的taos.dll文件到.NET项目最后生成.exe可执行文件所在文件夹。之后运行exe文件,即可访问TDengine数据库并做插入、查询等操作。
|
||||
此接口需要用到taos.dll文件,所以在执行应用程序前,拷贝Windows客户端install_directory/driver目录中的taos.dll文件到项目最后生成.exe可执行文件所在的文件夹。之后运行exe文件,即可访问TDengine数据库并做插入、查询等操作。
|
||||
|
||||
**注意:**
|
||||
|
||||
1. TDengine V2.0.3.0之后同时支持32位和64位Windows系统,所以.NET项目在生成.exe文件时,“解决方案”/“项目”的“平台”请选择对应的“X86” 或“x64”。
|
||||
2. 此.NET接口目前已经在Visual Studio 2015/2017中验证过,其它VS版本尚待验证。
|
||||
1. TDengine V2.0.3.0之后同时支持32位和64位Windows系统,所以C#项目在生成.exe文件时,“解决方案”/“项目”的“平台”请选择对应的“X86” 或“x64”。
|
||||
2. 此接口目前已经在Visual Studio 2015/2017中验证过,其它VS版本尚待验证。
|
||||
|
||||
### 第三方驱动
|
||||
|
||||
|
@ -856,32 +947,52 @@ https://www.taosdata.com/blog/2020/11/02/1901.html
|
|||
|
||||
### 安装准备
|
||||
|
||||
* 应用驱动安装请参考[安装连接器驱动步骤](https://www.taosdata.com/cn/documentation/connector#driver)。
|
||||
Go连接器支持的系统有:
|
||||
|
||||
TDengine提供了GO驱动程序`taosSql`。 `taosSql`实现了GO语言的内置接口`database/sql/driver`。用户只需按如下方式引入包就可以在应用程序中访问TDengine, 详见`https://github.com/taosdata/driver-go/blob/develop/taosSql/driver_test.go`。
|
||||
| **CPU类型** | x64(64bit) | | | aarch64 | aarch32 |
|
||||
| --------------- | ------------ | -------- | -------- | -------- | ---------- |
|
||||
| **OS类型** | Linux | Win64 | Win32 | Linux | Linux |
|
||||
| **支持与否** | **支持** | **支持** | **支持** | **支持** | **开发中** |
|
||||
|
||||
安装前准备:
|
||||
|
||||
- 已安装好TDengine应用驱动,参考[安装连接器驱动步骤](https://www.taosdata.com/cn/documentation/connector#driver)。
|
||||
|
||||
### 示例程序
|
||||
|
||||
使用 Go 连接器的示例代码请参考 https://github.com/taosdata/TDengine/tree/develop/tests/examples/go 以及[视频教程](https://www.taosdata.com/blog/2020/11/11/1951.html)。
|
||||
|
||||
```Go
|
||||
示例程序源码也位于安装目录下的 examples/go/taosdemo.go 文件中。
|
||||
|
||||
**提示:建议Go版本是1.13及以上,并开启模块支持:**
|
||||
```sh
|
||||
go env -w GO111MODULE=on
|
||||
go env -w GOPROXY=https://goproxy.io,direct
|
||||
```
|
||||
在taosdemo.go所在目录下进行编译和执行:
|
||||
```sh
|
||||
go mod init *demo*
|
||||
go build ./demo -h fqdn -p serverPort
|
||||
```
|
||||
|
||||
### Go连接器的使用
|
||||
|
||||
TDengine提供了GO驱动程序包`taosSql`.`taosSql`实现了GO语言的内置接口`database/sql/driver`。用户只需按如下方式引入包就可以在应用程序中访问TDengine。
|
||||
```go
|
||||
import (
|
||||
"database/sql"
|
||||
_ "github.com/taosdata/driver-go/taosSql"
|
||||
"database/sql"
|
||||
_ "github.com/taosdata/driver-go/taosSql"
|
||||
)
|
||||
```
|
||||
**建议使用Go版本1.13或以上,并开启模块支持:**
|
||||
|
||||
```bash
|
||||
go env -w GO111MODULE=on
|
||||
go env -w GOPROXY=https://goproxy.io,direct
|
||||
```
|
||||
**提示**:下划线与双引号之间必须有一个空格。
|
||||
|
||||
### 常用API
|
||||
|
||||
- `sql.Open(DRIVER_NAME string, dataSourceName string) *DB`
|
||||
|
||||
该API用来打开DB,返回一个类型为\*DB的对象,一般情况下,DRIVER_NAME设置为字符串`taosSql`, dataSourceName设置为字符串`user:password@/tcp(host:port)/dbname`,如果客户想要用多个goroutine并发访问TDengine, 那么需要在各个goroutine中分别创建一个sql.Open对象并用之访问TDengine
|
||||
该API用来打开DB,返回一个类型为\*DB的对象,一般情况下,DRIVER_NAME设置为字符串`taosSql`,dataSourceName设置为字符串`user:password@/tcp(host:port)/dbname`,如果客户想要用多个goroutine并发访问TDengine, 那么需要在各个goroutine中分别创建一个sql.Open对象并用之访问TDengine
|
||||
|
||||
**注意**: 该API成功创建的时候,并没有做权限等检查,只有在真正执行Query或者Exec的时候才能真正的去创建连接,并同时检查user/password/host/port是不是合法。 另外,由于整个驱动程序大部分实现都下沉到taosSql所依赖的libtaos中。所以,sql.Open本身特别轻量。
|
||||
**注意**: 该API成功创建的时候,并没有做权限等检查,只有在真正执行Query或者Exec的时候才能真正的去创建连接,并同时检查user/password/host/port是不是合法。另外,由于整个驱动程序大部分实现都下沉到taosSql所依赖的libtaos动态库中。所以,sql.Open本身特别轻量。
|
||||
|
||||
- `func (db *DB) Exec(query string, args ...interface{}) (Result, error)`
|
||||
|
||||
|
@ -920,7 +1031,7 @@ Node.js连接器支持的系统有:
|
|||
| **OS类型** | Linux | Win64 | Win32 | Linux | Linux |
|
||||
| **支持与否** | **支持** | **支持** | **支持** | **支持** | **支持** |
|
||||
|
||||
Node.js连接器的使用参见[视频教程](https://www.taosdata.com/blog/2020/11/11/1957.html)
|
||||
Node.js连接器的使用参见[视频教程](https://www.taosdata.com/blog/2020/11/11/1957.html)。
|
||||
|
||||
### 安装准备
|
||||
|
||||
|
@ -930,14 +1041,14 @@ Node.js连接器的使用参见[视频教程](https://www.taosdata.com/blog/2020
|
|||
|
||||
用户可以通过[npm](https://www.npmjs.com/)来进行安装,也可以通过源代码*src/connector/nodejs/* 来进行安装。具体安装步骤如下:
|
||||
|
||||
首先,通过[npm](https://www.npmjs.com/)安装node.js 连接器.
|
||||
首先,通过[npm](https://www.npmjs.com/)安装node.js 连接器。
|
||||
|
||||
```bash
|
||||
npm install td2.0-connector
|
||||
```
|
||||
我们建议用户使用npm 安装node.js连接器。如果您没有安装npm, 可以将*src/connector/nodejs/*拷贝到您的nodejs 项目目录下
|
||||
我们建议用户使用npm 安装node.js连接器。如果您没有安装npm,可以将*src/connector/nodejs/*拷贝到您的nodejs 项目目录下。
|
||||
|
||||
我们使用[node-gyp](https://github.com/nodejs/node-gyp)和TDengine服务端进行交互。安装node.js 连接器之前,还需安装以下软件:
|
||||
我们使用[node-gyp](https://github.com/nodejs/node-gyp)和TDengine服务端进行交互。安装node.js连接器之前,还需要根据具体操作系统来安装下文提到的一些依赖工具。
|
||||
|
||||
### Linux
|
||||
|
||||
|
@ -950,19 +1061,19 @@ npm install td2.0-connector
|
|||
|
||||
#### 安装方法1
|
||||
|
||||
使用微软的[windows-build-tools](https://github.com/felixrieseberg/windows-build-tools)在`cmd` 命令行界面执行`npm install --global --production windows-build-tools` 即可安装所有的必备工具
|
||||
使用微软的[windows-build-tools](https://github.com/felixrieseberg/windows-build-tools)在`cmd` 命令行界面执行`npm install --global --production windows-build-tools` 即可安装所有的必备工具。
|
||||
|
||||
#### 安装方法2
|
||||
|
||||
手动安装以下工具:
|
||||
手动安装以下工具:
|
||||
|
||||
- 安装Visual Studio相关:[Visual Studio Build 工具](https://visualstudio.microsoft.com/thank-you-downloading-visual-studio/?sku=BuildTools) 或者 [Visual Studio 2017 Community](https://visualstudio.microsoft.com/pl/thank-you-downloading-visual-studio/?sku=Community)
|
||||
- 安装 [Python](https://www.python.org/downloads/) 2.7(`v3.x.x` 暂不支持) 并执行 `npm config set python python2.7`
|
||||
- 进入`cmd`命令行界面, `npm config set msvs_version 2017`
|
||||
- 安装 [Python](https://www.python.org/downloads/) 2.7(`v3.x.x` 暂不支持) 并执行 `npm config set python python2.7`
|
||||
- 进入`cmd`命令行界面,`npm config set msvs_version 2017`
|
||||
|
||||
如果以上步骤不能成功执行, 可以参考微软的node.js用户手册[Microsoft's Node.js Guidelines for Windows](https://github.com/Microsoft/nodejs-guidelines/blob/master/windows-environment.md#compiling-native-addon-modules)
|
||||
如果以上步骤不能成功执行,可以参考微软的node.js用户手册[Microsoft's Node.js Guidelines for Windows](https://github.com/Microsoft/nodejs-guidelines/blob/master/windows-environment.md#compiling-native-addon-modules)。
|
||||
|
||||
如果在Windows 10 ARM 上使用ARM64 Node.js, 还需添加 "Visual C++ compilers and libraries for ARM64" 和 "Visual C++ ATL for ARM64".
|
||||
如果在Windows 10 ARM 上使用ARM64 Node.js,还需添加 "Visual C++ compilers and libraries for ARM64" 和 "Visual C++ ATL for ARM64"。
|
||||
|
||||
### 示例程序
|
||||
|
||||
|
@ -979,7 +1090,7 @@ Node-example-raw.js
|
|||
|
||||
1. 新建安装验证目录,例如:`~/tdengine-test`,拷贝github上nodejsChecker.js源程序。下载地址:(https://github.com/taosdata/TDengine/tree/develop/tests/examples/nodejs/nodejsChecker.js)。
|
||||
|
||||
2. 在命令中执行以下命令:
|
||||
2. 在命令行中执行以下命令:
|
||||
|
||||
```bash
|
||||
npm init -y
|
||||
|
@ -991,23 +1102,19 @@ node nodejsChecker.js host=localhost
|
|||
|
||||
### Node.js连接器的使用
|
||||
|
||||
以下是node.js 连接器的一些基本使用方法,详细的使用方法可参考[TDengine Node.js connector](http://docs.taosdata.com/node)
|
||||
以下是Node.js 连接器的一些基本使用方法,详细的使用方法可参考[TDengine Node.js connector](http://docs.taosdata.com/node)。
|
||||
|
||||
#### 建立连接
|
||||
|
||||
使用node.js连接器时,必须先<em>require</em> `td2.0-connector`,然后使用 `taos.connect` 函数。`taos.connect` 函数必须提供的参数是`host`,其它参数在没有提供的情况下会使用如下的默认值。最后需要初始化`cursor` 来和TDengine服务端通信
|
||||
使用node.js连接器时,必须先`require td2.0-connector`,然后使用 `taos.connect` 函数建立到服务端的连接。例如如下代码:
|
||||
|
||||
```javascript
|
||||
const taos = require('td2.0-connector');
|
||||
var conn = taos.connect({host:"127.0.0.1", user:"root", password:"taosdata", config:"/etc/taos",port:0})
|
||||
var conn = taos.connect({host:"taosdemo.com", user:"root", password:"taosdata", config:"/etc/taos",port:6030})
|
||||
var cursor = conn.cursor(); // Initializing a new cursor
|
||||
```
|
||||
|
||||
关闭连接可执行
|
||||
|
||||
```javascript
|
||||
conn.close();
|
||||
```
|
||||
建立了一个到hostname为taosdemo.com,端口为6030(Tdengine的默认端口号)的连接。连接指定了用户名(root)和密码(taosdata)。taos.connect 函数必须提供的参数是`host`,其它参数在没有提供的情况下会使用如下的默认值。taos.connect返回了`cursor` 对象,使用cursor来执行sql语句。
|
||||
|
||||
#### 执行SQL和插入数据
|
||||
|
||||
|
@ -1037,7 +1144,7 @@ TDengine目前还不支持update和delete语句。
|
|||
var query = cursor.query('show databases;')
|
||||
```
|
||||
|
||||
查询的结果可以通过 `query.execute()` 函数获取并打印出来
|
||||
查询的结果可以通过 `query.execute()` 函数获取并打印出来。
|
||||
|
||||
```javascript
|
||||
var promise = query.execute();
|
||||
|
@ -1061,6 +1168,14 @@ promise.then(function(result) {
|
|||
result.pretty();
|
||||
})
|
||||
```
|
||||
|
||||
#### 关闭连接
|
||||
|
||||
在完成插入、查询等操作后,要关闭连接。代码如下:
|
||||
```js
|
||||
conn.close();
|
||||
```
|
||||
|
||||
#### 异步函数
|
||||
|
||||
异步查询数据库的操作和上面类似,只需要在`cursor.execute`, `TaosQuery.execute`等函数后面加上`_a`。
|
||||
|
@ -1077,6 +1192,6 @@ promise2.then(function(result) {
|
|||
|
||||
### 示例
|
||||
|
||||
[node-example.js](https://github.com/taosdata/TDengine/tree/master/tests/examples/nodejs/node-example.js)提供了一个使用NodeJS 连接器建表,插入天气数据并查询插入的数据的代码示例
|
||||
[node-example.js](https://github.com/taosdata/TDengine/tree/master/tests/examples/nodejs/node-example.js)提供了一个使用NodeJS 连接器建表,插入天气数据并查询插入的数据的代码示例。
|
||||
|
||||
[node-example-raw.js](https://github.com/taosdata/TDengine/tree/master/tests/examples/nodejs/node-example-raw.js)同样是一个使用NodeJS 连接器建表,插入天气数据并查询插入的数据的代码示例,但和上面不同的是,该示例只使用`cursor`.
|
||||
[node-example-raw.js](https://github.com/taosdata/TDengine/tree/master/tests/examples/nodejs/node-example-raw.js)同样是一个使用NodeJS 连接器建表,插入天气数据并查询插入的数据的代码示例,但和上面不同的是,该示例只使用`cursor`。
|
||||
|
|
|
@ -19,11 +19,18 @@ TDengine 的 Grafana 插件在安装包的 /usr/local/taos/connector/grafanaplug
|
|||
sudo cp -rf /usr/local/taos/connector/grafanaplugin /var/lib/grafana/plugins/tdengine
|
||||
```
|
||||
|
||||
Grafana 8.x 版本会对插件进行签名检查,因此还需要在 grafana.ini 文件中增加如下行,才能正确使用插件:
|
||||
```
|
||||
[plugins]
|
||||
enable_alpha = true
|
||||
allow_loading_unsigned_plugins = taosdata-tdengine-datasource
|
||||
```
|
||||
|
||||
### 使用 Grafana
|
||||
|
||||
#### 配置数据源
|
||||
|
||||
用户可以直接通过 localhost:3000 的网址,登录 Grafana 服务器(用户名/密码:admin/admin),通过左侧 `Configuration -> Data Sources` 可以添加数据源,如下图所示:
|
||||
用户可以直接通过 localhost:3000 的网址,登录 Grafana 服务器(用户名/密码:admin/admin),通过左侧 `Configuration -> Data Sources` 可以添加数据源,如下图所示:
|
||||
|
||||

|
||||
|
||||
|
@ -35,7 +42,7 @@ sudo cp -rf /usr/local/taos/connector/grafanaplugin /var/lib/grafana/plugins/tde
|
|||
|
||||

|
||||
|
||||
* Host: TDengine 集群的中任意一台服务器的 IP 地址与 TDengine RESTful 接口的端口号(6041),默认 http://localhost:6041
|
||||
* Host: TDengine 集群的中任意一台服务器的 IP 地址与 TDengine RESTful 接口的端口号(6041),默认 http://localhost:6041 。
|
||||
* User:TDengine 用户名。
|
||||
* Password:TDengine 用户密码。
|
||||
|
||||
|
@ -64,7 +71,7 @@ sudo cp -rf /usr/local/taos/connector/grafanaplugin /var/lib/grafana/plugins/tde
|
|||
|
||||
#### 导入 Dashboard
|
||||
|
||||
在 Grafana 插件目录 /usr/local/taos/connector/grafana/tdengine/dashboard/ 下提供了一个 `tdengine-grafana.json` 可导入的 dashboard。
|
||||
在 Grafana 插件目录 /usr/local/taos/connector/grafanaplugin/dashboard 下提供了一个 `tdengine-grafana.json` 可导入的 dashboard。
|
||||
|
||||
点击左侧 `Import` 按钮,并上传 `tdengine-grafana.json` 文件:
|
||||
|
||||
|
@ -140,13 +147,13 @@ conn<-dbConnect(drv,"jdbc:TSDB://192.168.0.1:0/?user=root&password=taosdata","ro
|
|||
|
||||
|
||||
- dbWriteTable(conn, "test", iris, overwrite=FALSE, append=TRUE):将数据框iris写入表test中,overwrite必须设置为false,append必须设为TRUE,且数据框iris要与表test的结构一致。
|
||||
- dbGetQuery(conn, "select count(*) from test"):查询语句
|
||||
- dbGetQuery(conn, "select count(*) from test"):查询语句。
|
||||
- dbSendUpdate(conn, "use db"):执行任何非查询sql语句。例如dbSendUpdate(conn, "use db"), 写入数据dbSendUpdate(conn, "insert into t1 values(now, 99)")等。
|
||||
- dbReadTable(conn, "test"):读取表test中数据
|
||||
- dbDisconnect(conn):关闭连接
|
||||
- dbRemoveTable(conn, "test"):删除表test
|
||||
- dbReadTable(conn, "test"):读取表test中数据。
|
||||
- dbDisconnect(conn):关闭连接。
|
||||
- dbRemoveTable(conn, "test"):删除表test。
|
||||
|
||||
TDengine客户端暂不支持如下函数:
|
||||
- dbExistsTable(conn, "test"):是否存在表test
|
||||
- dbListTables(conn):显示连接中的所有表
|
||||
- dbExistsTable(conn, "test"):是否存在表test。
|
||||
- dbListTables(conn):显示连接中的所有表。
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
# TDengine 集群安装、管理
|
||||
|
||||
多个TDengine服务器,也就是多个taosd的运行实例可以组成一个集群,以保证TDengine的高可靠运行,并提供水平扩展能力。要了解TDengine 2.0的集群管理,需要对集群的基本概念有所了解,请看TDengine 2.0整体架构一章。而且在安装集群之前,先请按照[《立即开始》](https://www.taosdata.com/cn/documentation/getting-started/)一章安装并体验单节点功能。
|
||||
多个TDengine服务器,也就是多个taosd的运行实例可以组成一个集群,以保证TDengine的高可靠运行,并提供水平扩展能力。要了解TDengine 2.0的集群管理,需要对集群的基本概念有所了解,请看《TDengine整体架构》一章。而且在安装集群之前,建议先按照[《立即开始》](https://www.taosdata.com/cn/documentation/getting-started/)一章安装并体验单节点功能。
|
||||
|
||||
集群的每个数据节点是由End Point来唯一标识的,End Point是由FQDN(Fully Qualified Domain Name)外加Port组成,比如 h1.taosdata.com:6030。一般FQDN就是服务器的hostname,可通过Linux命令`hostname -f`获取(如何配置FQDN,请参考:[一篇文章说清楚TDengine的FQDN](https://www.taosdata.com/blog/2020/09/11/1824.html))。端口是这个数据节点对外服务的端口号,缺省是6030,但可以通过taos.cfg里配置参数serverPort进行修改。一个物理节点可能配置了多个hostname, TDengine会自动获取第一个,但也可以通过taos.cfg里配置参数fqdn进行指定。如果习惯IP地址直接访问,可以将参数fqdn设置为本节点的IP地址。
|
||||
|
||||
|
@ -12,7 +12,7 @@ TDengine的集群管理极其简单,除添加和删除节点需要人工干预
|
|||
|
||||
**第零步**:规划集群所有物理节点的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.X的版本,或者装过其他版本的TDengine,请先将其删除,并清空所有数据(如果需要保留原有数据,请联系涛思交付团队进行旧版本升级、数据迁移),具体步骤请参考博客[《TDengine多种安装包的安装和卸载》](https://www.taosdata.com/blog/2019/08/09/566.html)。
|
||||
**注意1:**因为FQDN的信息会写进文件,如果之前没有配置或者更改FQDN,且启动了TDengine。请一定在确保数据无用或者备份的前提下,清理一下之前的数据(`rm -rf /var/lib/taos/*`);
|
||||
**注意2:**客户端也需要配置,确保它可以正确解析每个节点的FQDN配置,不管是通过DNS服务,还是 Host 文件。
|
||||
|
||||
|
@ -23,23 +23,23 @@ TDengine的集群管理极其简单,除添加和删除节点需要人工干预
|
|||
**第四步**:检查所有数据节点,以及应用程序所在物理节点的网络设置:
|
||||
|
||||
1. 每个物理节点上执行命令`hostname -f`,查看和确认所有节点的hostname是不相同的(应用驱动所在节点无需做此项检查);
|
||||
2. 每个物理节点上执行`ping host`, 其中host是其他物理节点的hostname, 看能否ping通其它物理节点; 如果不能ping通,需要检查网络设置, 或/etc/hosts文件(Windows系统默认路径为C:\Windows\system32\drivers\etc\hosts),或DNS的配置。如果无法ping通,是无法组成集群的;
|
||||
2. 每个物理节点上执行`ping host`,其中host是其他物理节点的hostname,看能否ping通其它物理节点;如果不能ping通,需要检查网络设置,或/etc/hosts文件(Windows系统默认路径为C:\Windows\system32\drivers\etc\hosts),或DNS的配置。如果无法ping通,是无法组成集群的;
|
||||
3. 从应用运行的物理节点,ping taosd运行的数据节点,如果无法ping通,应用是无法连接taosd的,请检查应用所在物理节点的DNS设置或hosts文件;
|
||||
4. 每个数据节点的End Point就是输出的hostname外加端口号,比如h1.taosdata.com:6030
|
||||
4. 每个数据节点的End Point就是输出的hostname外加端口号,比如`h1.taosdata.com:6030`。
|
||||
|
||||
**第五步**:修改TDengine的配置文件(所有节点的文件/etc/taos/taos.cfg都需要修改)。假设准备启动的第一个数据节点End Point为 h1.taosdata.com:6030, 其与集群配置相关参数如下:
|
||||
**第五步**:修改TDengine的配置文件(所有节点的文件/etc/taos/taos.cfg都需要修改)。假设准备启动的第一个数据节点End Point为 h1.taosdata.com:6030,其与集群配置相关参数如下:
|
||||
|
||||
```
|
||||
// firstEp 是每个数据节点首次启动后连接的第一个数据节点
|
||||
firstEp h1.taosdata.com:6030
|
||||
|
||||
// 必须配置为本数据节点的FQDN,如果本机只有一个hostname, 可注释掉本配置
|
||||
// 必须配置为本数据节点的FQDN,如果本机只有一个hostname, 可注释掉本项
|
||||
fqdn h1.taosdata.com
|
||||
|
||||
// 配置本数据节点的端口号,缺省是6030
|
||||
serverPort 6030
|
||||
|
||||
// 使用场景,请参考《Arbitrator的使用》的部分
|
||||
// 副本数为偶数的时候,需要配置,请参考《Arbitrator的使用》的部分
|
||||
arbitrator ha.taosdata.com:6042
|
||||
```
|
||||
|
||||
|
@ -53,7 +53,7 @@ arbitrator ha.taosdata.com:6042
|
|||
| 2 | mnodeEqualVnodeNum | 一个mnode等同于vnode消耗的个数 |
|
||||
| 3 | offlineThreshold | dnode离线阈值,超过该时间将导致Dnode离线 |
|
||||
| 4 | statusInterval | dnode向mnode报告状态时长 |
|
||||
| 5 | arbitrator | 系统中裁决器的end point |
|
||||
| 5 | arbitrator | 系统中裁决器的End Point |
|
||||
| 6 | timezone | 时区 |
|
||||
| 7 | balance | 是否启动负载均衡 |
|
||||
| 8 | maxTablesPerVnode | 每个vnode中能够创建的最大表个数 |
|
||||
|
@ -87,7 +87,7 @@ taos>
|
|||
|
||||
1. 按照[《立即开始》](https://www.taosdata.com/cn/documentation/getting-started/)一章的方法在每个物理节点启动taosd;(注意:每个物理节点都需要在 taos.cfg 文件中将 firstEP 参数配置为新集群首个节点的 End Point——在本例中是 h1.taos.com:6030)
|
||||
|
||||
2. 在第一个数据节点,使用CLI程序taos, 登录进TDengine系统, 执行命令:
|
||||
2. 在第一个数据节点,使用CLI程序taos,登录进TDengine系统,执行命令:
|
||||
|
||||
```
|
||||
CREATE DNODE "h2.taos.com:6030";
|
||||
|
@ -101,7 +101,7 @@ taos>
|
|||
SHOW DNODES;
|
||||
```
|
||||
|
||||
查看新节点是否被成功加入。如果该被加入的数据节点处于离线状态,请做两个检查
|
||||
查看新节点是否被成功加入。如果该被加入的数据节点处于离线状态,请做两个检查:
|
||||
|
||||
- 查看该数据节点的taosd是否正常工作,如果没有正常运行,需要先检查为什么
|
||||
- 查看该数据节点taosd日志文件taosdlog.0里前面几行日志(一般在/var/log/taos目录),看日志里输出的该数据节点fqdn以及端口号是否为刚添加的End Point。如果不一致,需要将正确的End Point添加进去。
|
||||
|
@ -121,7 +121,7 @@ taos>
|
|||
|
||||
### 添加数据节点
|
||||
|
||||
执行CLI程序taos, 使用root账号登录进系统, 执行:
|
||||
执行CLI程序taos,使用root账号登录进系统,执行:
|
||||
|
||||
```
|
||||
CREATE DNODE "fqdn:port";
|
||||
|
@ -131,13 +131,13 @@ CREATE DNODE "fqdn:port";
|
|||
|
||||
### 删除数据节点
|
||||
|
||||
执行CLI程序taos, 使用root账号登录进TDengine系统,执行:
|
||||
执行CLI程序taos,使用root账号登录进TDengine系统,执行:
|
||||
|
||||
```
|
||||
DROP DNODE "fqdn:port";
|
||||
```mysql
|
||||
DROP DNODE "fqdn:port | dnodeID";
|
||||
```
|
||||
|
||||
其中fqdn是被删除的节点的FQDN,port是其对外服务器的端口号
|
||||
通过"fqdn:port"或"dnodeID"来指定一个具体的节点都是可以的。其中fqdn是被删除的节点的FQDN,port是其对外服务器的端口号;dnodeID可以通过SHOW DNODES获得。
|
||||
|
||||
<font color=green>**【注意】**</font>
|
||||
|
||||
|
@ -147,25 +147,41 @@ DROP DNODE "fqdn:port";
|
|||
|
||||
- 一个数据节点被drop之后,其他节点都会感知到这个dnodeID的删除操作,任何集群中的节点都不会再接收此dnodeID的请求。
|
||||
|
||||
- dnodeID的是集群自动分配的,不得人工指定。它在生成时递增的,不会重复。
|
||||
- dnodeID是集群自动分配的,不得人工指定。它在生成时是递增的,不会重复。
|
||||
|
||||
### 手动迁移数据节点
|
||||
|
||||
手动将某个vnode迁移到指定的dnode。
|
||||
|
||||
执行CLI程序taos,使用root账号登录进TDengine系统,执行:
|
||||
|
||||
```mysql
|
||||
ALTER DNODE <source-dnodeId> BALANCE "VNODE:<vgId>-DNODE:<dest-dnodeId>";
|
||||
```
|
||||
|
||||
其中:source-dnodeId是源dnodeId,也就是待迁移的vnode所在的dnodeID;vgId可以通过SHOW VGROUPS获得,列表的第一列;dest-dnodeId是目标dnodeId。
|
||||
|
||||
<font color=green>**【注意】**</font>
|
||||
|
||||
- 只有在集群的自动负载均衡选项关闭时(balance设置为0),才允许手动迁移。
|
||||
- 只有处于正常工作状态的vnode才能被迁移:master/slave,当处于offline/unsynced/syncing状态时,是不能迁移的。
|
||||
- 迁移前,务必核实目标dnode的资源足够:CPU、内存、硬盘。
|
||||
|
||||
### 查看数据节点
|
||||
|
||||
执行CLI程序taos,使用root账号登录进TDengine系统,执行:
|
||||
|
||||
```
|
||||
执行CLI程序taos,使用root账号登录进TDengine系统,执行:
|
||||
```mysql
|
||||
SHOW DNODES;
|
||||
```
|
||||
|
||||
它将列出集群中所有的dnode,每个dnode的fqdn:port, 状态(ready, offline等),vnode数目,还未使用的vnode数目等信息。在添加或删除一个数据节点后,可以使用该命令查看。
|
||||
它将列出集群中所有的dnode,每个dnode的ID,end_point(fqdn:port),状态(ready, offline等),vnode数目,还未使用的vnode数目等信息。在添加或删除一个数据节点后,可以使用该命令查看。
|
||||
|
||||
### 查看虚拟节点组
|
||||
|
||||
为充分利用多核技术,并提供scalability,数据需要分片处理。因此TDengine会将一个DB的数据切分成多份,存放在多个vnode里。这些vnode可能分布在多个数据节点dnode里,这样就实现了水平扩展。一个vnode仅仅属于一个DB,但一个DB可以有多个vnode。vnode的是mnode根据当前系统资源的情况,自动进行分配的,无需任何人工干预。
|
||||
|
||||
执行CLI程序taos,使用root账号登录进TDengine系统,执行:
|
||||
|
||||
```
|
||||
执行CLI程序taos,使用root账号登录进TDengine系统,执行:
|
||||
```mysql
|
||||
SHOW VGROUPS;
|
||||
```
|
||||
|
||||
|
@ -173,9 +189,9 @@ SHOW VGROUPS;
|
|||
|
||||
TDengine通过多副本的机制来提供系统的高可用性,包括vnode和mnode的高可用性。
|
||||
|
||||
vnode的副本数是与DB关联的,一个集群里可以有多个DB,根据运营的需求,每个DB可以配置不同的副本数。创建数据库时,通过参数replica 指定副本数(缺省为1)。如果副本数为1,系统的可靠性无法保证,只要数据所在的节点宕机,就将无法提供服务。集群的节点数必须大于等于副本数,否则创建表时将返回错误“more dnodes are needed"。比如下面的命令将创建副本数为3的数据库demo:
|
||||
vnode的副本数是与DB关联的,一个集群里可以有多个DB,根据运营的需求,每个DB可以配置不同的副本数。创建数据库时,通过参数replica 指定副本数(缺省为1)。如果副本数为1,系统的可靠性无法保证,只要数据所在的节点宕机,就将无法提供服务。集群的节点数必须大于等于副本数,否则创建表时将返回错误"more dnodes are needed"。比如下面的命令将创建副本数为3的数据库demo:
|
||||
|
||||
```
|
||||
```mysql
|
||||
CREATE DATABASE demo replica 3;
|
||||
```
|
||||
|
||||
|
@ -183,20 +199,19 @@ CREATE DATABASE demo replica 3;
|
|||
|
||||
一个数据节点dnode里可能有多个DB的数据,因此一个dnode离线时,可能会影响到多个DB。如果一个vnode group里的一半或一半以上的vnode不工作,那么该vnode group就无法对外服务,无法插入或读取数据,这样会影响到它所属的DB的一部分表的读写操作。
|
||||
|
||||
因为vnode的引入,无法简单的给出结论:“集群中过半数据节点dnode工作,集群就应该工作”。但是对于简单的情形,很好下结论。比如副本数为3,只有三个dnode,那如果仅有一个节点不工作,整个集群还是可以正常工作的,但如果有两个数据节点不工作,那整个集群就无法正常工作了。
|
||||
因为vnode的引入,无法简单地给出结论:“集群中过半数据节点dnode工作,集群就应该工作”。但是对于简单的情形,很好下结论。比如副本数为3,只有三个dnode,那如果仅有一个节点不工作,整个集群还是可以正常工作的,但如果有两个数据节点不工作,那整个集群就无法正常工作了。
|
||||
|
||||
## <a class="anchor" id="mnode"></a>Mnode的高可用性
|
||||
|
||||
TDengine集群是由mnode (taosd的一个模块,管理节点) 负责管理的,为保证mnode的高可用,可以配置多个mnode副本,副本数由系统配置参数numOfMnodes决定,有效范围为1-3。为保证元数据的强一致性,mnode副本之间是通过同步的方式进行数据复制的。
|
||||
|
||||
一个集群有多个数据节点dnode, 但一个dnode至多运行一个mnode实例。多个dnode情况下,哪个dnode可以作为mnode呢?这是完全由系统根据整个系统资源情况,自动指定的。用户可通过CLI程序taos,在TDengine的console里,执行如下命令:
|
||||
一个集群有多个数据节点dnode,但一个dnode至多运行一个mnode实例。多个dnode情况下,哪个dnode可以作为mnode呢?这是完全由系统根据整个系统资源情况,自动指定的。用户可通过CLI程序taos,在TDengine的console里,执行如下命令:
|
||||
|
||||
```
|
||||
```mysql
|
||||
SHOW MNODES;
|
||||
```
|
||||
|
||||
来查看mnode列表,该列表将列出mnode所处的dnode的End Point和角色(master, slave, unsynced 或offline)。
|
||||
当集群中第一个数据节点启动时,该数据节点一定会运行一个mnode实例,否则该数据节点dnode无法正常工作,因为一个系统是必须有至少一个mnode的。如果numOfMnodes配置为2,启动第二个dnode时,该dnode也将运行一个mnode实例。
|
||||
来查看mnode列表,该列表将列出mnode所处的dnode的End Point和角色(master, slave, unsynced 或offline)。当集群中第一个数据节点启动时,该数据节点一定会运行一个mnode实例,否则该数据节点dnode无法正常工作,因为一个系统是必须有至少一个mnode的。如果numOfMnodes配置为2,启动第二个dnode时,该dnode也将运行一个mnode实例。
|
||||
|
||||
为保证mnode服务的高可用性,numOfMnodes必须设置为2或更大。因为mnode保存的元数据必须是强一致的,如果numOfMnodes大于2,复制参数quorum自动设为2,也就是说,至少要保证有两个副本写入数据成功,才通知客户端应用写入成功。
|
||||
|
||||
|
@ -210,7 +225,7 @@ SHOW MNODES;
|
|||
- 当一个数据节点从集群中移除时,系统将自动把该数据节点上的数据转移到其他数据节点,无需任何人工干预。
|
||||
- 如果一个数据节点过热(数据量过大),系统将自动进行负载均衡,将该数据节点的一些vnode自动挪到其他节点。
|
||||
|
||||
当上述三种情况发生时,系统将启动一各个数据节点的负载计算,从而决定如何挪动。
|
||||
当上述三种情况发生时,系统将启动各个数据节点的负载计算,从而决定如何挪动。
|
||||
|
||||
**【提示】负载均衡由参数balance控制,它决定是否启动自动负载均衡。**
|
||||
|
||||
|
@ -225,7 +240,7 @@ SHOW MNODES;
|
|||
|
||||
## <a class="anchor" id="arbitrator"></a>Arbitrator的使用
|
||||
|
||||
如果副本数为偶数,当一个 vnode group 里一半 vnode 不工作时,是无法从中选出 master 的。同理,一半 mnode 不工作时,是无法选出 mnode 的 master 的,因为存在“split brain”问题。为解决这个问题,TDengine 引入了 Arbitrator 的概念。Arbitrator 模拟一个 vnode 或 mnode 在工作,但只简单的负责网络连接,不处理任何数据插入或访问。只要包含 Arbitrator 在内,超过半数的 vnode 或 mnode 工作,那么该 vnode group 或 mnode 组就可以正常的提供数据插入或查询服务。比如对于副本数为 2 的情形,如果一个节点 A 离线,但另外一个节点 B 正常,而且能连接到 Arbitrator,那么节点 B 就能正常工作。
|
||||
如果副本数为偶数,当一个 vnode group 里一半或超过一半的 vnode 不工作时,是无法从中选出 master 的。同理,一半或超过一半的 mnode 不工作时,是无法选出 mnode 的 master 的,因为存在“split brain”问题。为解决这个问题,TDengine 引入了 Arbitrator 的概念。Arbitrator 模拟一个 vnode 或 mnode 在工作,但只简单的负责网络连接,不处理任何数据插入或访问。只要包含 Arbitrator 在内,超过半数的 vnode 或 mnode 工作,那么该 vnode group 或 mnode 组就可以正常的提供数据插入或查询服务。比如对于副本数为 2 的情形,如果一个节点 A 离线,但另外一个节点 B 正常,而且能连接到 Arbitrator,那么节点 B 就能正常工作。
|
||||
|
||||
总之,在目前版本下,TDengine 建议在双副本环境要配置 Arbitrator,以提升系统的可用性。
|
||||
|
||||
|
@ -235,3 +250,9 @@ Arbitrator 的执行程序名为 tarbitrator。该程序对系统资源几乎没
|
|||
3. 修改每个 taosd 实例的配置文件,在 taos.cfg 里将参数 arbitrator 设置为 tarbitrator 程序所对应的 End Point。(如果该参数配置了,当副本数为偶数时,系统将自动连接配置的 Arbitrator。如果副本数为奇数,即使配置了 Arbitrator,系统也不会去建立连接。)
|
||||
4. 在配置文件中配置了的 Arbitrator,会出现在 `SHOW DNODES;` 指令的返回结果中,对应的 role 列的值会是“arb”。
|
||||
|
||||
|
||||
查看集群 Arbitrator 的状态【2.0.14.0 以后支持】
|
||||
|
||||
```mysql
|
||||
SHOW DNODES;
|
||||
```
|
||||
|
|
|
@ -73,7 +73,7 @@ Raw DataSize = numOfTables * rowSizePerTable * rowsPerTable
|
|||
|
||||
因为 TDengine 具有很好的水平扩展能力,根据总量,再根据单个物理机或虚拟机的资源,就可以轻松决定需要购置多少台物理机或虚拟机了。
|
||||
|
||||
**立即计算 CPU、内存、存储,请参见:[资源估算方法](https://www.taosdata.com/config/config.html)**
|
||||
**立即计算 CPU、内存、存储,请参见:[资源估算方法](https://www.taosdata.com/config/config.html)。**
|
||||
|
||||
## <a class="anchor" id="tolerance"></a>容错和灾备
|
||||
|
||||
|
@ -230,7 +230,7 @@ taosd -C
|
|||
| 1 | days | 天 | 一个数据文件存储数据的时间跨度 | | 10 |
|
||||
| 2 | keep | 天 | (可通过 alter database 修改<!-- REPLACE_OPEN_TO_ENTERPRISE__KEEP_PARAM_DESCRIPTION_IN_PARAM_LIST -->)数据库中数据保留的天数。 | 3650 |
|
||||
| 3 | cache | MB | 内存块的大小 | | 16 |
|
||||
| 4 | blocks | | (可通过 alter database 修改)每个 VNODE(TSDB)中有多少个 cache 大小的内存块。因此一个 VNODE 使用的内存大小粗略为(cache * blocks)。 | | 4 |
|
||||
| 4 | blocks | | (可通过 alter database 修改)每个 VNODE(TSDB)中有多少个 cache 大小的内存块。因此一个 VNODE 使用的内存大小粗略为(cache * blocks)。 | | 6 |
|
||||
| 5 | quorum | | (可通过 alter database 修改)多副本环境下指令执行的确认数要求 | 1-2 | 1 |
|
||||
| 6 | minRows | | 文件块中记录的最小条数 | | 100 |
|
||||
| 7 | maxRows | | 文件块中记录的最大条数 | | 4096 |
|
||||
|
@ -238,7 +238,7 @@ taosd -C
|
|||
| 9 | walLevel | | (作为 database 的参数时名为 wal;在 taos.cfg 中作为参数时需要写作 walLevel)WAL级别 | 1:写wal,但不执行fsync;2:写wal, 而且执行fsync | 1 |
|
||||
| 10 | fsync | 毫秒 | 当wal设置为2时,执行fsync的周期。设置为0,表示每次写入,立即执行fsync。 | | 3000 |
|
||||
| 11 | replica | | (可通过 alter database 修改)副本个数 | 1-3 | 1 |
|
||||
| 12 | precision | | 时间戳精度标识(2.1.2.0 版本之前、2.0.20.7 版本之前在 taos.cfg 文件中不支持此参数。) | ms 表示毫秒,us 表示微秒 | ms |
|
||||
| 12 | precision | | 时间戳精度标识(2.1.2.0 版本之前、2.0.20.7 版本之前在 taos.cfg 文件中不支持此参数。)(从 2.1.5.0 版本开始,新增对纳秒时间精度的支持) | ms 表示毫秒,us 表示微秒,ns 表示纳秒 | ms |
|
||||
| 13 | update | | 是否允许更新 | 0:不允许;1:允许 | 0 |
|
||||
| 14 | cacheLast | | (可通过 alter database 修改)是否在内存中缓存子表的最近数据(从 2.1.2.0 版本开始此参数支持 0~3 的取值范围,在此之前取值只能是 [0, 1];而 2.0.11.0 之前的版本在 SQL 指令中不支持此参数。)(2.1.2.0 版本之前、2.0.20.7 版本之前在 taos.cfg 文件中不支持此参数。) | 0:关闭;1:缓存子表最近一行数据;2:缓存子表每一列的最近的非NULL值;3:同时打开缓存最近行和列功能 | 0 |
|
||||
|
||||
|
@ -433,7 +433,7 @@ SHOW USERS;
|
|||
|
||||
显示所有用户
|
||||
|
||||
**注意:**SQL 语法中,< >表示需要用户输入的部分,但请不要输入< >本身
|
||||
**注意:**SQL 语法中,< >表示需要用户输入的部分,但请不要输入< >本身。
|
||||
|
||||
## <a class="anchor" id="import"></a>数据导入
|
||||
|
||||
|
@ -445,7 +445,7 @@ TDengine的shell支持source filename命令,用于批量运行文件中的SQL
|
|||
|
||||
**按数据文件导入**
|
||||
|
||||
TDengine也支持在shell对已存在的表从CSV文件中进行数据导入。CSV文件只属于一张表且CSV文件中的数据格式需与要导入表的结构相同, 在导入的时候,其语法如下
|
||||
TDengine也支持在shell对已存在的表从CSV文件中进行数据导入。CSV文件只属于一张表且CSV文件中的数据格式需与要导入表的结构相同,在导入的时候,其语法如下:
|
||||
|
||||
```mysql
|
||||
insert into tb1 file 'path/data.csv';
|
||||
|
@ -487,7 +487,7 @@ Query OK, 9 row(s) affected (0.004763s)
|
|||
|
||||
**taosdump工具导入**
|
||||
|
||||
TDengine提供了方便的数据库导入导出工具taosdump。用户可以将taosdump从一个系统导出的数据,导入到其他系统中。具体使用方法,请参见博客:[TDengine DUMP工具使用指南](https://www.taosdata.com/blog/2020/03/09/1334.html)
|
||||
TDengine提供了方便的数据库导入导出工具taosdump。用户可以将taosdump从一个系统导出的数据,导入到其他系统中。具体使用方法,请参见博客:[TDengine DUMP工具使用指南](https://www.taosdata.com/blog/2020/03/09/1334.html)。
|
||||
|
||||
## <a class="anchor" id="export"></a>数据导出
|
||||
|
||||
|
@ -627,7 +627,7 @@ Active: inactive (dead)
|
|||
......
|
||||
```
|
||||
|
||||
卸载 TDengine,只需要执行如下命令
|
||||
卸载 TDengine,只需要执行如下命令:
|
||||
```
|
||||
rmtaos
|
||||
```
|
||||
|
@ -724,7 +724,7 @@ rmtaos
|
|||
2. 服务端命令行输入:`taos -n server -P <port>` 以服务端身份启动对端口 port 为基准端口的监听
|
||||
3. 客户端命令行输入:`taos -n client -h <fqdn of server> -P <port>` 以客户端身份启动对指定的服务器、指定的端口发送测试包
|
||||
|
||||
服务端运行正常的话会输出以下信息
|
||||
服务端运行正常的话会输出以下信息:
|
||||
|
||||
```bash
|
||||
# taos -n server -P 6000
|
||||
|
@ -796,6 +796,19 @@ taos -n sync -P 6042 -h <fqdn of server>
|
|||
|
||||
用来诊断 sync 端口是否工作正常,判断服务端 sync 模块是否成功工作。另外,-P 6042 用来诊断 arbitrator 是否配置正常,判断指定服务器的 arbitrator 是否能正常工作。
|
||||
|
||||
#### 网络速度诊断
|
||||
|
||||
`taos -n speed -h <fqdn of server> -P 6030 -N 10 -l 10000000 -S TCP`
|
||||
|
||||
从 2.1.7.0 版本开始,taos 工具新提供了一个网络速度诊断的模式,可以对一个正在运行中的 taosd 实例或者 `taos -n server` 方式模拟的一个服务端实例,以非压缩传输的方式进行网络测速。这个模式下可供调整的参数如下:
|
||||
|
||||
-n:设为“speed”时,表示对网络速度进行诊断。
|
||||
-h:所要连接的服务端的 FQDN 或 ip 地址。如果不设置这一项,会使用本机 taos.cfg 文件中 FQDN 参数的设置作为默认值。
|
||||
-P:所连接服务端的网络端口。默认值为 6030。
|
||||
-N:诊断过程中使用的网络包总数。最小值是 1、最大值是 10000,默认值为 100。
|
||||
-l:单个网络包的大小(单位:字节)。最小值是 1024、最大值是 1024*1024*1024,默认值为 1000。
|
||||
-S:网络封包的类型。可以是 TCP 或 UDP,默认值为 TCP。
|
||||
|
||||
#### 服务端日志
|
||||
|
||||
taosd 服务端日志文件标志位 debugflag 默认为 131,在 debug 时往往需要将其提升到 135 或 143 。
|
||||
|
|
|
@ -9,7 +9,7 @@ TAOS SQL 不支持关键字的缩写,例如 DESCRIBE 不能缩写为 DESC。
|
|||
本章节 SQL 语法遵循如下约定:
|
||||
|
||||
- < > 里的内容是用户需要输入的,但不要输入 <> 本身
|
||||
- [ ] 表示内容为可选项,但不能输入 [] 本身
|
||||
- \[ \] 表示内容为可选项,但不能输入 [] 本身
|
||||
- | 表示多选一,选择其中一个即可,但不能输入 | 本身
|
||||
- … 表示前面的项可重复多个
|
||||
|
||||
|
@ -34,16 +34,16 @@ taos> DESCRIBE meters;
|
|||
- 时间格式为 ```YYYY-MM-DD HH:mm:ss.MS```,默认时间分辨率为毫秒。比如:```2017-08-12 18:25:58.128```
|
||||
- 内部函数 now 是客户端的当前时间
|
||||
- 插入记录时,如果时间戳为 now,插入数据时使用提交这条记录的客户端的当前时间
|
||||
- Epoch Time:时间戳也可以是一个长整数,表示从格林威治时间 1970-01-01 00:00:00.000 (UTC/GMT) 开始的毫秒数(相应地,如果所在 Database 的时间精度设置为“微秒”,则长整型格式的时间戳含义也就对应于从格林威治时间 1970-01-01 00:00:00.000 (UTC/GMT) 开始的微秒数)
|
||||
- 时间可以加减,比如 now-2h,表明查询时刻向前推 2 个小时(最近 2 小时)。数字后面的时间单位可以是 u(微秒)、a(毫秒)、s(秒)、m(分)、h(小时)、d(天)、w(周)。 比如 `select * from t1 where ts > now-2w and ts <= now-1w`,表示查询两周前整整一周的数据。在指定降频操作(down sampling)的时间窗口(interval)时,时间单位还可以使用 n(自然月) 和 y(自然年)。
|
||||
- Epoch Time:时间戳也可以是一个长整数,表示从格林威治时间 1970-01-01 00:00:00.000 (UTC/GMT) 开始的毫秒数(相应地,如果所在 Database 的时间精度设置为“微秒”,则长整型格式的时间戳含义也就对应于从格林威治时间 1970-01-01 00:00:00.000 (UTC/GMT) 开始的微秒数;纳秒精度的逻辑也是类似的。)
|
||||
- 时间可以加减,比如 now-2h,表明查询时刻向前推 2 个小时(最近 2 小时)。数字后面的时间单位可以是 b(纳秒)、u(微秒)、a(毫秒)、s(秒)、m(分)、h(小时)、d(天)、w(周)。 比如 `select * from t1 where ts > now-2w and ts <= now-1w`,表示查询两周前整整一周的数据。在指定降频操作(down sampling)的时间窗口(interval)时,时间单位还可以使用 n(自然月) 和 y(自然年)。
|
||||
|
||||
TDengine 缺省的时间戳是毫秒精度,但通过在 CREATE DATABASE 时传递的 PRECISION 参数就可以支持微秒。
|
||||
TDengine 缺省的时间戳是毫秒精度,但通过在 CREATE DATABASE 时传递的 PRECISION 参数就可以支持微秒和纳秒。(从 2.1.5.0 版本开始支持纳秒精度)
|
||||
|
||||
在TDengine中,普通表的数据模型中可使用以下 10 种数据类型。
|
||||
|
||||
| # | **类型** | **Bytes** | **说明** |
|
||||
| ---- | :-------: | ------ | ------------------------------------------------------------ |
|
||||
| 1 | TIMESTAMP | 8 | 时间戳。缺省精度毫秒,可支持微秒。从格林威治时间 1970-01-01 00:00:00.000 (UTC/GMT) 开始,计时不能早于该时间。(从 2.0.18.0 版本开始,已经去除了这一时间范围限制) |
|
||||
| 1 | TIMESTAMP | 8 | 时间戳。缺省精度毫秒,可支持微秒和纳秒。从格林威治时间 1970-01-01 00:00:00.000 (UTC/GMT) 开始,计时不能早于该时间。(从 2.0.18.0 版本开始,已经去除了这一时间范围限制)(从 2.1.5.0 版本开始支持纳秒精度) |
|
||||
| 2 | INT | 4 | 整型,范围 [-2^31+1, 2^31-1], -2^31 用作 NULL |
|
||||
| 3 | BIGINT | 8 | 长整型,范围 [-2^63+1, 2^63-1], -2^63 用于 NULL |
|
||||
| 4 | FLOAT | 4 | 浮点型,有效位数 6-7,范围 [-3.4E38, 3.4E38] |
|
||||
|
@ -265,7 +265,7 @@ TDengine 缺省的时间戳是毫秒精度,但通过在 CREATE DATABASE 时传
|
|||
```mysql
|
||||
CREATE STABLE [IF NOT EXISTS] stb_name (timestamp_field_name TIMESTAMP, field1_name data_type1 [, field2_name data_type2 ...]) TAGS (tag1_name tag_type1, tag2_name tag_type2 [, tag3_name tag_type3]);
|
||||
```
|
||||
创建 STable,与创建表的 SQL 语法相似,但需要指定 TAGS 字段的名称和类型
|
||||
创建 STable,与创建表的 SQL 语法相似,但需要指定 TAGS 字段的名称和类型。
|
||||
|
||||
说明:
|
||||
|
||||
|
@ -389,7 +389,7 @@ INSERT INTO
|
|||
INSERT INTO d1001 VALUES ('2021-07-13 14:06:32.272', 10.2, 219, 0.32) (1626164208000, 10.15, 217, 0.33);
|
||||
```
|
||||
**注意:**
|
||||
1)在第二个例子中,两行记录的首列时间戳使用了不同格式的写法。其中字符串格式的时间戳写法不受所在 DATABASE 的时间精度设置影响;而长整形格式的时间戳写法会受到所在 DATABASE 的时间精度设置影响——例子中的时间戳在毫秒精度下可以写作 1626164208000,而如果是在微秒精度设置下就需要写为 1626164208000000。
|
||||
1)在第二个例子中,两行记录的首列时间戳使用了不同格式的写法。其中字符串格式的时间戳写法不受所在 DATABASE 的时间精度设置影响;而长整形格式的时间戳写法会受到所在 DATABASE 的时间精度设置影响——例子中的时间戳在毫秒精度下可以写作 1626164208000,而如果是在微秒精度设置下就需要写为 1626164208000000,纳秒精度设置下需要写为 1626164208000000000。
|
||||
2)在使用“插入多条记录”方式写入数据时,不能把第一列的时间戳取值都设为 NOW,否则会导致语句中的多条记录使用相同的时间戳,于是就可能出现相互覆盖以致这些数据行无法全部被正确保存。其原因在于,NOW 函数在执行中会被解析为所在 SQL 语句的实际执行时间,出现在同一语句中的多个 NOW 标记也就会被替换为完全相同的时间戳取值。
|
||||
3)允许插入的最老记录的时间戳,是相对于当前服务器时间,减去配置的 keep 值(数据保留的天数);允许插入的最新记录的时间戳,是相对于当前服务器时间,加上配置的 days 值(数据文件存储数据的时间跨度,单位为天)。keep 和 days 都是可以在创建数据库时指定的,缺省值分别是 3650 天和 10 天。
|
||||
|
||||
|
@ -728,18 +728,6 @@ Query OK, 1 row(s) in set (0.001091s)
|
|||
4. 从 2.0.17.0 版本开始,条件过滤开始支持 BETWEEN AND 语法,例如 `WHERE col2 BETWEEN 1.5 AND 3.25` 表示查询条件为“1.5 ≤ col2 ≤ 3.25”。
|
||||
5. 从 2.1.4.0 版本开始,条件过滤开始支持 IN 算子,例如 `WHERE city IN ('Beijing', 'Shanghai')`。说明:BOOL 类型写作 `{true, false}` 或 `{0, 1}` 均可,但不能写作 0、1 之外的整数;FLOAT 和 DOUBLE 类型会受到浮点数精度影响,集合内的值在精度范围内认为和数据行的值完全相等才能匹配成功;TIMESTAMP 类型支持非主键的列。<!-- REPLACE_OPEN_TO_ENTERPRISE__IN_OPERATOR_AND_UNSIGNED_INTEGER -->
|
||||
|
||||
<!--
|
||||
<a class="anchor" id="having"></a>
|
||||
### GROUP BY 之后的 HAVING 过滤
|
||||
|
||||
从 2.0.20.0 版本开始,GROUP BY 之后允许再跟一个 HAVING 子句,对成组后的各组数据再做筛选。HAVING 子句可以使用聚合函数和选择函数作为过滤条件(但暂时不支持 LEASTSQUARES、TOP、BOTTOM、LAST_ROW)。
|
||||
|
||||
例如,如下语句只会输出 `AVG(f1) > 0` 的分组:
|
||||
```mysql
|
||||
SELECT AVG(f1), SPREAD(f1, f2, st2.f1) FROM st2 WHERE f1 > 0 GROUP BY f1 HAVING AVG(f1) > 0;
|
||||
```
|
||||
-->
|
||||
|
||||
<a class="anchor" id="union"></a>
|
||||
### UNION ALL 操作符
|
||||
|
||||
|
@ -953,6 +941,8 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数
|
|||
|
||||
### 选择函数
|
||||
|
||||
在使用所有的选择函数的时候,可以同时指定输出 ts 列或标签列(包括 tbname),这样就可以方便地知道被选出的值是源于哪个数据行的。
|
||||
|
||||
- **MIN**
|
||||
```mysql
|
||||
SELECT MIN(field_name) FROM {tb_name | stb_name} [WHERE clause];
|
||||
|
@ -1023,9 +1013,9 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数
|
|||
|
||||
1)如果要返回各个列的首个(时间戳最小)非NULL值,可以使用FIRST(\*);
|
||||
|
||||
2) 如果结果集中的某列全部为NULL值,则该列的返回结果也是NULL;
|
||||
2)如果结果集中的某列全部为NULL值,则该列的返回结果也是NULL;
|
||||
|
||||
3) 如果结果集中所有列全部为NULL值,则不返回结果。
|
||||
3)如果结果集中所有列全部为NULL值,则不返回结果。
|
||||
|
||||
示例:
|
||||
```mysql
|
||||
|
@ -1185,7 +1175,7 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数
|
|||
|
||||
适用于:**表、超级表**。
|
||||
|
||||
说明:*P*值取值范围0≤*P*≤100,为0的时候等同于MIN,为100的时候等同于MAX。推荐使用```APERCENTILE```函数,该函数性能远胜于```PERCENTILE```函数
|
||||
说明:*P*值取值范围0≤*P*≤100,为0的时候等同于MIN,为100的时候等同于MAX。推荐使用```APERCENTILE```函数,该函数性能远胜于```PERCENTILE```函数。
|
||||
|
||||
```mysql
|
||||
taos> SELECT APERCENTILE(current, 20) FROM d1001;
|
||||
|
@ -1228,7 +1218,7 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数
|
|||
|
||||
- **INTERP**
|
||||
```mysql
|
||||
SELECT INTERP(field_name) FROM { tb_name | stb_name } WHERE ts='timestamp' [FILL ({ VALUE | PREV | NULL | LINEAR})];
|
||||
SELECT INTERP(field_name) FROM { tb_name | stb_name } WHERE ts='timestamp' [FILL ({ VALUE | PREV | NULL | LINEAR | NEXT})];
|
||||
```
|
||||
功能说明:返回表/超级表的指定时间截面、指定字段的记录。
|
||||
|
||||
|
@ -1240,8 +1230,6 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数
|
|||
|
||||
说明:(从 2.0.15.0 版本开始新增此函数)INTERP 必须指定时间断面,如果该时间断面不存在直接对应的数据,那么会根据 FILL 参数的设定进行插值。其中,条件语句里面可以附带更多的筛选条件,例如标签、tbname。
|
||||
|
||||
限制:INTERP 目前不支持 FILL(NEXT)。
|
||||
|
||||
示例:
|
||||
```mysql
|
||||
taos> select interp(*) from meters where ts='2017-7-14 10:42:00.005' fill(prev);
|
||||
|
@ -1416,13 +1404,13 @@ SELECT AVG(current), MAX(current), LEASTSQUARES(current, start_val, step_val), P
|
|||
|
||||
## <a class="anchor" id="limitation"></a>TAOS SQL 边界限制
|
||||
|
||||
- 数据库名最大长度为 32
|
||||
- 表名最大长度为 192,每行数据最大长度 16k 个字符(注意:数据行内每个 BINARY/NCHAR 类型的列还会额外占用 2 个字节的存储位置)
|
||||
- 列名最大长度为 64,最多允许 1024 列,最少需要 2 列,第一列必须是时间戳
|
||||
- 标签名最大长度为 64,最多允许 128 个,可以 1 个,一个表中标签值的总长度不超过 16k 个字符
|
||||
- SQL 语句最大长度 65480 个字符,但可通过系统配置参数 maxSQLLength 修改,最长可配置为 1M
|
||||
- 数据库名最大长度为 32。
|
||||
- 表名最大长度为 192,每行数据最大长度 16k 个字符(注意:数据行内每个 BINARY/NCHAR 类型的列还会额外占用 2 个字节的存储位置)。
|
||||
- 列名最大长度为 64,最多允许 1024 列,最少需要 2 列,第一列必须是时间戳。
|
||||
- 标签名最大长度为 64,最多允许 128 个,可以 1 个,一个表中标签值的总长度不超过 16k 个字符。
|
||||
- SQL 语句最大长度 65480 个字符,但可通过系统配置参数 maxSQLLength 修改,最长可配置为 1M。
|
||||
- SELECT 语句的查询结果,最多允许返回 1024 列(语句中的函数调用可能也会占用一些列空间),超限时需要显式指定较少的返回数据列,以避免语句执行报错。
|
||||
- 库的数目,超级表的数目、表的数目,系统不做限制,仅受系统资源限制
|
||||
- 库的数目,超级表的数目、表的数目,系统不做限制,仅受系统资源限制。
|
||||
|
||||
## TAOS SQL其他约定
|
||||
|
||||
|
|
|
@ -26,15 +26,15 @@
|
|||
|
||||
## 2. Windows平台下JDBCDriver找不到动态链接库,怎么办?
|
||||
|
||||
请看为此问题撰写的[技术博客](https://www.taosdata.com/blog/2019/12/03/950.html)
|
||||
请看为此问题撰写的[技术博客](https://www.taosdata.com/blog/2019/12/03/950.html)。
|
||||
|
||||
## 3. 创建数据表时提示more dnodes are needed
|
||||
|
||||
请看为此问题撰写的[技术博客](https://www.taosdata.com/blog/2019/12/03/965.html)
|
||||
请看为此问题撰写的[技术博客](https://www.taosdata.com/blog/2019/12/03/965.html)。
|
||||
|
||||
## 4. 如何让TDengine crash时生成core文件?
|
||||
|
||||
请看为此问题撰写的[技术博客](https://www.taosdata.com/blog/2019/12/06/974.html)
|
||||
请看为此问题撰写的[技术博客](https://www.taosdata.com/blog/2019/12/06/974.html)。
|
||||
|
||||
## 5. 遇到错误“Unable to establish connection”, 我怎么办?
|
||||
|
||||
|
@ -49,7 +49,7 @@
|
|||
|
||||
3. 在服务器,执行 `systemctl status taosd` 检查*taosd*运行状态。如果没有运行,启动*taosd*
|
||||
|
||||
4. 确认客户端连接时指定了正确的服务器FQDN (Fully Qualified Domain Name(可在服务器上执行Linux命令hostname -f获得)),FQDN配置参考:[一篇文章说清楚TDengine的FQDN](https://www.taosdata.com/blog/2020/09/11/1824.html)。
|
||||
4. 确认客户端连接时指定了正确的服务器FQDN (Fully Qualified Domain Name —— 可在服务器上执行Linux命令hostname -f获得),FQDN配置参考:[一篇文章说清楚TDengine的FQDN](https://www.taosdata.com/blog/2020/09/11/1824.html)。
|
||||
|
||||
5. ping服务器FQDN,如果没有反应,请检查你的网络,DNS设置,或客户端所在计算机的系统hosts文件。如果部署的是TDengine集群,客户端需要能ping通所有集群节点的FQDN。
|
||||
|
||||
|
@ -74,16 +74,16 @@
|
|||
|
||||
产生这个错误,是由于客户端或数据节点无法解析FQDN(Fully Qualified Domain Name)导致。对于TAOS Shell或客户端应用,请做如下检查:
|
||||
|
||||
1. 请检查连接的服务器的FQDN是否正确,FQDN配置参考:[一篇文章说清楚TDengine的FQDN](https://www.taosdata.com/blog/2020/09/11/1824.html)。
|
||||
2. 如果网络配置有DNS server, 请检查是否正常工作
|
||||
3. 如果网络没有配置DNS server, 请检查客户端所在机器的hosts文件,查看该FQDN是否配置,并是否有正确的IP地址。
|
||||
1. 请检查连接的服务器的FQDN是否正确,FQDN配置参考:[一篇文章说清楚TDengine的FQDN](https://www.taosdata.com/blog/2020/09/11/1824.html)
|
||||
2. 如果网络配置有DNS server,请检查是否正常工作
|
||||
3. 如果网络没有配置DNS server,请检查客户端所在机器的hosts文件,查看该FQDN是否配置,并是否有正确的IP地址
|
||||
4. 如果网络配置OK,从客户端所在机器,你需要能Ping该连接的FQDN,否则客户端是无法连接服务器的
|
||||
|
||||
## 7. 虽然语法正确,为什么我还是得到 "Invalid SQL" 错误
|
||||
|
||||
如果你确认语法正确,2.0之前版本,请检查SQL语句长度是否超过64K。如果超过,也会返回这个错误。
|
||||
|
||||
## 8. 是否支持validation queries?
|
||||
## 8. 是否支持validation queries?
|
||||
|
||||
TDengine还没有一组专用的validation queries。然而建议你使用系统监测的数据库”log"来做。
|
||||
|
||||
|
@ -137,7 +137,7 @@ Connection = DriverManager.getConnection(url, properties);
|
|||
|
||||
TDengine是根据hostname唯一标志一台机器的,在数据文件从机器A移动机器B时,注意如下两件事:
|
||||
|
||||
- 2.0.0.0 至 2.0.6.x 的版本,重新配置机器B的hostname为机器A的hostname
|
||||
- 2.0.0.0 至 2.0.6.x 的版本,重新配置机器B的hostname为机器A的hostname。
|
||||
- 2.0.7.0 及以后的版本,到/var/lib/taos/dnode下,修复dnodeEps.json的dnodeId对应的FQDN,重启。确保机器内所有机器的此文件是完全相同的。
|
||||
- 1.x 和 2.x 版本的存储结构不兼容,需要使用迁移工具或者自己开发应用导出导入数据。
|
||||
|
||||
|
|
|
@ -16,9 +16,7 @@ Please visit our [TDengine Official Docker Image: Distribution, Downloading, and
|
|||
|
||||
It’s extremely easy to install for TDengine, which takes only a few seconds from downloaded to successful installed. The server installation package includes clients and connectors. We provide 3 installation packages, which you can choose according to actual needs:
|
||||
|
||||
Click [here](https://www.taosdata.com/cn/getting-started/#%E9%80%9A%E8%BF%87%E5%AE%89%E8%A3%85%E5%8C%85%E5%AE%89%E8%A3%85) to download the install package.
|
||||
|
||||
For more about installation process, please refer [TDengine Installation Packages: Install and Uninstall](https://www.taosdata.com/blog/2019/08/09/566.html), and [Video Tutorials](https://www.taosdata.com/blog/2020/11/11/1941.html).
|
||||
Click [here](https://www.taosdata.com/en/getting-started/#Install-from-Package) to download the install package.
|
||||
|
||||
## <a class="anchor" id="start"></a>Quick Launch
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ Please watch the [video tutorial](https://www.taosdata.com/blog/2020/11/11/1945.
|
|||
Different types of data collection points often have different data characteristics, including frequency of data collecting, length of data retention time, number of replicas, size of data blocks, whether to update data or not, and so on. To ensure TDengine working with great efficiency in various scenarios, TDengine suggests creating tables with different data characteristics in different databases, because each database can be configured with different storage strategies. When creating a database, in addition to SQL standard options, the application can also specify a variety of parameters such as retention duration, number of replicas, number of memory blocks, time accuracy, max and min number of records in a file block, whether it is compressed or not, and number of days a data file will be overwritten. For example:
|
||||
|
||||
```mysql
|
||||
CREATE DATABASE power KEEP 365 DAYS 10 BLOCKS 4 UPDATE 1;
|
||||
CREATE DATABASE power KEEP 365 DAYS 10 BLOCKS 6 UPDATE 1;
|
||||
```
|
||||
|
||||
The above statement will create a database named “power”. The data of this database will be kept for 365 days (it will be automatically deleted 365 days later), one data file created per 10 days, and the number of memory blocks is 4 for data updating. For detailed syntax and parameters, please refer to [Data Management section of TAOS SQL](https://www.taosdata.com/en/documentation/taos-sql#management).
|
||||
|
|
|
@ -6,7 +6,7 @@ TDengine can quickly integrate with [Grafana](https://www.grafana.com/), an open
|
|||
|
||||
### Install Grafana
|
||||
|
||||
TDengine currently supports Grafana 5.2.4 and above. You can download and install the package from Grafana website according to the current operating system. The download address is as follows:
|
||||
TDengine currently supports Grafana 6.2 and above. You can download and install the package from Grafana website according to the current operating system. The download address is as follows:
|
||||
|
||||
https://grafana.com/grafana/download.
|
||||
|
||||
|
@ -64,7 +64,7 @@ According to the default prompt, query the average system memory usage at the sp
|
|||
|
||||
#### Import Dashboard
|
||||
|
||||
A `tdengine-grafana.json` importable dashboard is provided under the Grafana plug-in directory/usr/local/taos/connector/grafana/tdengine/dashboard/.
|
||||
A `tdengine-grafana.json` importable dashboard is provided under the Grafana plug-in directory `/usr/local/taos/connector/grafanaplugin/dashboard`.
|
||||
|
||||
Click the `Import` button on the left panel and upload the `tdengine-grafana.json` file:
|
||||
|
||||
|
|
|
@ -218,8 +218,4 @@ use telegraf;
|
|||
使用telegraf这个数据库。然后执行show tables,describe table等命令详细查询下telegraf这个库里保存了些什么数据。
|
||||
具体TDengine的查询语句可以参考[TDengine官方文档](https://www.taosdata.com/cn/documentation/taos-sql/)
|
||||
## 接入多个监控对象
|
||||
<<<<<<< HEAD
|
||||
就像前面原理介绍的,这个miniDevops的小系统,已经提供了一个时序数据库和可视化系统,对于多台机器的监控,只需要将每台机器的telegraf或prometheus配置按上面所述修改,就可以完成监控数据采集和可视化呈现了。
|
||||
=======
|
||||
就像前面原理介绍的,这个miniDevops的小系统,已经提供了一个时序数据库和可视化系统,对于多台机器的监控,只需要将每台机器的telegraf或prometheus配置按上面所述修改,就可以完成监控数据采集和可视化呈现了。
|
||||
>>>>>>> 740f82af58c4ecc2deecfa36fb1de4ef5ee55efc
|
||||
|
|
|
@ -29,15 +29,16 @@ extern "C" {
|
|||
#include "tsched.h"
|
||||
#include "tsclient.h"
|
||||
|
||||
#define UTIL_TABLE_IS_SUPER_TABLE(metaInfo) \
|
||||
#define UTIL_TABLE_IS_SUPER_TABLE(metaInfo) \
|
||||
(((metaInfo)->pTableMeta != NULL) && ((metaInfo)->pTableMeta->tableType == TSDB_SUPER_TABLE))
|
||||
|
||||
#define UTIL_TABLE_IS_CHILD_TABLE(metaInfo) \
|
||||
(((metaInfo)->pTableMeta != NULL) && ((metaInfo)->pTableMeta->tableType == TSDB_CHILD_TABLE))
|
||||
|
||||
#define UTIL_TABLE_IS_NORMAL_TABLE(metaInfo)\
|
||||
(!(UTIL_TABLE_IS_SUPER_TABLE(metaInfo) || UTIL_TABLE_IS_CHILD_TABLE(metaInfo)))
|
||||
|
||||
#define UTIL_TABLE_IS_TMP_TABLE(metaInfo) \
|
||||
#define UTIL_TABLE_IS_NORMAL_TABLE(metaInfo) \
|
||||
(!(UTIL_TABLE_IS_SUPER_TABLE(metaInfo) || UTIL_TABLE_IS_CHILD_TABLE(metaInfo) || UTIL_TABLE_IS_TMP_TABLE(metaInfo)))
|
||||
|
||||
#define UTIL_TABLE_IS_TMP_TABLE(metaInfo) \
|
||||
(((metaInfo)->pTableMeta != NULL) && ((metaInfo)->pTableMeta->tableType == TSDB_TEMP_TABLE))
|
||||
|
||||
#pragma pack(push,1)
|
||||
|
@ -221,7 +222,7 @@ void tscExprDestroy(SArray* pExprInfo);
|
|||
|
||||
int32_t createProjectionExpr(SQueryInfo* pQueryInfo, STableMetaInfo* pTableMetaInfo, SExprInfo*** pExpr, int32_t* num);
|
||||
|
||||
void clearAllTableMetaInfo(SQueryInfo* pQueryInfo, bool removeMeta);
|
||||
void clearAllTableMetaInfo(SQueryInfo* pQueryInfo, bool removeMeta, uint64_t id);
|
||||
|
||||
SColumn* tscColumnClone(const SColumn* src);
|
||||
void tscColumnCopy(SColumn* pDest, const SColumn* pSrc);
|
||||
|
@ -320,7 +321,7 @@ void tscPrintSelNodeList(SSqlObj* pSql, int32_t subClauseIndex);
|
|||
bool hasMoreVnodesToTry(SSqlObj *pSql);
|
||||
bool hasMoreClauseToTry(SSqlObj* pSql);
|
||||
|
||||
void tscFreeQueryInfo(SSqlCmd* pCmd, bool removeMeta);
|
||||
void tscFreeQueryInfo(SSqlCmd* pCmd, bool removeCachedMeta, uint64_t id);
|
||||
|
||||
void tscTryQueryNextVnode(SSqlObj *pSql, __async_cb_func_t fp);
|
||||
void tscTryQueryNextClause(SSqlObj* pSql, __async_cb_func_t fp);
|
||||
|
@ -359,7 +360,7 @@ bool vgroupInfoIdentical(SNewVgroupInfo *pExisted, SVgroupMsg* src);
|
|||
SNewVgroupInfo createNewVgroupInfo(SVgroupMsg *pVgroupMsg);
|
||||
STblCond* tsGetTableFilter(SArray* filters, uint64_t uid, int16_t idx);
|
||||
|
||||
void tscRemoveTableMetaBuf(STableMetaInfo* pTableMetaInfo, uint64_t id);
|
||||
void tscRemoveCachedTableMeta(STableMetaInfo* pTableMetaInfo, uint64_t id);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -123,17 +123,15 @@ typedef struct {
|
|||
int32_t kvLen; // len of SKVRow
|
||||
} SMemRowInfo;
|
||||
typedef struct {
|
||||
uint8_t memRowType;
|
||||
uint8_t compareStat; // 0 unknown, 1 need compare, 2 no need
|
||||
TDRowTLenT dataRowInitLen;
|
||||
uint8_t memRowType; // default is 0, that is SDataRow
|
||||
uint8_t compareStat; // 0 no need, 1 need compare
|
||||
TDRowTLenT kvRowInitLen;
|
||||
SMemRowInfo *rowInfo;
|
||||
} SMemRowBuilder;
|
||||
|
||||
typedef enum {
|
||||
ROW_COMPARE_UNKNOWN = 0,
|
||||
ROW_COMPARE_NO_NEED = 0,
|
||||
ROW_COMPARE_NEED = 1,
|
||||
ROW_COMPARE_NO_NEED = 2,
|
||||
} ERowCompareStat;
|
||||
|
||||
int tsParseTime(SStrToken *pToken, int64_t *time, char **next, char *error, int16_t timePrec);
|
||||
|
@ -447,7 +445,7 @@ void tscSetResRawPtrRv(SSqlRes* pRes, SQueryInfo* pQueryInfo, SSDataBlock* pBloc
|
|||
void handleDownstreamOperator(SSqlObj** pSqlList, int32_t numOfUpstream, SQueryInfo* px, SSqlObj* pParent);
|
||||
void destroyTableNameList(SInsertStatementParam* pInsertParam);
|
||||
|
||||
void tscResetSqlCmd(SSqlCmd *pCmd, bool removeMeta);
|
||||
void tscResetSqlCmd(SSqlCmd *pCmd, bool removeMeta, uint64_t id);
|
||||
|
||||
/**
|
||||
* free query result of the sql object
|
||||
|
|
|
@ -351,7 +351,7 @@ void tscTableMetaCallBack(void *param, TAOS_RES *res, int code) {
|
|||
if (pSql->pStream == NULL) {
|
||||
SQueryInfo *pQueryInfo = tscGetQueryInfo(pCmd);
|
||||
|
||||
if (TSDB_QUERY_HAS_TYPE(pQueryInfo->type, TSDB_QUERY_TYPE_INSERT)) {
|
||||
if (pQueryInfo != NULL && TSDB_QUERY_HAS_TYPE(pQueryInfo->type, TSDB_QUERY_TYPE_INSERT)) {
|
||||
tscDebug("0x%" PRIx64 " continue parse sql after get table-meta", pSql->self);
|
||||
|
||||
code = tsParseSql(pSql, false);
|
||||
|
@ -381,7 +381,6 @@ void tscTableMetaCallBack(void *param, TAOS_RES *res, int code) {
|
|||
} else {
|
||||
if (pSql->retryReason != TSDB_CODE_SUCCESS) {
|
||||
tscDebug("0x%" PRIx64 " update cached table-meta, re-validate sql statement and send query again", pSql->self);
|
||||
tscResetSqlCmd(pCmd, false);
|
||||
pSql->retryReason = TSDB_CODE_SUCCESS;
|
||||
} else {
|
||||
tscDebug("0x%" PRIx64 " cached table-meta, continue validate sql statement and send query", pSql->self);
|
||||
|
|
|
@ -51,20 +51,18 @@ int initMemRowBuilder(SMemRowBuilder *pBuilder, uint32_t nRows, uint3
|
|||
}
|
||||
}
|
||||
|
||||
// default compareStat is ROW_COMPARE_NO_NEED
|
||||
if (nBoundCols == 0) { // file input
|
||||
pBuilder->memRowType = SMEM_ROW_DATA;
|
||||
pBuilder->compareStat = ROW_COMPARE_NO_NEED;
|
||||
return TSDB_CODE_SUCCESS;
|
||||
} else {
|
||||
float boundRatio = ((float)nBoundCols / (float)nCols);
|
||||
|
||||
if (boundRatio < KVRatioKV) {
|
||||
pBuilder->memRowType = SMEM_ROW_KV;
|
||||
pBuilder->compareStat = ROW_COMPARE_NO_NEED;
|
||||
return TSDB_CODE_SUCCESS;
|
||||
} else if (boundRatio > KVRatioData) {
|
||||
pBuilder->memRowType = SMEM_ROW_DATA;
|
||||
pBuilder->compareStat = ROW_COMPARE_NO_NEED;
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
pBuilder->compareStat = ROW_COMPARE_NEED;
|
||||
|
@ -76,7 +74,6 @@ int initMemRowBuilder(SMemRowBuilder *pBuilder, uint32_t nRows, uint3
|
|||
}
|
||||
}
|
||||
|
||||
pBuilder->dataRowInitLen = TD_MEM_ROW_DATA_HEAD_SIZE + allNullLen;
|
||||
pBuilder->kvRowInitLen = TD_MEM_ROW_KV_HEAD_SIZE + nBoundCols * sizeof(SColIdx);
|
||||
|
||||
if (nRows > 0) {
|
||||
|
@ -86,7 +83,7 @@ int initMemRowBuilder(SMemRowBuilder *pBuilder, uint32_t nRows, uint3
|
|||
}
|
||||
|
||||
for (int i = 0; i < nRows; ++i) {
|
||||
(pBuilder->rowInfo + i)->dataLen = pBuilder->dataRowInitLen;
|
||||
(pBuilder->rowInfo + i)->dataLen = TD_MEM_ROW_DATA_HEAD_SIZE + allNullLen;
|
||||
(pBuilder->rowInfo + i)->kvLen = pBuilder->kvRowInitLen;
|
||||
}
|
||||
}
|
||||
|
@ -460,7 +457,7 @@ int tsParseOneRow(char **str, STableDataBlocks *pDataBlocks, int16_t timePrec, i
|
|||
STableMeta * pTableMeta = pDataBlocks->pTableMeta;
|
||||
SSchema * schema = tscGetTableSchema(pTableMeta);
|
||||
SMemRowBuilder * pBuilder = &pDataBlocks->rowBuilder;
|
||||
int32_t dataLen = pBuilder->dataRowInitLen;
|
||||
int32_t dataLen = spd->allNullLen + TD_MEM_ROW_DATA_HEAD_SIZE;
|
||||
int32_t kvLen = pBuilder->kvRowInitLen;
|
||||
bool isParseBindParam = false;
|
||||
|
||||
|
@ -657,9 +654,7 @@ int32_t tsParseValues(char **str, STableDataBlocks *pDataBlock, int maxRows, SIn
|
|||
index = 0;
|
||||
sToken = tStrGetToken(*str, &index, false);
|
||||
if (sToken.n == 0 || sToken.type != TK_RP) {
|
||||
tscSQLSyntaxErrMsg(pInsertParam->msg, ") expected", *str);
|
||||
code = TSDB_CODE_TSC_SQL_SYNTAX_ERROR;
|
||||
return code;
|
||||
return tscSQLSyntaxErrMsg(pInsertParam->msg, ") expected", *str);
|
||||
}
|
||||
|
||||
*str += index;
|
||||
|
@ -811,13 +806,12 @@ int tscSortRemoveDataBlockDupRows(STableDataBlocks *dataBuf, SBlockKeyInfo *pBlk
|
|||
// allocate memory
|
||||
size_t nAlloc = nRows * sizeof(SBlockKeyTuple);
|
||||
if (pBlkKeyInfo->pKeyTuple == NULL || pBlkKeyInfo->maxBytesAlloc < nAlloc) {
|
||||
size_t nRealAlloc = nAlloc + 10 * sizeof(SBlockKeyTuple);
|
||||
char * tmp = trealloc(pBlkKeyInfo->pKeyTuple, nRealAlloc);
|
||||
char *tmp = trealloc(pBlkKeyInfo->pKeyTuple, nAlloc);
|
||||
if (tmp == NULL) {
|
||||
return TSDB_CODE_TSC_OUT_OF_MEMORY;
|
||||
}
|
||||
pBlkKeyInfo->pKeyTuple = (SBlockKeyTuple *)tmp;
|
||||
pBlkKeyInfo->maxBytesAlloc = (int32_t)nRealAlloc;
|
||||
pBlkKeyInfo->maxBytesAlloc = (int32_t)nAlloc;
|
||||
}
|
||||
memset(pBlkKeyInfo->pKeyTuple, 0, nAlloc);
|
||||
|
||||
|
@ -1597,7 +1591,7 @@ int tsParseSql(SSqlObj *pSql, bool initial) {
|
|||
if (pSql->parseRetry < 1 && (ret == TSDB_CODE_TSC_SQL_SYNTAX_ERROR || ret == TSDB_CODE_TSC_INVALID_OPERATION)) {
|
||||
tscDebug("0x%"PRIx64 " parse insert sql statement failed, code:%s, clear meta cache and retry ", pSql->self, tstrerror(ret));
|
||||
|
||||
tscResetSqlCmd(pCmd, true);
|
||||
tscResetSqlCmd(pCmd, true, pSql->self);
|
||||
pSql->parseRetry++;
|
||||
|
||||
if ((ret = tsInsertInitialCheck(pSql)) == TSDB_CODE_SUCCESS) {
|
||||
|
@ -1614,7 +1608,7 @@ int tsParseSql(SSqlObj *pSql, bool initial) {
|
|||
if (ret == TSDB_CODE_TSC_INVALID_OPERATION && pSql->parseRetry < 1 && sqlInfo.type == TSDB_SQL_SELECT) {
|
||||
tscDebug("0x%"PRIx64 " parse query sql statement failed, code:%s, clear meta cache and retry ", pSql->self, tstrerror(ret));
|
||||
|
||||
tscResetSqlCmd(pCmd, true);
|
||||
tscResetSqlCmd(pCmd, true, pSql->self);
|
||||
pSql->parseRetry++;
|
||||
|
||||
ret = tscValidateSqlInfo(pSql, &sqlInfo);
|
||||
|
@ -1728,12 +1722,6 @@ static void parseFileSendDataBlock(void *param, TAOS_RES *tres, int32_t numOfRow
|
|||
goto _error;
|
||||
}
|
||||
|
||||
if (TSDB_CODE_SUCCESS !=
|
||||
(ret = initMemRowBuilder(&pTableDataBlock->rowBuilder, 0, tinfo.numOfColumns, pTableDataBlock->numOfParams,
|
||||
pTableDataBlock->boundColumnInfo.allNullLen))) {
|
||||
goto _error;
|
||||
}
|
||||
|
||||
while ((readLen = tgetline(&line, &n, fp)) != -1) {
|
||||
if (('\r' == line[readLen - 1]) || ('\n' == line[readLen - 1])) {
|
||||
line[--readLen] = 0;
|
||||
|
|
|
@ -1694,7 +1694,7 @@ int taos_stmt_set_tbname_tags(TAOS_STMT* stmt, const char* name, TAOS_BIND* tags
|
|||
if (taosHashGetSize(pCmd->insertParam.pTableBlockHashList) > 0) {
|
||||
SHashObj* hashList = pCmd->insertParam.pTableBlockHashList;
|
||||
pCmd->insertParam.pTableBlockHashList = NULL;
|
||||
tscResetSqlCmd(pCmd, false);
|
||||
tscResetSqlCmd(pCmd, false, pSql->self);
|
||||
pCmd->insertParam.pTableBlockHashList = hashList;
|
||||
}
|
||||
|
||||
|
|
|
@ -18,11 +18,11 @@
|
|||
#include "tsclient.h"
|
||||
#include "tsocket.h"
|
||||
#include "ttimer.h"
|
||||
#include "tutil.h"
|
||||
#include "taosmsg.h"
|
||||
#include "tcq.h"
|
||||
|
||||
#include "taos.h"
|
||||
#include "tscUtil.h"
|
||||
|
||||
void tscSaveSlowQueryFp(void *handle, void *tmrId);
|
||||
TAOS *tscSlowQueryConn = NULL;
|
||||
|
@ -227,16 +227,16 @@ void tscKillStream(STscObj *pObj, uint32_t killId) {
|
|||
|
||||
int tscBuildQueryStreamDesc(void *pMsg, STscObj *pObj) {
|
||||
SHeartBeatMsg *pHeartbeat = pMsg;
|
||||
|
||||
int allocedQueriesNum = pHeartbeat->numOfQueries;
|
||||
int allocedStreamsNum = pHeartbeat->numOfStreams;
|
||||
|
||||
pHeartbeat->numOfQueries = 0;
|
||||
SQueryDesc *pQdesc = (SQueryDesc *)pHeartbeat->pData;
|
||||
|
||||
// We extract the lock to tscBuildHeartBeatMsg function.
|
||||
|
||||
int64_t now = taosGetTimestampMs();
|
||||
SSqlObj *pSql = pObj->sqlList;
|
||||
|
||||
while (pSql) {
|
||||
/*
|
||||
* avoid sqlobj may not be correctly removed from sql list
|
||||
|
@ -248,41 +248,55 @@ int tscBuildQueryStreamDesc(void *pMsg, STscObj *pObj) {
|
|||
}
|
||||
|
||||
tstrncpy(pQdesc->sql, pSql->sqlstr, sizeof(pQdesc->sql));
|
||||
pQdesc->stime = htobe64(pSql->stime);
|
||||
pQdesc->queryId = htonl(pSql->queryId);
|
||||
//pQdesc->useconds = htobe64(pSql->res.useconds);
|
||||
pQdesc->stime = htobe64(pSql->stime);
|
||||
pQdesc->queryId = htonl(pSql->queryId);
|
||||
pQdesc->useconds = htobe64(now - pSql->stime);
|
||||
pQdesc->qId = htobe64(pSql->res.qId);
|
||||
pQdesc->qId = htobe64(pSql->res.qId);
|
||||
pQdesc->sqlObjId = htobe64(pSql->self);
|
||||
pQdesc->pid = pHeartbeat->pid;
|
||||
pQdesc->stableQuery = pSql->cmd.pQueryInfo->stableQuery;
|
||||
pQdesc->pid = pHeartbeat->pid;
|
||||
pQdesc->numOfSub = pSql->subState.numOfSub;
|
||||
|
||||
// todo race condition
|
||||
pQdesc->stableQuery = 0;
|
||||
|
||||
char *p = pQdesc->subSqlInfo;
|
||||
int32_t remainLen = sizeof(pQdesc->subSqlInfo);
|
||||
if (pQdesc->numOfSub == 0) {
|
||||
snprintf(p, remainLen, "N/A");
|
||||
} else {
|
||||
int32_t len;
|
||||
for (int32_t i = 0; i < pQdesc->numOfSub; ++i) {
|
||||
len = snprintf(p, remainLen, "[%d]0x%" PRIx64 "(%c) ", i,
|
||||
pSql->pSubs[i]->self,
|
||||
pSql->subState.states[i] ? 'C' : 'I');
|
||||
if (len > remainLen) {
|
||||
break;
|
||||
// SQueryInfo* pQueryInfo = tscGetQueryInfo(&pSql->cmd);
|
||||
// if (pQueryInfo != NULL) {
|
||||
// pQdesc->stableQuery = (pQueryInfo->stableQuery)?1:0;
|
||||
// } else {
|
||||
// pQdesc->stableQuery = 0;
|
||||
// }
|
||||
|
||||
if (pSql->pSubs != NULL && pSql->subState.states != NULL) {
|
||||
for (int32_t i = 0; i < pQdesc->numOfSub; ++i) {
|
||||
SSqlObj *psub = pSql->pSubs[i];
|
||||
int64_t self = (psub != NULL)? psub->self : 0;
|
||||
|
||||
int32_t len = snprintf(p, remainLen, "[%d]0x%" PRIx64 "(%c) ", i, self, pSql->subState.states[i] ? 'C' : 'I');
|
||||
if (len > remainLen) {
|
||||
break;
|
||||
}
|
||||
|
||||
remainLen -= len;
|
||||
p += len;
|
||||
}
|
||||
remainLen -= len;
|
||||
p += len;
|
||||
}
|
||||
}
|
||||
pQdesc->numOfSub = htonl(pQdesc->numOfSub);
|
||||
|
||||
pQdesc->numOfSub = htonl(pQdesc->numOfSub);
|
||||
taosGetFqdn(pQdesc->fqdn);
|
||||
|
||||
pHeartbeat->numOfQueries++;
|
||||
pQdesc++;
|
||||
|
||||
pSql = pSql->next;
|
||||
if (pHeartbeat->numOfQueries >= allocedQueriesNum) break;
|
||||
if (pHeartbeat->numOfQueries >= allocedQueriesNum) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pHeartbeat->numOfStreams = 0;
|
||||
|
|
|
@ -1944,20 +1944,6 @@ static void addPrimaryTsColIntoResult(SQueryInfo* pQueryInfo, SSqlCmd* pCmd) {
|
|||
pQueryInfo->type |= TSDB_QUERY_TYPE_PROJECTION_QUERY;
|
||||
}
|
||||
|
||||
bool isValidDistinctSql(SQueryInfo* pQueryInfo) {
|
||||
if (pQueryInfo == NULL) {
|
||||
return false;
|
||||
}
|
||||
if ((pQueryInfo->type & TSDB_QUERY_TYPE_STABLE_QUERY) != TSDB_QUERY_TYPE_STABLE_QUERY
|
||||
&& (pQueryInfo->type & TSDB_QUERY_TYPE_TABLE_QUERY) != TSDB_QUERY_TYPE_TABLE_QUERY) {
|
||||
return false;
|
||||
}
|
||||
if (tscNumOfExprs(pQueryInfo) == 1){
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool hasNoneUserDefineExpr(SQueryInfo* pQueryInfo) {
|
||||
size_t numOfExprs = taosArrayGetSize(pQueryInfo->exprList);
|
||||
for (int32_t i = 0; i < numOfExprs; ++i) {
|
||||
|
@ -2047,8 +2033,12 @@ int32_t validateSelectNodeList(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SArray* pS
|
|||
const char* msg1 = "too many items in selection clause";
|
||||
const char* msg2 = "functions or others can not be mixed up";
|
||||
const char* msg3 = "not support query expression";
|
||||
const char* msg4 = "only support distinct one column or tag";
|
||||
const char* msg4 = "not support distinct mixed with proj/agg func";
|
||||
const char* msg5 = "invalid function name";
|
||||
const char* msg6 = "not support distinct mixed with join";
|
||||
const char* msg7 = "not support distinct mixed with groupby";
|
||||
const char* msg8 = "not support distinct in nest query";
|
||||
const char* msg9 = "_block_dist not support subquery, only support stable/table";
|
||||
|
||||
// too many result columns not support order by in query
|
||||
if (taosArrayGetSize(pSelNodeList) > TSDB_MAX_COLUMNS) {
|
||||
|
@ -2060,18 +2050,28 @@ int32_t validateSelectNodeList(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SArray* pS
|
|||
}
|
||||
|
||||
bool hasDistinct = false;
|
||||
size_t numOfExpr = taosArrayGetSize(pSelNodeList);
|
||||
bool hasAgg = false;
|
||||
size_t numOfExpr = taosArrayGetSize(pSelNodeList);
|
||||
int32_t distIdx = -1;
|
||||
for (int32_t i = 0; i < numOfExpr; ++i) {
|
||||
int32_t outputIndex = (int32_t)tscNumOfExprs(pQueryInfo);
|
||||
tSqlExprItem* pItem = taosArrayGet(pSelNodeList, i);
|
||||
|
||||
if (hasDistinct == false) {
|
||||
hasDistinct = (pItem->distinct == true);
|
||||
}
|
||||
hasDistinct = (pItem->distinct == true);
|
||||
distIdx = hasDistinct ? i : -1;
|
||||
}
|
||||
|
||||
int32_t type = pItem->pNode->type;
|
||||
if (type == SQL_NODE_SQLFUNCTION) {
|
||||
hasAgg = true;
|
||||
if (hasDistinct) break;
|
||||
|
||||
pItem->pNode->functionId = isValidFunction(pItem->pNode->Expr.operand.z, pItem->pNode->Expr.operand.n);
|
||||
|
||||
if (pItem->pNode->functionId == TSDB_FUNC_BLKINFO && taosArrayGetSize(pQueryInfo->pUpstream) > 0) {
|
||||
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg9);
|
||||
}
|
||||
|
||||
SUdfInfo* pUdfInfo = NULL;
|
||||
if (pItem->pNode->functionId < 0) {
|
||||
pUdfInfo = isValidUdf(pQueryInfo->pUdfInfo, pItem->pNode->Expr.operand.z, pItem->pNode->Expr.operand.n);
|
||||
|
@ -2106,9 +2106,21 @@ int32_t validateSelectNodeList(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SArray* pS
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
//TODO(dengyihao), refactor as function
|
||||
//handle distinct func mixed with other func
|
||||
if (hasDistinct == true) {
|
||||
if (!isValidDistinctSql(pQueryInfo) ) {
|
||||
if (distIdx != 0 || hasAgg) {
|
||||
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg4);
|
||||
}
|
||||
if (joinQuery) {
|
||||
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg6);
|
||||
}
|
||||
if (pQueryInfo->groupbyExpr.numOfGroupCols != 0) {
|
||||
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg7);
|
||||
}
|
||||
if (pQueryInfo->pDownstream != NULL) {
|
||||
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg8);
|
||||
}
|
||||
pQueryInfo->distinct = true;
|
||||
}
|
||||
|
@ -3725,7 +3737,8 @@ static int32_t doExtractColumnFilterInfo(SSqlCmd* pCmd, SQueryInfo* pQueryInfo,
|
|||
if (pRight->tokenId != TK_SET || !serializeExprListToVariant(pRight->Expr.paramList, &pVal, colType, timePrecision)) {
|
||||
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg);
|
||||
}
|
||||
pColumnFilter->pz = (int64_t)calloc(1, pVal->nLen + 1);
|
||||
|
||||
pColumnFilter->pz = (int64_t)calloc(1, pVal->nLen);
|
||||
pColumnFilter->len = pVal->nLen;
|
||||
pColumnFilter->filterstr = 1;
|
||||
memcpy((char *)(pColumnFilter->pz), (char *)(pVal->pz), pVal->nLen);
|
||||
|
@ -4293,7 +4306,7 @@ static bool isValidExpr(tSqlExpr* pLeft, tSqlExpr* pRight, int32_t optr) {
|
|||
if (pRight == NULL) {
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
if (pLeft->tokenId >= TK_BOOL && pLeft->tokenId <= TK_BINARY && pRight->tokenId >= TK_BOOL && pRight->tokenId <= TK_BINARY) {
|
||||
return false;
|
||||
}
|
||||
|
@ -5746,36 +5759,42 @@ static void setDefaultOrderInfo(SQueryInfo* pQueryInfo) {
|
|||
pQueryInfo->order.order = TSDB_ORDER_ASC;
|
||||
if (isTopBottomQuery(pQueryInfo)) {
|
||||
pQueryInfo->order.orderColId = PRIMARYKEY_TIMESTAMP_COL_INDEX;
|
||||
} else { // in case of select tbname from super_table, the defualt order column can not be the primary ts column
|
||||
pQueryInfo->order.orderColId = INT32_MIN;
|
||||
} else { // in case of select tbname from super_table, the default order column can not be the primary ts column
|
||||
pQueryInfo->order.orderColId = INT32_MIN; // todo define a macro
|
||||
}
|
||||
|
||||
/* for super table query, set default ascending order for group output */
|
||||
if (UTIL_TABLE_IS_SUPER_TABLE(pTableMetaInfo)) {
|
||||
pQueryInfo->groupbyExpr.orderType = TSDB_ORDER_ASC;
|
||||
}
|
||||
|
||||
if (pQueryInfo->distinct) {
|
||||
pQueryInfo->order.order = TSDB_ORDER_ASC;
|
||||
pQueryInfo->order.orderColId = PRIMARYKEY_TIMESTAMP_COL_INDEX;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSqlNode, SSchema* pSchema) {
|
||||
const char* msg0 = "only support order by primary timestamp";
|
||||
const char* msg1 = "invalid column name";
|
||||
const char* msg2 = "order by primary timestamp, first tag or groupby column in groupby clause allowed";
|
||||
const char* msg3 = "invalid column in order by clause, only primary timestamp or first tag in groupby clause allowed";
|
||||
const char* msg0 = "only one column allowed in orderby";
|
||||
const char* msg1 = "invalid column name in orderby clause";
|
||||
const char* msg2 = "too many order by columns";
|
||||
const char* msg3 = "only primary timestamp/tbname/first tag in groupby clause allowed";
|
||||
const char* msg4 = "only tag in groupby clause allowed in order clause";
|
||||
const char* msg5 = "only primary timestamp/column in top/bottom function allowed as order column";
|
||||
const char* msg6 = "only primary timestamp allowed as the second order column";
|
||||
const char* msg7 = "only primary timestamp/column in groupby clause allowed as order column";
|
||||
const char* msg8 = "only column in groupby clause allowed as order column";
|
||||
const char* msg9 = "orderby column must projected in subquery";
|
||||
|
||||
setDefaultOrderInfo(pQueryInfo);
|
||||
STableMetaInfo* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0);
|
||||
|
||||
|
||||
if (pQueryInfo->distinct == true) {
|
||||
pQueryInfo->order.order = TSDB_ORDER_ASC;
|
||||
pQueryInfo->order.orderColId = 0;
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
if (pSqlNode->pSortOrder == NULL) {
|
||||
if (pQueryInfo->distinct || pSqlNode->pSortOrder == NULL) {
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
SArray* pSortorder = pSqlNode->pSortOrder;
|
||||
char* pMsgBuf = tscGetErrorMsgPayload(pCmd);
|
||||
SArray* pSortOrder = pSqlNode->pSortOrder;
|
||||
|
||||
/*
|
||||
* for table query, there is only one or none order option is allowed, which is the
|
||||
|
@ -5783,19 +5802,19 @@ int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSq
|
|||
*
|
||||
* for super table query, the order option must be less than 3.
|
||||
*/
|
||||
size_t size = taosArrayGetSize(pSortorder);
|
||||
if (UTIL_TABLE_IS_NORMAL_TABLE(pTableMetaInfo)) {
|
||||
size_t size = taosArrayGetSize(pSortOrder);
|
||||
if (UTIL_TABLE_IS_NORMAL_TABLE(pTableMetaInfo) || UTIL_TABLE_IS_TMP_TABLE(pTableMetaInfo)) {
|
||||
if (size > 1) {
|
||||
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg0);
|
||||
return invalidOperationMsg(pMsgBuf, msg0);
|
||||
}
|
||||
} else {
|
||||
if (size > 2) {
|
||||
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg3);
|
||||
return invalidOperationMsg(pMsgBuf, msg2);
|
||||
}
|
||||
}
|
||||
|
||||
// handle the first part of order by
|
||||
tVariant* pVar = taosArrayGet(pSortorder, 0);
|
||||
tVariant* pVar = taosArrayGet(pSortOrder, 0);
|
||||
|
||||
// e.g., order by 1 asc, return directly with out further check.
|
||||
if (pVar->nType >= TSDB_DATA_TYPE_TINYINT && pVar->nType <= TSDB_DATA_TYPE_BIGINT) {
|
||||
|
@ -5807,7 +5826,7 @@ int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSq
|
|||
|
||||
if (UTIL_TABLE_IS_SUPER_TABLE(pTableMetaInfo)) { // super table query
|
||||
if (getColumnIndexByName(&columnName, pQueryInfo, &index, tscGetErrorMsgPayload(pCmd)) != TSDB_CODE_SUCCESS) {
|
||||
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg1);
|
||||
return invalidOperationMsg(pMsgBuf, msg1);
|
||||
}
|
||||
|
||||
bool orderByTags = false;
|
||||
|
@ -5819,7 +5838,7 @@ int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSq
|
|||
|
||||
// it is a tag column
|
||||
if (pQueryInfo->groupbyExpr.columnInfo == NULL) {
|
||||
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg2);
|
||||
return invalidOperationMsg(pMsgBuf, msg4);
|
||||
}
|
||||
SColIndex* pColIndex = taosArrayGet(pQueryInfo->groupbyExpr.columnInfo, 0);
|
||||
if (relTagIndex == pColIndex->colIndex) {
|
||||
|
@ -5840,13 +5859,14 @@ int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSq
|
|||
orderByGroupbyCol = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!(orderByTags || orderByTS || orderByGroupbyCol) && !isTopBottomQuery(pQueryInfo)) {
|
||||
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg3);
|
||||
return invalidOperationMsg(pMsgBuf, msg3);
|
||||
} else { // order by top/bottom result value column is not supported in case of interval query.
|
||||
assert(!(orderByTags && orderByTS && orderByGroupbyCol));
|
||||
}
|
||||
|
||||
size_t s = taosArrayGetSize(pSortorder);
|
||||
size_t s = taosArrayGetSize(pSortOrder);
|
||||
if (s == 1) {
|
||||
if (orderByTags) {
|
||||
pQueryInfo->groupbyExpr.orderIndex = index.columnIndex - tscGetNumOfColumns(pTableMetaInfo->pTableMeta);
|
||||
|
@ -5865,7 +5885,7 @@ int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSq
|
|||
|
||||
pExpr = tscExprGet(pQueryInfo, 1);
|
||||
if (pExpr->base.colInfo.colIndex != index.columnIndex && index.columnIndex != PRIMARYKEY_TIMESTAMP_COL_INDEX) {
|
||||
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg2);
|
||||
return invalidOperationMsg(pMsgBuf, msg5);
|
||||
}
|
||||
|
||||
tVariantListItem* p1 = taosArrayGet(pSqlNode->pSortOrder, 0);
|
||||
|
@ -5880,12 +5900,21 @@ int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSq
|
|||
|
||||
// orderby ts query on super table
|
||||
if (tscOrderedProjectionQueryOnSTable(pQueryInfo, 0)) {
|
||||
addPrimaryTsColIntoResult(pQueryInfo, pCmd);
|
||||
bool found = false;
|
||||
for (int32_t i = 0; i < tscNumOfExprs(pQueryInfo); ++i) {
|
||||
SExprInfo* pExpr = tscExprGet(pQueryInfo, i);
|
||||
if (pExpr->base.functionId == TSDB_FUNC_PRJ && pExpr->base.colInfo.colId == PRIMARYKEY_TIMESTAMP_COL_INDEX) {
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!found && pQueryInfo->pDownstream) {
|
||||
return invalidOperationMsg(pMsgBuf, msg9);
|
||||
}
|
||||
addPrimaryTsColIntoResult(pQueryInfo, pCmd);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (s == 2) {
|
||||
} else {
|
||||
tVariantListItem *pItem = taosArrayGet(pSqlNode->pSortOrder, 0);
|
||||
if (orderByTags) {
|
||||
pQueryInfo->groupbyExpr.orderIndex = index.columnIndex - tscGetNumOfColumns(pTableMetaInfo->pTableMeta);
|
||||
|
@ -5902,22 +5931,23 @@ int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSq
|
|||
tVariant* pVar2 = &pItem->pVar;
|
||||
SStrToken cname = {pVar2->nLen, pVar2->nType, pVar2->pz};
|
||||
if (getColumnIndexByName(&cname, pQueryInfo, &index, tscGetErrorMsgPayload(pCmd)) != TSDB_CODE_SUCCESS) {
|
||||
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg1);
|
||||
return invalidOperationMsg(pMsgBuf, msg1);
|
||||
}
|
||||
|
||||
if (index.columnIndex != PRIMARYKEY_TIMESTAMP_COL_INDEX) {
|
||||
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg2);
|
||||
return invalidOperationMsg(pMsgBuf, msg6);
|
||||
} else {
|
||||
tVariantListItem* p1 = taosArrayGet(pSortorder, 1);
|
||||
tVariantListItem* p1 = taosArrayGet(pSortOrder, 1);
|
||||
pQueryInfo->order.order = p1->sortOrder;
|
||||
pQueryInfo->order.orderColId = PRIMARYKEY_TIMESTAMP_COL_INDEX;
|
||||
}
|
||||
}
|
||||
|
||||
} else { // meter query
|
||||
if (getColumnIndexByName(&columnName, pQueryInfo, &index, tscGetErrorMsgPayload(pCmd)) != TSDB_CODE_SUCCESS) {
|
||||
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg1);
|
||||
} else if (UTIL_TABLE_IS_NORMAL_TABLE(pTableMetaInfo) || UTIL_TABLE_IS_CHILD_TABLE(pTableMetaInfo)) { // check order by clause for normal table & temp table
|
||||
if (getColumnIndexByName(&columnName, pQueryInfo, &index, pMsgBuf) != TSDB_CODE_SUCCESS) {
|
||||
return invalidOperationMsg(pMsgBuf, msg1);
|
||||
}
|
||||
|
||||
if (index.columnIndex != PRIMARYKEY_TIMESTAMP_COL_INDEX && !isTopBottomQuery(pQueryInfo)) {
|
||||
bool validOrder = false;
|
||||
SArray *columnInfo = pQueryInfo->groupbyExpr.columnInfo;
|
||||
|
@ -5925,21 +5955,24 @@ int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSq
|
|||
SColIndex* pColIndex = taosArrayGet(columnInfo, 0);
|
||||
validOrder = (pColIndex->colIndex == index.columnIndex);
|
||||
}
|
||||
|
||||
if (!validOrder) {
|
||||
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg2);
|
||||
return invalidOperationMsg(pMsgBuf, msg7);
|
||||
}
|
||||
|
||||
tVariantListItem* p1 = taosArrayGet(pSqlNode->pSortOrder, 0);
|
||||
pQueryInfo->groupbyExpr.orderIndex = pSchema[index.columnIndex].colId;
|
||||
pQueryInfo->groupbyExpr.orderType = p1->sortOrder;
|
||||
|
||||
}
|
||||
|
||||
if (isTopBottomQuery(pQueryInfo)) {
|
||||
bool validOrder = false;
|
||||
SArray *columnInfo = pQueryInfo->groupbyExpr.columnInfo;
|
||||
if (columnInfo != NULL && taosArrayGetSize(columnInfo) > 0) {
|
||||
SColIndex* pColIndex = taosArrayGet(columnInfo, 0);
|
||||
validOrder = (pColIndex->colIndex == index.columnIndex);
|
||||
|
||||
if (pColIndex->colIndex == index.columnIndex) {
|
||||
return invalidOperationMsg(pMsgBuf, msg8);
|
||||
}
|
||||
} else {
|
||||
/* order of top/bottom query in interval is not valid */
|
||||
SExprInfo* pExpr = tscExprGet(pQueryInfo, 0);
|
||||
|
@ -5947,13 +5980,8 @@ int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSq
|
|||
|
||||
pExpr = tscExprGet(pQueryInfo, 1);
|
||||
if (pExpr->base.colInfo.colIndex != index.columnIndex && index.columnIndex != PRIMARYKEY_TIMESTAMP_COL_INDEX) {
|
||||
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg2);
|
||||
return invalidOperationMsg(pMsgBuf, msg5);
|
||||
}
|
||||
validOrder = true;
|
||||
}
|
||||
|
||||
if (!validOrder) {
|
||||
return invalidOperationMsg(tscGetErrorMsgPayload(pCmd), msg2);
|
||||
}
|
||||
|
||||
tVariantListItem* pItem = taosArrayGet(pSqlNode->pSortOrder, 0);
|
||||
|
@ -5963,6 +5991,18 @@ int32_t validateOrderbyNode(SSqlCmd* pCmd, SQueryInfo* pQueryInfo, SSqlNode* pSq
|
|||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
tVariantListItem* pItem = taosArrayGet(pSqlNode->pSortOrder, 0);
|
||||
pQueryInfo->order.order = pItem->sortOrder;
|
||||
pQueryInfo->order.orderColId = pSchema[index.columnIndex].colId;
|
||||
} else {
|
||||
// handle the temp table order by clause. You can order by any single column in case of the temp table, created by
|
||||
// inner subquery.
|
||||
assert(UTIL_TABLE_IS_TMP_TABLE(pTableMetaInfo) && taosArrayGetSize(pSqlNode->pSortOrder) == 1);
|
||||
|
||||
if (getColumnIndexByName(&columnName, pQueryInfo, &index, pMsgBuf) != TSDB_CODE_SUCCESS) {
|
||||
return invalidOperationMsg(pMsgBuf, msg1);
|
||||
}
|
||||
|
||||
tVariantListItem* pItem = taosArrayGet(pSqlNode->pSortOrder, 0);
|
||||
pQueryInfo->order.order = pItem->sortOrder;
|
||||
pQueryInfo->order.orderColId = pSchema[index.columnIndex].colId;
|
||||
|
@ -8643,6 +8683,8 @@ static STableMeta* extractTempTableMetaFromSubquery(SQueryInfo* pUpstream) {
|
|||
|
||||
n += 1;
|
||||
}
|
||||
info->numOfColumns = n;
|
||||
|
||||
|
||||
return meta;
|
||||
}
|
||||
|
@ -8666,12 +8708,12 @@ static int32_t doValidateSubquery(SSqlNode* pSqlNode, int32_t index, SSqlObj* pS
|
|||
pSub->pUdfInfo = pUdfInfo;
|
||||
pSub->udfCopy = true;
|
||||
|
||||
pSub->pDownstream = pQueryInfo;
|
||||
int32_t code = validateSqlNode(pSql, p, pSub);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
return code;
|
||||
}
|
||||
|
||||
pSub->pDownstream = pQueryInfo;
|
||||
|
||||
// create dummy table meta info
|
||||
STableMetaInfo* pTableMetaInfo1 = calloc(1, sizeof(STableMetaInfo));
|
||||
|
@ -8730,8 +8772,7 @@ int32_t validateSqlNode(SSqlObj* pSql, SSqlNode* pSqlNode, SQueryInfo* pQueryInf
|
|||
const char* msg8 = "condition missing for join query";
|
||||
const char* msg9 = "not support 3 level select";
|
||||
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
SSqlCmd* pCmd = &pSql->cmd;
|
||||
|
||||
STableMetaInfo *pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0);
|
||||
|
@ -8753,7 +8794,7 @@ int32_t validateSqlNode(SSqlObj* pSql, SSqlNode* pSqlNode, SQueryInfo* pQueryInf
|
|||
}
|
||||
|
||||
if (pSqlNode->from->type == SQL_NODE_FROM_SUBQUERY) {
|
||||
clearAllTableMetaInfo(pQueryInfo, false);
|
||||
clearAllTableMetaInfo(pQueryInfo, false, pSql->self);
|
||||
pQueryInfo->numOfTables = 0;
|
||||
|
||||
// parse the subquery in the first place
|
||||
|
@ -8780,6 +8821,7 @@ int32_t validateSqlNode(SSqlObj* pSql, SSqlNode* pSqlNode, SQueryInfo* pQueryInf
|
|||
if (validateGroupbyNode(pQueryInfo, pSqlNode->pGroupby, pCmd) != TSDB_CODE_SUCCESS) {
|
||||
return TSDB_CODE_TSC_INVALID_OPERATION;
|
||||
}
|
||||
|
||||
|
||||
if (validateSelectNodeList(pCmd, pQueryInfo, pSqlNode->pSelNodeList, false, timeWindowQuery, true) !=
|
||||
TSDB_CODE_SUCCESS) {
|
||||
|
@ -9022,8 +9064,6 @@ int32_t validateSqlNode(SSqlObj* pSql, SSqlNode* pSqlNode, SQueryInfo* pQueryInf
|
|||
pQueryInfo->simpleAgg = isSimpleAggregateRv(pQueryInfo);
|
||||
pQueryInfo->onlyTagQuery = onlyTagPrjFunction(pQueryInfo);
|
||||
pQueryInfo->groupbyColumn = tscGroupbyColumn(pQueryInfo);
|
||||
//pQueryInfo->globalMerge = tscIsTwoStageSTableQuery(pQueryInfo, 0);
|
||||
|
||||
pQueryInfo->arithmeticOnAgg = tsIsArithmeticQueryOnAggResult(pQueryInfo);
|
||||
pQueryInfo->orderProjectQuery = tscOrderedProjectionQueryOnSTable(pQueryInfo, 0);
|
||||
|
||||
|
|
|
@ -409,7 +409,7 @@ static void doProcessMsgFromServer(SSchedMsg* pSchedMsg) {
|
|||
if ((TSDB_QUERY_HAS_TYPE(pQueryInfo->type, (TSDB_QUERY_TYPE_STABLE_SUBQUERY | TSDB_QUERY_TYPE_SUBQUERY |
|
||||
TSDB_QUERY_TYPE_TAG_FILTER_QUERY)) &&
|
||||
!TSDB_QUERY_HAS_TYPE(pQueryInfo->type, TSDB_QUERY_TYPE_PROJECTION_QUERY)) ||
|
||||
(TSDB_QUERY_HAS_TYPE(pQueryInfo->type, TSDB_QUERY_TYPE_NEST_SUBQUERY))) {
|
||||
(TSDB_QUERY_HAS_TYPE(pQueryInfo->type, TSDB_QUERY_TYPE_NEST_SUBQUERY)) || (TSDB_QUERY_HAS_TYPE(pQueryInfo->type, TSDB_QUERY_TYPE_STABLE_SUBQUERY) && pQueryInfo->distinct)) {
|
||||
// do nothing in case of super table subquery
|
||||
} else {
|
||||
pSql->retry += 1;
|
||||
|
@ -502,13 +502,25 @@ static void doProcessMsgFromServer(SSchedMsg* pSchedMsg) {
|
|||
}
|
||||
rpcMsg->code = (pRes->code == TSDB_CODE_SUCCESS) ? (int32_t)pRes->numOfRows : pRes->code;
|
||||
if (pRes->code == TSDB_CODE_RPC_FQDN_ERROR) {
|
||||
tscAllocPayload(pCmd, TSDB_FQDN_LEN + 64);
|
||||
// handle three situation
|
||||
// 1. epset retry, only return last failure ep
|
||||
// 2. no epset retry, like 'taos -h invalidFqdn', return invalidFqdn
|
||||
// 3. other situation, no expected
|
||||
if (pEpSet) {
|
||||
char buf[TSDB_FQDN_LEN + 64] = {0};
|
||||
tscAllocPayload(pCmd, sizeof(buf));
|
||||
sprintf(tscGetErrorMsgPayload(pCmd), "%s\"%s\"", tstrerror(pRes->code),pEpSet->fqdn[(pEpSet->inUse)%(pEpSet->numOfEps)]);
|
||||
} else if (pCmd->command >= TSDB_SQL_MGMT) {
|
||||
SRpcEpSet tEpset;
|
||||
|
||||
SRpcCorEpSet *pCorEpSet = pSql->pTscObj->tscCorMgmtEpSet;
|
||||
taosCorBeginRead(&pCorEpSet->version);
|
||||
tEpset = pCorEpSet->epSet;
|
||||
taosCorEndRead(&pCorEpSet->version);
|
||||
|
||||
sprintf(tscGetErrorMsgPayload(pCmd), "%s\"%s\"", tstrerror(pRes->code),tEpset.fqdn[(tEpset.inUse)%(tEpset.numOfEps)]);
|
||||
} else {
|
||||
sprintf(tscGetErrorMsgPayload(pCmd), "%s", tstrerror(pRes->code));
|
||||
}
|
||||
}
|
||||
}
|
||||
(*pSql->fp)(pSql->param, pSql, rpcMsg->code);
|
||||
}
|
||||
|
@ -525,6 +537,7 @@ static void doProcessMsgFromServer(SSchedMsg* pSchedMsg) {
|
|||
}
|
||||
|
||||
void tscProcessMsgFromServer(SRpcMsg *rpcMsg, SRpcEpSet *pEpSet) {
|
||||
int64_t st = taosGetTimestampUs();
|
||||
SSchedMsg schedMsg = {0};
|
||||
|
||||
schedMsg.fp = doProcessMsgFromServer;
|
||||
|
@ -543,6 +556,11 @@ void tscProcessMsgFromServer(SRpcMsg *rpcMsg, SRpcEpSet *pEpSet) {
|
|||
schedMsg.msg = NULL;
|
||||
|
||||
taosScheduleTask(tscQhandle, &schedMsg);
|
||||
|
||||
int64_t et = taosGetTimestampUs();
|
||||
if (et - st > 100) {
|
||||
tscDebug("add message to task queue, elapsed time:%"PRId64, et - st);
|
||||
}
|
||||
}
|
||||
|
||||
int doBuildAndSendMsg(SSqlObj *pSql) {
|
||||
|
@ -897,16 +915,16 @@ int tscBuildQueryMsg(SSqlObj *pSql, SSqlInfo *pInfo) {
|
|||
}
|
||||
|
||||
SQueryInfo *pQueryInfo = tscGetQueryInfo(pCmd);
|
||||
STableMetaInfo *pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0);
|
||||
STableMeta * pTableMeta = pTableMetaInfo->pTableMeta;
|
||||
|
||||
SQueryAttr query = {{0}};
|
||||
tscCreateQueryFromQueryInfo(pQueryInfo, &query, pSql);
|
||||
query.vgId = pTableMeta->vgId;
|
||||
|
||||
SArray* tableScanOperator = createTableScanPlan(&query);
|
||||
SArray* queryOperator = createExecOperatorPlan(&query);
|
||||
|
||||
STableMetaInfo *pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0);
|
||||
STableMeta * pTableMeta = pTableMetaInfo->pTableMeta;
|
||||
|
||||
SQueryTableMsg *pQueryMsg = (SQueryTableMsg *)pCmd->payload;
|
||||
tstrncpy(pQueryMsg->version, version, tListLen(pQueryMsg->version));
|
||||
|
||||
|
@ -2269,6 +2287,10 @@ int tscProcessMultiTableMetaRsp(SSqlObj *pSql) {
|
|||
pMsg = buf;
|
||||
}
|
||||
|
||||
if (pParentCmd->pTableMetaMap == NULL) {
|
||||
pParentCmd->pTableMetaMap = taosHashInit(4, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), false, HASH_NO_LOCK);
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < pMultiMeta->numOfTables; i++) {
|
||||
STableMetaMsg *pMetaMsg = (STableMetaMsg *)pMsg;
|
||||
int32_t code = tableMetaMsgConvert(pMetaMsg);
|
||||
|
@ -2605,7 +2627,7 @@ int tscProcessDropDbRsp(SSqlObj *pSql) {
|
|||
|
||||
int tscProcessDropTableRsp(SSqlObj *pSql) {
|
||||
STableMetaInfo *pTableMetaInfo = tscGetTableMetaInfoFromCmd(&pSql->cmd, 0);
|
||||
tscRemoveTableMetaBuf(pTableMetaInfo, pSql->self);
|
||||
tscRemoveCachedTableMeta(pTableMetaInfo, pSql->self);
|
||||
tfree(pTableMetaInfo->pTableMeta);
|
||||
return 0;
|
||||
}
|
||||
|
@ -2656,6 +2678,50 @@ int tscProcessQueryRsp(SSqlObj *pSql) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void decompressQueryColData(SSqlRes *pRes, SQueryInfo* pQueryInfo, char **data, int8_t compressed, int compLen) {
|
||||
int32_t decompLen = 0;
|
||||
int32_t numOfCols = pQueryInfo->fieldsInfo.numOfOutput;
|
||||
int32_t *compSizes;
|
||||
char *pData = *data;
|
||||
compSizes = (int32_t *)(pData + compLen);
|
||||
|
||||
TAOS_FIELD *pField = tscFieldInfoGetField(&pQueryInfo->fieldsInfo, numOfCols - 1);
|
||||
int16_t offset = tscFieldInfoGetOffset(pQueryInfo, numOfCols - 1);
|
||||
char *outputBuf = tcalloc(pRes->numOfRows, (pField->bytes + offset));
|
||||
|
||||
char *p = outputBuf;
|
||||
int32_t bufOffset;
|
||||
for (int32_t i = 0; i < numOfCols; ++i) {
|
||||
SInternalField* pInfo = (SInternalField*)TARRAY_GET_ELEM(pQueryInfo->fieldsInfo.internalField, i);
|
||||
bufOffset = pInfo->field.bytes * pRes->numOfRows;
|
||||
|
||||
int32_t flen = (*(tDataTypes[pInfo->field.type].decompFunc))(pData, htonl(compSizes[i]), pRes->numOfRows, p, bufOffset,
|
||||
compressed, NULL, 0);
|
||||
|
||||
p += flen;
|
||||
decompLen +=flen;
|
||||
pData += htonl(compSizes[i]);
|
||||
}
|
||||
|
||||
/* Resize rsp as decompressed data will occupy more space */
|
||||
pRes->rspLen = pRes->rspLen - (compLen + numOfCols * sizeof(int32_t)) + decompLen;
|
||||
char *new_rsp = (char *)realloc(pRes->pRsp, pRes->rspLen);
|
||||
if (new_rsp == NULL) {
|
||||
pRes->code = TSDB_CODE_TSC_OUT_OF_MEMORY;
|
||||
return;
|
||||
} else {
|
||||
pRes->pRsp = new_rsp;
|
||||
*data = ((SRetrieveTableRsp *)pRes->pRsp)->data;
|
||||
pData = *data + compLen + numOfCols * sizeof(int32_t);
|
||||
}
|
||||
|
||||
int32_t tailLen = pRes->rspLen - sizeof(SRetrieveTableRsp) - decompLen;
|
||||
memmove(*data + decompLen, pData, tailLen);
|
||||
memmove(*data, outputBuf, decompLen);
|
||||
|
||||
tfree(outputBuf);
|
||||
}
|
||||
|
||||
int tscProcessRetrieveRspFromNode(SSqlObj *pSql) {
|
||||
SSqlRes *pRes = &pSql->res;
|
||||
SSqlCmd *pCmd = &pSql->cmd;
|
||||
|
@ -2668,18 +2734,24 @@ int tscProcessRetrieveRspFromNode(SSqlObj *pSql) {
|
|||
return pRes->code;
|
||||
}
|
||||
|
||||
pRes->numOfRows = htonl(pRetrieve->numOfRows);
|
||||
pRes->precision = htons(pRetrieve->precision);
|
||||
pRes->offset = htobe64(pRetrieve->offset);
|
||||
pRes->useconds = htobe64(pRetrieve->useconds);
|
||||
pRes->completed = (pRetrieve->completed == 1);
|
||||
pRes->data = pRetrieve->data;
|
||||
|
||||
pRes->numOfRows = htonl(pRetrieve->numOfRows);
|
||||
pRes->precision = htons(pRetrieve->precision);
|
||||
pRes->offset = htobe64(pRetrieve->offset);
|
||||
pRes->useconds = htobe64(pRetrieve->useconds);
|
||||
pRes->completed = (pRetrieve->completed == 1);
|
||||
pRes->data = pRetrieve->data;
|
||||
|
||||
SQueryInfo* pQueryInfo = tscGetQueryInfo(pCmd);
|
||||
if (tscCreateResPointerInfo(pRes, pQueryInfo) != TSDB_CODE_SUCCESS) {
|
||||
return pRes->code;
|
||||
}
|
||||
|
||||
//Decompress col data if compressed from server
|
||||
if (pRetrieve->compressed) {
|
||||
int32_t compLen = htonl(pRetrieve->compLen);
|
||||
decompressQueryColData(pRes, pQueryInfo, &pRes->data, pRetrieve->compressed, compLen);
|
||||
}
|
||||
|
||||
STableMetaInfo *pTableMetaInfo = tscGetMetaInfo(pQueryInfo, 0);
|
||||
if ((pCmd->command == TSDB_SQL_RETRIEVE) ||
|
||||
((UTIL_TABLE_IS_CHILD_TABLE(pTableMetaInfo) || UTIL_TABLE_IS_NORMAL_TABLE(pTableMetaInfo)) &&
|
||||
|
@ -2692,10 +2764,10 @@ int tscProcessRetrieveRspFromNode(SSqlObj *pSql) {
|
|||
|
||||
if (pSql->pSubscription != NULL) {
|
||||
int32_t numOfCols = pQueryInfo->fieldsInfo.numOfOutput;
|
||||
|
||||
|
||||
TAOS_FIELD *pField = tscFieldInfoGetField(&pQueryInfo->fieldsInfo, numOfCols - 1);
|
||||
int16_t offset = tscFieldInfoGetOffset(pQueryInfo, numOfCols - 1);
|
||||
|
||||
|
||||
char* p = pRes->data + (pField->bytes + offset) * pRes->numOfRows;
|
||||
|
||||
int32_t numOfTables = htonl(*(int32_t*)p);
|
||||
|
@ -2990,13 +3062,11 @@ int tscRenewTableMeta(SSqlObj *pSql, int32_t tableIndex) {
|
|||
tscGetNumOfTags(pTableMeta), tscGetNumOfColumns(pTableMeta), pTableMeta->id.uid);
|
||||
}
|
||||
|
||||
|
||||
// remove stored tableMeta info in hash table
|
||||
tscRemoveTableMetaBuf(pTableMetaInfo, pSql->self);
|
||||
tscResetSqlCmd(pCmd, true, pSql->self);
|
||||
|
||||
pCmd->pTableMetaMap = tscCleanupTableMetaMap(pCmd->pTableMetaMap);
|
||||
pCmd->pTableMetaMap = taosHashInit(4, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), false, HASH_NO_LOCK);
|
||||
|
||||
SArray* pNameList = taosArrayInit(1, POINTER_BYTES);
|
||||
SArray* pNameList = taosArrayInit(1, POINTER_BYTES);
|
||||
SArray* vgroupList = taosArrayInit(1, POINTER_BYTES);
|
||||
|
||||
char* n = strdup(name);
|
||||
|
|
|
@ -113,7 +113,7 @@ static void doLaunchQuery(void* param, TAOS_RES* tres, int32_t code) {
|
|||
|
||||
pQueryInfo->command = TSDB_SQL_SELECT;
|
||||
|
||||
pSql->fp = tscProcessStreamQueryCallback;
|
||||
pSql->fp = tscProcessStreamQueryCallback;
|
||||
pSql->fetchFp = tscProcessStreamQueryCallback;
|
||||
executeQuery(pSql, pQueryInfo);
|
||||
tscIncStreamExecutionCount(pStream);
|
||||
|
@ -142,6 +142,7 @@ static void tscProcessStreamTimer(void *handle, void *tmrId) {
|
|||
if(pSql == NULL) {
|
||||
return ;
|
||||
}
|
||||
|
||||
SQueryInfo* pQueryInfo = tscGetQueryInfo(&pSql->cmd);
|
||||
tscDebug("0x%"PRIx64" add into timer", pSql->self);
|
||||
|
||||
|
@ -186,14 +187,16 @@ static void tscProcessStreamTimer(void *handle, void *tmrId) {
|
|||
}
|
||||
|
||||
// launch stream computing in a new thread
|
||||
SSchedMsg schedMsg = { 0 };
|
||||
schedMsg.fp = tscProcessStreamLaunchQuery;
|
||||
SSchedMsg schedMsg = {0};
|
||||
schedMsg.fp = tscProcessStreamLaunchQuery;
|
||||
schedMsg.ahandle = pStream;
|
||||
schedMsg.thandle = (void *)1;
|
||||
schedMsg.msg = NULL;
|
||||
schedMsg.msg = NULL;
|
||||
taosScheduleTask(tscQhandle, &schedMsg);
|
||||
}
|
||||
|
||||
static void cbParseSql(void* param, TAOS_RES* res, int code);
|
||||
|
||||
static void tscProcessStreamQueryCallback(void *param, TAOS_RES *tres, int numOfRows) {
|
||||
SSqlStream *pStream = (SSqlStream *)param;
|
||||
if (tres == NULL || numOfRows < 0) {
|
||||
|
@ -201,24 +204,26 @@ static void tscProcessStreamQueryCallback(void *param, TAOS_RES *tres, int numOf
|
|||
tscError("0x%"PRIx64" stream:%p, query data failed, code:0x%08x, retry in %" PRId64 "ms", pStream->pSql->self,
|
||||
pStream, numOfRows, retryDelay);
|
||||
|
||||
STableMetaInfo* pTableMetaInfo = tscGetTableMetaInfoFromCmd(&pStream->pSql->cmd, 0);
|
||||
SSqlObj* pSql = pStream->pSql;
|
||||
|
||||
char name[TSDB_TABLE_FNAME_LEN] = {0};
|
||||
tNameExtractFullName(&pTableMetaInfo->name, name);
|
||||
tscFreeSqlResult(pSql);
|
||||
tscFreeSubobj(pSql);
|
||||
tfree(pSql->pSubs);
|
||||
pSql->subState.numOfSub = 0;
|
||||
|
||||
taosHashRemove(tscTableMetaMap, name, strnlen(name, TSDB_TABLE_FNAME_LEN));
|
||||
int32_t code = tsParseSql(pSql, true);
|
||||
if (code == TSDB_CODE_SUCCESS) {
|
||||
cbParseSql(pStream, pSql, code);
|
||||
} else if (code == TSDB_CODE_TSC_ACTION_IN_PROGRESS) {
|
||||
tscDebug("0x%"PRIx64" CQ taso_open_stream IN Process", pSql->self);
|
||||
} else {
|
||||
tscError("0x%"PRIx64" open stream failed, code:%s", pSql->self, tstrerror(code));
|
||||
taosReleaseRef(tscObjRef, pSql->self);
|
||||
free(pStream);
|
||||
}
|
||||
|
||||
tfree(pTableMetaInfo->pTableMeta);
|
||||
|
||||
tscFreeSqlResult(pStream->pSql);
|
||||
tscFreeSubobj(pStream->pSql);
|
||||
tfree(pStream->pSql->pSubs);
|
||||
pStream->pSql->subState.numOfSub = 0;
|
||||
|
||||
pTableMetaInfo->vgroupList = tscVgroupInfoClear(pTableMetaInfo->vgroupList);
|
||||
|
||||
tscSetRetryTimer(pStream, pStream->pSql, retryDelay);
|
||||
return;
|
||||
// tscSetRetryTimer(pStream, pStream->pSql, retryDelay);
|
||||
// return;
|
||||
}
|
||||
|
||||
taos_fetch_rows_a(tres, tscProcessStreamRetrieveResult, param);
|
||||
|
@ -555,7 +560,6 @@ static void tscCreateStream(void *param, TAOS_RES *res, int code) {
|
|||
if (code != TSDB_CODE_SUCCESS) {
|
||||
pSql->res.code = code;
|
||||
tscError("0x%"PRIx64" open stream failed, sql:%s, reason:%s, code:%s", pSql->self, pSql->sqlstr, pCmd->payload, tstrerror(code));
|
||||
|
||||
pStream->fp(pStream->param, NULL, NULL);
|
||||
return;
|
||||
}
|
||||
|
@ -582,9 +586,10 @@ static void tscCreateStream(void *param, TAOS_RES *res, int code) {
|
|||
|
||||
// set stime with ltime if ltime > stime
|
||||
const char* dstTable = pStream->dstTable? pStream->dstTable: "";
|
||||
tscDebug(" CQ table=%s ltime is %"PRId64, dstTable, pStream->ltime);
|
||||
tscDebug("0x%"PRIx64" CQ table %s ltime is %"PRId64, pSql->self, dstTable, pStream->ltime);
|
||||
|
||||
if(pStream->ltime != INT64_MIN && pStream->ltime > pStream->stime) {
|
||||
tscWarn(" CQ set stream %s stime=%"PRId64" replace with ltime=%"PRId64" if ltime>0 ", dstTable, pStream->stime, pStream->ltime);
|
||||
tscWarn("0x%"PRIx64" CQ set stream %s stime=%"PRId64" replace with ltime=%"PRId64" if ltime > 0", pSql->self, dstTable, pStream->stime, pStream->ltime);
|
||||
pStream->stime = pStream->ltime;
|
||||
}
|
||||
|
||||
|
@ -592,7 +597,6 @@ static void tscCreateStream(void *param, TAOS_RES *res, int code) {
|
|||
pCmd->command = TSDB_SQL_SELECT;
|
||||
|
||||
tscAddIntoStreamList(pStream);
|
||||
|
||||
taosTmrReset(tscProcessStreamTimer, (int32_t)starttime, pStream, tscTmr, &pStream->pTimer);
|
||||
|
||||
tscDebug("0x%"PRIx64" stream:%p is opened, query on:%s, interval:%" PRId64 ", sliding:%" PRId64 ", first launched in:%" PRId64 ", sql:%s", pSql->self,
|
||||
|
@ -659,10 +663,9 @@ void cbParseSql(void* param, TAOS_RES* res, int code) {
|
|||
char sql[128] = "";
|
||||
sprintf(sql, "select last_row(*) from %s;", pStream->dstTable);
|
||||
taos_query_a(pSql->pTscObj, sql, fpStreamLastRow, param);
|
||||
return ;
|
||||
}
|
||||
|
||||
TAOS_STREAM *taos_open_stream_withname(TAOS *taos, const char* dstTable, const char *sqlstr, void (*fp)(void *param, TAOS_RES *, TAOS_ROW row),
|
||||
TAOS_STREAM *taos_open_stream_withname(TAOS *taos, const char* dstTable, const char *sqlstr, void (*fp)(void *, TAOS_RES *, TAOS_ROW),
|
||||
int64_t stime, void *param, void (*callback)(void *), void* cqhandle) {
|
||||
STscObj *pObj = (STscObj *)taos;
|
||||
if (pObj == NULL || pObj->signature != pObj) return NULL;
|
||||
|
@ -697,14 +700,12 @@ TAOS_STREAM *taos_open_stream_withname(TAOS *taos, const char* dstTable, const c
|
|||
pStream->param = param;
|
||||
pStream->pSql = pSql;
|
||||
pStream->cqhandle = cqhandle;
|
||||
pSql->pStream = pStream;
|
||||
pSql->param = pStream;
|
||||
pSql->maxRetry = TSDB_MAX_REPLICA;
|
||||
tscSetStreamDestTable(pStream, dstTable);
|
||||
|
||||
pSql->pStream = pStream;
|
||||
pSql->param = pStream;
|
||||
pSql->maxRetry = TSDB_MAX_REPLICA;
|
||||
|
||||
pSql->sqlstr = calloc(1, strlen(sqlstr) + 1);
|
||||
if (pSql->sqlstr == NULL) {
|
||||
tscError("0x%"PRIx64" failed to malloc sql string buffer", pSql->self);
|
||||
|
@ -725,14 +726,13 @@ TAOS_STREAM *taos_open_stream_withname(TAOS *taos, const char* dstTable, const c
|
|||
|
||||
pSql->fp = cbParseSql;
|
||||
pSql->fetchFp = cbParseSql;
|
||||
|
||||
registerSqlObj(pSql);
|
||||
|
||||
int32_t code = tsParseSql(pSql, true);
|
||||
if (code == TSDB_CODE_SUCCESS) {
|
||||
cbParseSql(pStream, pSql, code);
|
||||
} else if (code == TSDB_CODE_TSC_ACTION_IN_PROGRESS) {
|
||||
tscDebug(" CQ taso_open_stream IN Process. sql=%s", sqlstr);
|
||||
tscDebug("0x%"PRIx64" CQ taso_open_stream IN Process", pSql->self);
|
||||
} else {
|
||||
tscError("0x%"PRIx64" open stream failed, sql:%s, code:%s", pSql->self, sqlstr, tstrerror(code));
|
||||
taosReleaseRef(tscObjRef, pSql->self);
|
||||
|
@ -743,7 +743,7 @@ TAOS_STREAM *taos_open_stream_withname(TAOS *taos, const char* dstTable, const c
|
|||
return pStream;
|
||||
}
|
||||
|
||||
TAOS_STREAM *taos_open_stream(TAOS *taos, const char *sqlstr, void (*fp)(void *param, TAOS_RES *, TAOS_ROW row),
|
||||
TAOS_STREAM *taos_open_stream(TAOS *taos, const char *sqlstr, void (*fp)(void *, TAOS_RES *, TAOS_ROW),
|
||||
int64_t stime, void *param, void (*callback)(void *)) {
|
||||
return taos_open_stream_withname(taos, "", sqlstr, fp, stime, param, callback, NULL);
|
||||
}
|
||||
|
|
|
@ -2404,8 +2404,8 @@ int32_t tscHandleFirstRoundStableQuery(SSqlObj *pSql) {
|
|||
SColumn* x = taosArrayGetP(pNewQueryInfo->colList, index1);
|
||||
tscColumnCopy(x, pCol);
|
||||
} else {
|
||||
SColumn *p = tscColumnClone(pCol);
|
||||
taosArrayPush(pNewQueryInfo->colList, &p);
|
||||
SSchema ss = {.type = (uint8_t)pCol->info.type, .bytes = pCol->info.bytes, .colId = (int16_t)pCol->columnIndex};
|
||||
tscColumnListInsert(pNewQueryInfo->colList, pCol->columnIndex, pCol->tableUid, &ss);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2433,6 +2433,26 @@ int32_t tscHandleFirstRoundStableQuery(SSqlObj *pSql) {
|
|||
return terrno;
|
||||
}
|
||||
|
||||
typedef struct SPair {
|
||||
int32_t first;
|
||||
int32_t second;
|
||||
} SPair;
|
||||
|
||||
static void doSendQueryReqs(SSchedMsg* pSchedMsg) {
|
||||
SSqlObj* pSql = pSchedMsg->ahandle;
|
||||
SPair* p = pSchedMsg->msg;
|
||||
|
||||
for(int32_t i = p->first; i < p->second; ++i) {
|
||||
SSqlObj* pSub = pSql->pSubs[i];
|
||||
SRetrieveSupport* pSupport = pSub->param;
|
||||
|
||||
tscDebug("0x%"PRIx64" sub:0x%"PRIx64" launch subquery, orderOfSub:%d.", pSql->self, pSub->self, pSupport->subqueryIndex);
|
||||
tscBuildAndSendRequest(pSub, NULL);
|
||||
}
|
||||
|
||||
tfree(p);
|
||||
}
|
||||
|
||||
int32_t tscHandleMasterSTableQuery(SSqlObj *pSql) {
|
||||
SSqlRes *pRes = &pSql->res;
|
||||
SSqlCmd *pCmd = &pSql->cmd;
|
||||
|
@ -2555,13 +2575,33 @@ int32_t tscHandleMasterSTableQuery(SSqlObj *pSql) {
|
|||
doCleanupSubqueries(pSql, i);
|
||||
return pRes->code;
|
||||
}
|
||||
|
||||
for(int32_t j = 0; j < pState->numOfSub; ++j) {
|
||||
SSqlObj* pSub = pSql->pSubs[j];
|
||||
SRetrieveSupport* pSupport = pSub->param;
|
||||
|
||||
tscDebug("0x%"PRIx64" sub:0x%"PRIx64" launch subquery, orderOfSub:%d.", pSql->self, pSub->self, pSupport->subqueryIndex);
|
||||
tscBuildAndSendRequest(pSub, NULL);
|
||||
|
||||
// concurrently sent the query requests.
|
||||
const int32_t MAX_REQUEST_PER_TASK = 8;
|
||||
|
||||
int32_t numOfTasks = (pState->numOfSub + MAX_REQUEST_PER_TASK - 1)/MAX_REQUEST_PER_TASK;
|
||||
assert(numOfTasks >= 1);
|
||||
|
||||
int32_t num = (pState->numOfSub/numOfTasks) + 1;
|
||||
tscDebug("0x%"PRIx64 " query will be sent by %d threads", pSql->self, numOfTasks);
|
||||
|
||||
for(int32_t j = 0; j < numOfTasks; ++j) {
|
||||
SSchedMsg schedMsg = {0};
|
||||
schedMsg.fp = doSendQueryReqs;
|
||||
schedMsg.ahandle = (void*)pSql;
|
||||
|
||||
schedMsg.thandle = NULL;
|
||||
SPair* p = calloc(1, sizeof(SPair));
|
||||
p->first = j * num;
|
||||
|
||||
if (j == numOfTasks - 1) {
|
||||
p->second = pState->numOfSub;
|
||||
} else {
|
||||
p->second = (j + 1) * num;
|
||||
}
|
||||
|
||||
schedMsg.msg = p;
|
||||
taosScheduleTask(tscQhandle, &schedMsg);
|
||||
}
|
||||
|
||||
return TSDB_CODE_SUCCESS;
|
||||
|
@ -2727,16 +2767,10 @@ void tscHandleSubqueryError(SRetrieveSupport *trsupport, SSqlObj *pSql, int numO
|
|||
int32_t code = pParentSql->res.code;
|
||||
if ((code == TSDB_CODE_TDB_INVALID_TABLE_ID || code == TSDB_CODE_VND_INVALID_VGROUP_ID) && pParentSql->retry < pParentSql->maxRetry) {
|
||||
// remove the cached tableMeta and vgroup id list, and then parse the sql again
|
||||
SSqlCmd* pParentCmd = &pParentSql->cmd;
|
||||
STableMetaInfo* pTableMetaInfo = tscGetTableMetaInfoFromCmd(pParentCmd, 0);
|
||||
tscRemoveTableMetaBuf(pTableMetaInfo, pParentSql->self);
|
||||
tscResetSqlCmd( &pParentSql->cmd, true, pParentSql->self);
|
||||
|
||||
pParentCmd->pTableMetaMap = tscCleanupTableMetaMap(pParentCmd->pTableMetaMap);
|
||||
pParentCmd->pTableMetaMap = taosHashInit(4, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), false, HASH_NO_LOCK);
|
||||
|
||||
pParentSql->res.code = TSDB_CODE_SUCCESS;
|
||||
pParentSql->retry++;
|
||||
|
||||
pParentSql->res.code = TSDB_CODE_SUCCESS;
|
||||
tscDebug("0x%"PRIx64" retry parse sql and send query, prev error: %s, retry:%d", pParentSql->self,
|
||||
tstrerror(code), pParentSql->retry);
|
||||
|
||||
|
@ -3040,7 +3074,7 @@ void tscRetrieveDataRes(void *param, TAOS_RES *tres, int code) {
|
|||
if (taos_errno(pSql) != TSDB_CODE_SUCCESS) {
|
||||
assert(code == taos_errno(pSql));
|
||||
|
||||
if (trsupport->numOfRetry++ < MAX_NUM_OF_SUBQUERY_RETRY && (code != TSDB_CODE_TDB_INVALID_TABLE_ID)) {
|
||||
if (trsupport->numOfRetry++ < MAX_NUM_OF_SUBQUERY_RETRY && (code != TSDB_CODE_TDB_INVALID_TABLE_ID && code != TSDB_CODE_VND_INVALID_VGROUP_ID)) {
|
||||
tscError("0x%"PRIx64" sub:0x%"PRIx64" failed code:%s, retry:%d", pParentSql->self, pSql->self, tstrerror(code), trsupport->numOfRetry);
|
||||
|
||||
int32_t sent = 0;
|
||||
|
@ -3151,7 +3185,7 @@ static void multiVnodeInsertFinalize(void* param, TAOS_RES* tres, int numOfRows)
|
|||
numOfFailed += 1;
|
||||
|
||||
// clean up tableMeta in cache
|
||||
tscFreeQueryInfo(&pSql->cmd, false);
|
||||
tscFreeQueryInfo(&pSql->cmd, false, pSql->self);
|
||||
SQueryInfo* pQueryInfo = tscGetQueryInfoS(&pSql->cmd);
|
||||
STableMetaInfo* pMasterTableMetaInfo = tscGetTableMetaInfoFromCmd(&pParentObj->cmd, 0);
|
||||
tscAddTableMetaInfo(pQueryInfo, &pMasterTableMetaInfo->name, NULL, NULL, NULL, NULL);
|
||||
|
@ -3173,7 +3207,7 @@ static void multiVnodeInsertFinalize(void* param, TAOS_RES* tres, int numOfRows)
|
|||
}
|
||||
|
||||
pParentObj->res.code = TSDB_CODE_SUCCESS;
|
||||
tscResetSqlCmd(&pParentObj->cmd, false);
|
||||
tscResetSqlCmd(&pParentObj->cmd, false, pParentObj->self);
|
||||
|
||||
// in case of insert, redo parsing the sql string and build new submit data block for two reasons:
|
||||
// 1. the table Id(tid & uid) may have been update, the submit block needs to be updated accordingly.
|
||||
|
|
|
@ -821,17 +821,22 @@ static void doSetupSDataBlock(SSqlRes* pRes, SSDataBlock* pBlock, SFilterInfo* p
|
|||
// filter data if needed
|
||||
if (pFilterInfo) {
|
||||
//doSetFilterColumnInfo(pFilterInfo, numOfFilterCols, pBlock);
|
||||
doSetFilterColInfo(pFilterInfo, pBlock);
|
||||
filterSetColFieldData(pFilterInfo, pBlock->info.numOfCols, pBlock->pDataBlock);
|
||||
bool gotNchar = false;
|
||||
filterConverNcharColumns(pFilterInfo, pBlock->info.rows, &gotNchar);
|
||||
int8_t* p = calloc(pBlock->info.rows, sizeof(int8_t));
|
||||
int8_t* p = NULL;
|
||||
//bool all = doFilterDataBlock(pFilterInfo, numOfFilterCols, pBlock->info.rows, p);
|
||||
bool all = filterExecute(pFilterInfo, pBlock->info.rows, p);
|
||||
bool all = filterExecute(pFilterInfo, pBlock->info.rows, &p, NULL, 0);
|
||||
if (gotNchar) {
|
||||
filterFreeNcharColumns(pFilterInfo);
|
||||
}
|
||||
if (!all) {
|
||||
doCompactSDataBlock(pBlock, pBlock->info.rows, p);
|
||||
if (p) {
|
||||
doCompactSDataBlock(pBlock, pBlock->info.rows, p);
|
||||
} else {
|
||||
pBlock->info.rows = 0;
|
||||
pBlock->pBlockStatis = NULL; // clean the block statistics info
|
||||
}
|
||||
}
|
||||
|
||||
tfree(p);
|
||||
|
@ -1228,11 +1233,9 @@ void handleDownstreamOperator(SSqlObj** pSqlObjList, int32_t numOfUpstream, SQue
|
|||
if (pCond && pCond->cond) {
|
||||
createQueryFilter(pCond->cond, pCond->len, &pFilters);
|
||||
}
|
||||
//createInputDataFlterInfo(px, numOfCol1, &numOfFilterCols, &pFilterInfo);
|
||||
}
|
||||
|
||||
SOperatorInfo* pSourceOperator = createDummyInputOperator(pSqlObjList[0], pSchema, numOfCol1, pFilters);
|
||||
|
||||
pOutput->precision = pSqlObjList[0]->res.precision;
|
||||
|
||||
SSchema* schema = NULL;
|
||||
|
@ -1332,12 +1335,13 @@ static void tscDestroyResPointerInfo(SSqlRes* pRes) {
|
|||
pRes->data = NULL; // pRes->data points to the buffer of pRsp, no need to free
|
||||
}
|
||||
|
||||
void tscFreeQueryInfo(SSqlCmd* pCmd, bool removeMeta) {
|
||||
void tscFreeQueryInfo(SSqlCmd* pCmd, bool removeCachedMeta, uint64_t id) {
|
||||
if (pCmd == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
SQueryInfo* pQueryInfo = pCmd->pQueryInfo;
|
||||
|
||||
while(pQueryInfo != NULL) {
|
||||
SQueryInfo* p = pQueryInfo->sibling;
|
||||
|
||||
|
@ -1346,7 +1350,7 @@ void tscFreeQueryInfo(SSqlCmd* pCmd, bool removeMeta) {
|
|||
SQueryInfo* pUpQueryInfo = taosArrayGetP(pQueryInfo->pUpstream, i);
|
||||
freeQueryInfoImpl(pUpQueryInfo);
|
||||
|
||||
clearAllTableMetaInfo(pUpQueryInfo, removeMeta);
|
||||
clearAllTableMetaInfo(pUpQueryInfo, removeCachedMeta, id);
|
||||
if (pUpQueryInfo->pQInfo != NULL) {
|
||||
qDestroyQueryInfo(pUpQueryInfo->pQInfo);
|
||||
pUpQueryInfo->pQInfo = NULL;
|
||||
|
@ -1362,7 +1366,7 @@ void tscFreeQueryInfo(SSqlCmd* pCmd, bool removeMeta) {
|
|||
}
|
||||
|
||||
freeQueryInfoImpl(pQueryInfo);
|
||||
clearAllTableMetaInfo(pQueryInfo, removeMeta);
|
||||
clearAllTableMetaInfo(pQueryInfo, removeCachedMeta, id);
|
||||
|
||||
if (pQueryInfo->pQInfo != NULL) {
|
||||
qDestroyQueryInfo(pQueryInfo->pQInfo);
|
||||
|
@ -1391,7 +1395,7 @@ void destroyTableNameList(SInsertStatementParam* pInsertParam) {
|
|||
tfree(pInsertParam->pTableNameList);
|
||||
}
|
||||
|
||||
void tscResetSqlCmd(SSqlCmd* pCmd, bool clearCachedMeta) {
|
||||
void tscResetSqlCmd(SSqlCmd* pCmd, bool clearCachedMeta, uint64_t id) {
|
||||
pCmd->command = 0;
|
||||
pCmd->numOfCols = 0;
|
||||
pCmd->count = 0;
|
||||
|
@ -1405,19 +1409,8 @@ void tscResetSqlCmd(SSqlCmd* pCmd, bool clearCachedMeta) {
|
|||
tfree(pCmd->insertParam.tagData.data);
|
||||
pCmd->insertParam.tagData.dataLen = 0;
|
||||
|
||||
tscFreeQueryInfo(pCmd, clearCachedMeta);
|
||||
|
||||
if (pCmd->pTableMetaMap != NULL) {
|
||||
STableMetaVgroupInfo* p = taosHashIterate(pCmd->pTableMetaMap, NULL);
|
||||
while (p) {
|
||||
taosArrayDestroy(p->vgroupIdList);
|
||||
tfree(p->pTableMeta);
|
||||
p = taosHashIterate(pCmd->pTableMetaMap, p);
|
||||
}
|
||||
|
||||
taosHashCleanup(pCmd->pTableMetaMap);
|
||||
pCmd->pTableMetaMap = NULL;
|
||||
}
|
||||
tscFreeQueryInfo(pCmd, clearCachedMeta, id);
|
||||
pCmd->pTableMetaMap = tscCleanupTableMetaMap(pCmd->pTableMetaMap);
|
||||
}
|
||||
|
||||
void* tscCleanupTableMetaMap(SHashObj* pTableMetaMap) {
|
||||
|
@ -1513,8 +1506,6 @@ void tscFreeSqlObj(SSqlObj* pSql) {
|
|||
tscFreeMetaSqlObj(&pSql->metaRid);
|
||||
tscFreeMetaSqlObj(&pSql->svgroupRid);
|
||||
|
||||
tscFreeSubobj(pSql);
|
||||
|
||||
SSqlCmd* pCmd = &pSql->cmd;
|
||||
int32_t cmd = pCmd->command;
|
||||
if (cmd < TSDB_SQL_INSERT || cmd == TSDB_SQL_RETRIEVE_GLOBALMERGE || cmd == TSDB_SQL_RETRIEVE_EMPTY_RESULT ||
|
||||
|
@ -1522,6 +1513,8 @@ void tscFreeSqlObj(SSqlObj* pSql) {
|
|||
tscRemoveFromSqlList(pSql);
|
||||
}
|
||||
|
||||
tscFreeSubobj(pSql);
|
||||
|
||||
pSql->signature = NULL;
|
||||
pSql->fp = NULL;
|
||||
tfree(pSql->sqlstr);
|
||||
|
@ -1532,9 +1525,8 @@ void tscFreeSqlObj(SSqlObj* pSql) {
|
|||
pSql->self = 0;
|
||||
|
||||
tscFreeSqlResult(pSql);
|
||||
tscResetSqlCmd(pCmd, false);
|
||||
tscResetSqlCmd(pCmd, false, pSql->self);
|
||||
|
||||
memset(pCmd->payload, 0, (size_t)pCmd->allocSize);
|
||||
tfree(pCmd->payload);
|
||||
pCmd->allocSize = 0;
|
||||
|
||||
|
@ -3379,20 +3371,15 @@ SArray* tscVgroupTableInfoDup(SArray* pVgroupTables) {
|
|||
return pa;
|
||||
}
|
||||
|
||||
void clearAllTableMetaInfo(SQueryInfo* pQueryInfo, bool removeMeta) {
|
||||
void clearAllTableMetaInfo(SQueryInfo* pQueryInfo, bool removeMeta, uint64_t id) {
|
||||
for(int32_t i = 0; i < pQueryInfo->numOfTables; ++i) {
|
||||
STableMetaInfo* pTableMetaInfo = tscGetMetaInfo(pQueryInfo, i);
|
||||
|
||||
if (removeMeta) {
|
||||
char name[TSDB_TABLE_FNAME_LEN] = {0};
|
||||
tNameExtractFullName(&pTableMetaInfo->name, name);
|
||||
taosHashRemove(tscTableMetaMap, name, strnlen(name, TSDB_TABLE_FNAME_LEN));
|
||||
tscRemoveCachedTableMeta(pTableMetaInfo, id);
|
||||
}
|
||||
|
||||
tscFreeVgroupTableInfo(pTableMetaInfo->pVgroupTables);
|
||||
tscClearTableMetaInfo(pTableMetaInfo);
|
||||
|
||||
free(pTableMetaInfo);
|
||||
}
|
||||
|
||||
tfree(pQueryInfo->pTableMetaInfo);
|
||||
|
@ -3459,10 +3446,12 @@ void tscClearTableMetaInfo(STableMetaInfo* pTableMetaInfo) {
|
|||
}
|
||||
|
||||
tfree(pTableMetaInfo->pTableMeta);
|
||||
|
||||
pTableMetaInfo->vgroupList = tscVgroupInfoClear(pTableMetaInfo->vgroupList);
|
||||
|
||||
tscColumnListDestroy(pTableMetaInfo->tagColList);
|
||||
pTableMetaInfo->tagColList = NULL;
|
||||
|
||||
free(pTableMetaInfo);
|
||||
}
|
||||
|
||||
void tscResetForNextRetrieve(SSqlRes* pRes) {
|
||||
|
@ -3632,7 +3621,8 @@ SSqlObj* createSubqueryObj(SSqlObj* pSql, int16_t tableIndex, __async_cb_func_t
|
|||
pNewQueryInfo->prjOffset = pQueryInfo->prjOffset;
|
||||
pNewQueryInfo->numOfTables = 0;
|
||||
pNewQueryInfo->pTableMetaInfo = NULL;
|
||||
pNewQueryInfo->bufLen = pQueryInfo->bufLen;
|
||||
pNewQueryInfo->bufLen = pQueryInfo->bufLen;
|
||||
pNewQueryInfo->distinct = pQueryInfo->distinct;
|
||||
|
||||
pNewQueryInfo->buf = malloc(pQueryInfo->bufLen);
|
||||
if (pNewQueryInfo->buf == NULL) {
|
||||
|
@ -3860,13 +3850,7 @@ static void tscSubqueryCompleteCallback(void* param, TAOS_RES* tres, int code) {
|
|||
|
||||
// todo refactor
|
||||
tscDebug("0x%"PRIx64" all subquery response received, retry", pParentSql->self);
|
||||
|
||||
SSqlCmd* pParentCmd = &pParentSql->cmd;
|
||||
STableMetaInfo* pTableMetaInfo = tscGetTableMetaInfoFromCmd(pParentCmd, 0);
|
||||
tscRemoveTableMetaBuf(pTableMetaInfo, pParentSql->self);
|
||||
|
||||
pParentCmd->pTableMetaMap = tscCleanupTableMetaMap(pParentCmd->pTableMetaMap);
|
||||
pParentCmd->pTableMetaMap = taosHashInit(4, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), false, HASH_NO_LOCK);
|
||||
tscResetSqlCmd(&pParentSql->cmd, true, pParentSql->self);
|
||||
|
||||
pParentSql->res.code = TSDB_CODE_SUCCESS;
|
||||
pParentSql->retry++;
|
||||
|
@ -3885,7 +3869,7 @@ static void tscSubqueryCompleteCallback(void* param, TAOS_RES* tres, int code) {
|
|||
return;
|
||||
}
|
||||
|
||||
SQueryInfo *pQueryInfo = tscGetQueryInfo(pParentCmd);
|
||||
SQueryInfo *pQueryInfo = tscGetQueryInfo(&pParentSql->cmd);
|
||||
executeQuery(pParentSql, pQueryInfo);
|
||||
return;
|
||||
}
|
||||
|
@ -5009,7 +4993,7 @@ SNewVgroupInfo createNewVgroupInfo(SVgroupMsg *pVgroupMsg) {
|
|||
return info;
|
||||
}
|
||||
|
||||
void tscRemoveTableMetaBuf(STableMetaInfo* pTableMetaInfo, uint64_t id) {
|
||||
void tscRemoveCachedTableMeta(STableMetaInfo* pTableMetaInfo, uint64_t id) {
|
||||
char fname[TSDB_TABLE_FNAME_LEN] = {0};
|
||||
tNameExtractFullName(&pTableMetaInfo->name, fname);
|
||||
|
||||
|
|
|
@ -41,6 +41,7 @@ extern char tsArbitrator[];
|
|||
extern int8_t tsArbOnline;
|
||||
extern int64_t tsArbOnlineTimestamp;
|
||||
extern int32_t tsDnodeId;
|
||||
extern int64_t tsDnodeStartTime;
|
||||
|
||||
// common
|
||||
extern int tsRpcTimer;
|
||||
|
@ -59,6 +60,8 @@ extern char tsLocale[];
|
|||
extern char tsCharset[]; // default encode string
|
||||
extern int8_t tsEnableCoreFile;
|
||||
extern int32_t tsCompressMsgSize;
|
||||
extern int32_t tsCompressColData;
|
||||
extern int32_t tsMaxNumOfDistinctResults;
|
||||
extern char tsTempDir[];
|
||||
|
||||
//query buffer management
|
||||
|
@ -104,6 +107,9 @@ extern int32_t tsQuorum;
|
|||
extern int8_t tsUpdate;
|
||||
extern int8_t tsCacheLastRow;
|
||||
|
||||
//tsdb
|
||||
extern bool tsdbForceKeepFile;
|
||||
|
||||
// balance
|
||||
extern int8_t tsEnableBalance;
|
||||
extern int8_t tsAlternativeRole;
|
||||
|
|
|
@ -46,6 +46,7 @@ int8_t tsArbOnline = 0;
|
|||
int64_t tsArbOnlineTimestamp = TSDB_ARB_DUMMY_TIME;
|
||||
char tsEmail[TSDB_FQDN_LEN] = {0};
|
||||
int32_t tsDnodeId = 0;
|
||||
int64_t tsDnodeStartTime = 0;
|
||||
|
||||
// common
|
||||
int32_t tsRpcTimer = 300;
|
||||
|
@ -74,6 +75,14 @@ int32_t tsMaxBinaryDisplayWidth = 30;
|
|||
*/
|
||||
int32_t tsCompressMsgSize = -1;
|
||||
|
||||
/* denote if server needs to compress the retrieved column data before adding to the rpc response message body.
|
||||
* 0: disable column data compression
|
||||
* 1: enable column data compression
|
||||
* This option is default to disabled. Once enabled, compression will be conducted if any column has size more
|
||||
* than QUERY_COMP_THRESHOLD. Otherwise, no further compression is needed.
|
||||
*/
|
||||
int32_t tsCompressColData = 0;
|
||||
|
||||
// client
|
||||
int32_t tsMaxSQLStringLen = TSDB_MAX_ALLOWED_SQL_LEN;
|
||||
int32_t tsMaxWildCardsLen = TSDB_PATTERN_STRING_MAX_LEN;
|
||||
|
@ -86,6 +95,9 @@ int32_t tsMaxNumOfOrderedResults = 100000;
|
|||
// 10 ms for sliding time, the value will changed in case of time precision changed
|
||||
int32_t tsMinSlidingTime = 10;
|
||||
|
||||
// the maxinum number of distict query result
|
||||
int32_t tsMaxNumOfDistinctResults = 1000 * 10000;
|
||||
|
||||
// 1 us for interval time range, changed accordingly
|
||||
int32_t tsMinIntervalTime = 1;
|
||||
|
||||
|
@ -139,6 +151,11 @@ int32_t tsMinTablePerVnode = TSDB_TABLES_STEP;
|
|||
int32_t tsMaxTablePerVnode = TSDB_DEFAULT_TABLES;
|
||||
int32_t tsTableIncStepPerVnode = TSDB_TABLES_STEP;
|
||||
|
||||
// tsdb config
|
||||
|
||||
// For backward compatibility
|
||||
bool tsdbForceKeepFile = false;
|
||||
|
||||
// balance
|
||||
int8_t tsEnableBalance = 1;
|
||||
int8_t tsAlternativeRole = 0;
|
||||
|
@ -543,6 +560,17 @@ static void doInitGlobalConfig(void) {
|
|||
cfg.unitType = TAOS_CFG_UTYPE_NONE;
|
||||
taosInitConfigOption(cfg);
|
||||
|
||||
cfg.option = "maxNumOfDistinctRes";
|
||||
cfg.ptr = &tsMaxNumOfDistinctResults;
|
||||
cfg.valType = TAOS_CFG_VTYPE_INT32;
|
||||
cfg.cfgType = TSDB_CFG_CTYPE_B_CONFIG | TSDB_CFG_CTYPE_B_SHOW | TSDB_CFG_CTYPE_B_CLIENT;
|
||||
cfg.minValue = 10*10000;
|
||||
cfg.maxValue = 10000*10000;
|
||||
cfg.ptrLength = 0;
|
||||
cfg.unitType = TAOS_CFG_UTYPE_NONE;
|
||||
taosInitConfigOption(cfg);
|
||||
|
||||
|
||||
cfg.option = "numOfMnodes";
|
||||
cfg.ptr = &tsNumOfMnodes;
|
||||
cfg.valType = TAOS_CFG_VTYPE_INT32;
|
||||
|
@ -976,6 +1004,16 @@ static void doInitGlobalConfig(void) {
|
|||
cfg.unitType = TAOS_CFG_UTYPE_NONE;
|
||||
taosInitConfigOption(cfg);
|
||||
|
||||
cfg.option = "compressColData";
|
||||
cfg.ptr = &tsCompressColData;
|
||||
cfg.valType = TAOS_CFG_VTYPE_INT8;
|
||||
cfg.cfgType = TSDB_CFG_CTYPE_B_CONFIG | TSDB_CFG_CTYPE_B_SHOW;
|
||||
cfg.minValue = 0;
|
||||
cfg.maxValue = 1;
|
||||
cfg.ptrLength = 0;
|
||||
cfg.unitType = TAOS_CFG_UTYPE_NONE;
|
||||
taosInitConfigOption(cfg);
|
||||
|
||||
cfg.option = "maxSQLLength";
|
||||
cfg.ptr = &tsMaxSQLStringLen;
|
||||
cfg.valType = TAOS_CFG_VTYPE_INT32;
|
||||
|
|
|
@ -70,12 +70,11 @@ SColumnFilterInfo* tFilterInfoDup(const SColumnFilterInfo* src, int32_t numOfFil
|
|||
|
||||
memcpy(pFilter, src, sizeof(SColumnFilterInfo) * numOfFilters);
|
||||
for (int32_t j = 0; j < numOfFilters; ++j) {
|
||||
|
||||
if (pFilter[j].filterstr) {
|
||||
size_t len = (size_t) pFilter[j].len + 1 * TSDB_NCHAR_SIZE;
|
||||
pFilter[j].pz = (int64_t) calloc(1, len);
|
||||
|
||||
memcpy((char*)pFilter[j].pz, (char*)src[j].pz, (size_t)len);
|
||||
memcpy((char*)pFilter[j].pz, (char*)src[j].pz, (size_t) pFilter[j].len);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -38,11 +38,7 @@ const int32_t TYPE_BYTES[15] = {
|
|||
|
||||
#define DO_STATICS(__sum, __min, __max, __minIndex, __maxIndex, _list, _index) \
|
||||
do { \
|
||||
if (_list[(_index)] >= (INT64_MAX - (__sum))) { \
|
||||
__sum = INT64_MAX; \
|
||||
} else { \
|
||||
(__sum) += (_list)[(_index)]; \
|
||||
} \
|
||||
(__sum) += (_list)[(_index)]; \
|
||||
if ((__min) > (_list)[(_index)]) { \
|
||||
(__min) = (_list)[(_index)]; \
|
||||
(__minIndex) = (_index); \
|
||||
|
|
|
@ -1 +1 @@
|
|||
Subproject commit a44ec1ca493ad01b2bf825b6418f69e11f548206
|
||||
Subproject commit 4a4d79099b076b8ff12d5b4fdbcba54049a6866d
|
|
@ -0,0 +1,570 @@
|
|||
package com.taosdata.jdbc.cases;
|
||||
|
||||
|
||||
import com.taosdata.jdbc.TSDBDriver;
|
||||
import org.junit.AfterClass;
|
||||
import org.junit.Assert;
|
||||
import org.junit.BeforeClass;
|
||||
import org.junit.After;
|
||||
import org.junit.Test;
|
||||
|
||||
import java.sql.*;
|
||||
import java.util.Properties;
|
||||
import java.text.Format;
|
||||
import java.text.SimpleDateFormat;
|
||||
|
||||
public class TimestampPrecisonInNanoRestTest {
|
||||
|
||||
private static final String host = "127.0.0.1";
|
||||
private static final String ns_timestamp_db = "ns_precision_test";
|
||||
private static final long timestamp1 = System.currentTimeMillis();
|
||||
private static final long timestamp2 = timestamp1 * 1000_000 + 123455;
|
||||
private static final long timestamp3 = (timestamp1 + 10) * 1000_000 + 123456;
|
||||
private static final Format format = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss.SSS");
|
||||
private static final String date1 = format.format(new Date(timestamp1));
|
||||
private static final String date4 = format.format(new Date(timestamp1 + 10L));
|
||||
private static final String date2 = date1 + "123455";
|
||||
private static final String date3 = date4 + "123456";
|
||||
|
||||
|
||||
private static Connection conn;
|
||||
|
||||
@BeforeClass
|
||||
public static void beforeClass() throws SQLException {
|
||||
Properties properties = new Properties();
|
||||
properties.setProperty(TSDBDriver.PROPERTY_KEY_CHARSET, "UTF-8");
|
||||
properties.setProperty(TSDBDriver.PROPERTY_KEY_LOCALE, "en_US.UTF-8");
|
||||
properties.setProperty(TSDBDriver.PROPERTY_KEY_TIME_ZONE, "UTC-8");
|
||||
|
||||
String url = "jdbc:TAOS-RS://" + host + ":6041/?user=root&password=taosdata";
|
||||
conn = DriverManager.getConnection(url, properties);
|
||||
|
||||
Statement stmt = conn.createStatement();
|
||||
stmt.execute("drop database if exists " + ns_timestamp_db);
|
||||
stmt.execute("create database if not exists " + ns_timestamp_db + " precision 'ns'");
|
||||
stmt.execute("create table " + ns_timestamp_db + ".weather(ts timestamp, ts2 timestamp, f1 int)");
|
||||
stmt.executeUpdate("insert into " + ns_timestamp_db + ".weather(ts, ts2, f1) values(\"" + date3 + "\", \"" + date3 + "\", 128)");
|
||||
stmt.executeUpdate("insert into " + ns_timestamp_db + ".weather(ts, ts2, f1) values(" + timestamp2 + "," + timestamp2 + ", 127)");
|
||||
stmt.close();
|
||||
}
|
||||
|
||||
@After
|
||||
public void afterEach() throws SQLException {
|
||||
Statement stmt = conn.createStatement();
|
||||
stmt.execute("drop database if exists " + ns_timestamp_db);
|
||||
stmt.execute("create database if not exists " + ns_timestamp_db + " precision 'ns'");
|
||||
stmt.execute("create table " + ns_timestamp_db + ".weather(ts timestamp, ts2 timestamp, f1 int)");
|
||||
stmt.executeUpdate("insert into " + ns_timestamp_db + ".weather(ts, ts2, f1) values(\"" + date3 + "\", \"" + date3 + "\", 128)");
|
||||
stmt.executeUpdate("insert into " + ns_timestamp_db + ".weather(ts, ts2, f1) values(" + timestamp2 + "," + timestamp2 + ", 127)");
|
||||
stmt.close();
|
||||
}
|
||||
|
||||
@AfterClass
|
||||
public static void afterClass() {
|
||||
try {
|
||||
if (conn != null)
|
||||
conn.close();
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
private void checkCount(long count, ResultSet rs) throws SQLException {
|
||||
if (count == 0) {
|
||||
Assert.fail();
|
||||
}
|
||||
rs.next();
|
||||
long test_count = rs.getLong(1);
|
||||
Assert.assertEquals(count, test_count);
|
||||
}
|
||||
|
||||
private void checkTime(long ts, ResultSet rs) throws SQLException {
|
||||
rs.next();
|
||||
int nanos = rs.getTimestamp(1).getNanos();
|
||||
Assert.assertEquals(ts % 1000_000_000l, nanos);
|
||||
long test_ts = rs.getLong(1);
|
||||
Assert.assertEquals(ts / 1000_000l, test_ts);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canInsertTimestampAndQueryByEqualToInDateTypeInBothFirstAndSecondCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts = '" + date3 + "'");
|
||||
checkCount(1l, rs);
|
||||
rs = stmt.executeQuery("select ts from " + ns_timestamp_db + ".weather where ts = '" + date3 + "'");
|
||||
checkTime(timestamp3, rs);
|
||||
rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts2 = '" + date3 + "'");
|
||||
checkCount(1l, rs);
|
||||
rs = stmt.executeQuery("select ts2 from " + ns_timestamp_db + ".weather where ts2 = '" + date3 + "'");
|
||||
checkTime(timestamp3, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canImportTimestampAndQueryByEqualToInDateTypeInBothFirstAndSecondCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
stmt.executeUpdate("import into " + ns_timestamp_db + ".weather(ts, ts2, f1) values(\"" + date1 + "123123\", \"" + date1 + "123123\", 127)");
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts = '" + date1 + "123123'");
|
||||
checkCount(1l, rs);
|
||||
rs = stmt.executeQuery("select ts from " + ns_timestamp_db + ".weather where ts = '" + date1 + "123123'");
|
||||
checkTime(timestamp1 * 1000_000l + 123123l, rs);
|
||||
rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts2 = '" + date1 + "123123'");
|
||||
checkCount(1l, rs);
|
||||
rs = stmt.executeQuery("select ts2 from " + ns_timestamp_db + ".weather where ts2 = '" + date1 + "123123'");
|
||||
checkTime(timestamp1 * 1000_000l + 123123l, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canInsertTimestampAndQueryByEqualToInNumberTypeInBothFirstAndSecondCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts = '" + timestamp2 + "'");
|
||||
checkCount(1l, rs);
|
||||
rs = stmt.executeQuery("select ts from " + ns_timestamp_db + ".weather where ts = '" + timestamp2 + "'");
|
||||
checkTime(timestamp2, rs);
|
||||
rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts2 = '" + timestamp2 + "'");
|
||||
checkCount(1l, rs);
|
||||
rs = stmt.executeQuery("select ts2 from " + ns_timestamp_db + ".weather where ts2 = '" + timestamp2 + "'");
|
||||
checkTime(timestamp2, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canImportTimestampAndQueryByEqualToInNumberTypeInBothFirstAndSecondCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
long timestamp4 = timestamp1 * 1000_000 + 123123;
|
||||
stmt.executeUpdate("import into " + ns_timestamp_db + ".weather(ts, ts2, f1) values(" + timestamp4 + ", " + timestamp4 + ", 127)");
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts = '" + timestamp4 + "'");
|
||||
checkCount(1l, rs);
|
||||
rs = stmt.executeQuery("select ts from " + ns_timestamp_db + ".weather where ts = '" + timestamp4 + "'");
|
||||
checkTime(timestamp4, rs);
|
||||
rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts2 = '" + timestamp4 + "'");
|
||||
checkCount(1l, rs);
|
||||
rs = stmt.executeQuery("select ts2 from " + ns_timestamp_db + ".weather where ts2 = '" + timestamp4 + "'");
|
||||
checkTime(timestamp4, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canSelectLastRowFromWeatherForFirstCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select last(ts) from " + ns_timestamp_db + ".weather");
|
||||
checkTime(timestamp3, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canSelectLastRowFromWeatherForSecondCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select last(ts2) from " + ns_timestamp_db + ".weather");
|
||||
checkTime(timestamp3, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canSelectFirstRowFromWeatherForFirstCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select first(ts) from " + ns_timestamp_db + ".weather");
|
||||
checkTime(timestamp2, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canSelectFirstRowFromWeatherForSecondCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select first(ts2) from " + ns_timestamp_db + ".weather");
|
||||
checkTime(timestamp2, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canQueryLargerThanInDateTypeForFirstCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts > '" + date2 + "'");
|
||||
checkCount(1l, rs);
|
||||
rs = stmt.executeQuery("select ts from " + ns_timestamp_db + ".weather where ts > '" + date2 + "'");
|
||||
checkTime(timestamp3, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canQueryLargerThanInDateTypeForSecondCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts2 > '" + date2 + "'");
|
||||
checkCount(1l, rs);
|
||||
rs = stmt.executeQuery("select ts2 from " + ns_timestamp_db + ".weather where ts2 > '" + date2 + "'");
|
||||
checkTime(timestamp3, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canQueryLargerThanInNumberTypeForFirstCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts > '" + timestamp2 + "'");
|
||||
checkCount(1l, rs);
|
||||
rs = stmt.executeQuery("select ts from " + ns_timestamp_db + ".weather where ts > '" + timestamp2 + "'");
|
||||
checkTime(timestamp3, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canQueryLargerThanInNumberTypeForSecondCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts2 > '" + timestamp2 + "'");
|
||||
checkCount(1l, rs);
|
||||
rs = stmt.executeQuery("select ts2 from " + ns_timestamp_db + ".weather where ts2 > '" + timestamp2 + "'");
|
||||
checkTime(timestamp3, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canQueryLargerThanOrEqualToInDateTypeForFirstCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts >= '" + date2 + "'");
|
||||
checkCount(2l, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canQueryLargerThanOrEqualToInDateTypeForSecondCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts2 >= '" + date2 + "'");
|
||||
checkCount(2l, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canQueryLargerThanOrEqualToInNumberTypeForFirstCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts >= '" + timestamp2 + "'");
|
||||
checkCount(2l, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canQueryLargerThanOrEqualToInNumberTypeForSecondCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts2 >= '" + timestamp2 + "'");
|
||||
checkCount(2l, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canQueryLessThanInDateTypeForFirstCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts < '" + date3 + "'");
|
||||
checkCount(1l, rs);
|
||||
rs = stmt.executeQuery("select ts from " + ns_timestamp_db + ".weather where ts < '" + date3 + "'");
|
||||
checkTime(timestamp2, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canQueryLessThanInDateTypeForSecondCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts2 < '" + date3 + "'");
|
||||
checkCount(1l, rs);
|
||||
rs = stmt.executeQuery("select ts2 from " + ns_timestamp_db + ".weather where ts2 < '" + date3 + "'");
|
||||
checkTime(timestamp2, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canQueryLessThanInNumberTypeForFirstCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts < '" + timestamp3 + "'");
|
||||
checkCount(1l, rs);
|
||||
rs = stmt.executeQuery("select ts from " + ns_timestamp_db + ".weather where ts < '" + timestamp3 + "'");
|
||||
checkTime(timestamp2, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canQueryLessThanInNumberTypeForSecondCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts2 < '" + timestamp3 + "'");
|
||||
checkCount(1l, rs);
|
||||
rs = stmt.executeQuery("select ts2 from " + ns_timestamp_db + ".weather where ts2 < '" + timestamp3 + "'");
|
||||
checkTime(timestamp2, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canQueryLessThanOrEqualToInDateTypeForFirstCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts <= '" + date3 + "'");
|
||||
checkCount(2l, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canQueryLessThanOrEqualToInDateTypeForSecondCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts2 <= '" + date3 + "'");
|
||||
checkCount(2l, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canQueryLessThanOrEqualToInNumberTypeForFirstCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts <= '" + timestamp3 + "'");
|
||||
checkCount(2l, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canQueryLessThanOrEqualToInNumberTypeForSecondCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts2 <= '" + timestamp3 + "'");
|
||||
checkCount(2l, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canQueryBetweenAndInDateTypeForFirstCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts <= '" + date3 + "' AND ts > '" + date2 + "'");
|
||||
checkCount(1l, rs);
|
||||
rs = stmt.executeQuery("select ts from " + ns_timestamp_db + ".weather where ts <= '" + date3 + "' AND ts > '" + date2 + "'");
|
||||
checkTime(timestamp3, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canQueryBetweenAndInDateTypeForSecondCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts2 <= '" + date3 + "' AND ts2 > '" + date2 + "'");
|
||||
checkCount(1l, rs);
|
||||
rs = stmt.executeQuery("select ts2 from " + ns_timestamp_db + ".weather where ts2 <= '" + date3 + "' AND ts2 > '" + date2 + "'");
|
||||
checkTime(timestamp3, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canQueryBetweenAndInNumberTypeForFirstCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts <= '" + timestamp3 + "' AND ts > '" + timestamp2 + "'");
|
||||
checkCount(1l, rs);
|
||||
rs = stmt.executeQuery("select ts from " + ns_timestamp_db + ".weather where ts <= '" + timestamp3 + "' AND ts > '" + timestamp2 + "'");
|
||||
checkTime(timestamp3, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canQueryBetweenAndInNumberTypeForSecondCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts2 <= '" + timestamp3 + "' AND ts2 > '" + timestamp2 + "'");
|
||||
checkCount(1l, rs);
|
||||
rs = stmt.executeQuery("select ts2 from " + ns_timestamp_db + ".weather where ts2 <= '" + timestamp3 + "' AND ts2 > '" + timestamp2 + "'");
|
||||
checkTime(timestamp3, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canQueryNotEqualToInDateTypeForSecondCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts2 <> '" + date3 + "'");
|
||||
checkCount(1l, rs);
|
||||
rs = stmt.executeQuery("select ts2 from " + ns_timestamp_db + ".weather where ts2 <> '" + date3 + "'");
|
||||
checkTime(timestamp2, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canQueryNotEqualToInNumberTypeForSecondCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts2 <> '" + timestamp3 + "'");
|
||||
checkCount(1l, rs);
|
||||
rs = stmt.executeQuery("select ts2 from " + ns_timestamp_db + ".weather where ts2 <> '" + timestamp3 + "'");
|
||||
checkTime(timestamp2, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canQueryNotEqualInDateTypeForSecondCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts2 != '" + date3 + "'");
|
||||
checkCount(1l, rs);
|
||||
rs = stmt.executeQuery("select ts2 from " + ns_timestamp_db + ".weather where ts2 != '" + date3 + "'");
|
||||
checkTime(timestamp2, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canQueryNotEqualInNumberTypeForSecondCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts2 != '" + timestamp3 + "'");
|
||||
checkCount(1l, rs);
|
||||
rs = stmt.executeQuery("select ts2 from " + ns_timestamp_db + ".weather where ts2 != '" + timestamp3 + "'");
|
||||
checkTime(timestamp2, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canInsertTimestampWithNowAndNsOffsetInBothFirstAndSecondCol(){
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
stmt.executeUpdate("insert into " + ns_timestamp_db + ".weather(ts, ts2, f1) values(now + 1000b, now - 1000b, 128)");
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather");
|
||||
checkCount(3l, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canIntervalAndSlidingAcceptNsUnitForFirstCol(){
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select sum(f1) from " + ns_timestamp_db + ".weather where ts >= '" + date2 + "' and ts <= '" + date3 + "' interval(10000000b) sliding(10000000b)");
|
||||
rs.next();
|
||||
long sum = rs.getLong(2);
|
||||
Assert.assertEquals(127l, sum);
|
||||
rs.next();
|
||||
sum = rs.getLong(2);
|
||||
Assert.assertEquals(128l, sum);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void canIntervalAndSlidingAcceptNsUnitForSecondCol(){
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
ResultSet rs = stmt.executeQuery("select sum(f1) from " + ns_timestamp_db + ".weather where ts2 >= '" + date2 + "' and ts <= '" + date3 + "' interval(10000000b) sliding(10000000b)");
|
||||
rs.next();
|
||||
long sum = rs.getLong(2);
|
||||
Assert.assertEquals(127l, sum);
|
||||
rs.next();
|
||||
sum = rs.getLong(2);
|
||||
Assert.assertEquals(128l, sum);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDataOutOfRangeExceptionForFirstCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
stmt.executeUpdate("insert into " + ns_timestamp_db + ".weather(ts, ts2, f1) values(123456789012345678, 1234567890123456789, 127)");
|
||||
} catch (SQLException e) {
|
||||
Assert.assertEquals("TDengine ERROR (60b): Timestamp data out of range", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testDataOutOfRangeExceptionForSecondCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
stmt.executeUpdate("insert into " + ns_timestamp_db + ".weather(ts, ts2, f1) values(1234567890123456789, 123456789012345678, 127)");
|
||||
} catch (SQLException e) {
|
||||
Assert.assertEquals("TDengine ERROR (60b): Timestamp data out of range", e.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void willAutomaticallyFillToNsUnitWithZerosForFirstCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
stmt.executeUpdate("insert into " + ns_timestamp_db + ".weather(ts, ts2, f1) values('" + date1 + "', '" + date1 + "', 127)");
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts = '" + date1 + "000000'");
|
||||
checkCount(1l, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void willAutomaticallyFillToNsUnitWithZerosForSecondCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
stmt.executeUpdate("insert into " + ns_timestamp_db + ".weather(ts, ts2, f1) values('" + date1 + "', '" + date1 + "', 127)");
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts2 = '" + date1 + "000000'");
|
||||
checkCount(1l, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void willAutomaticallyDropDigitExceedNsDigitNumberForFirstCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
stmt.executeUpdate("insert into " + ns_timestamp_db + ".weather(ts, ts2, f1) values('" + date1 + "999999999', '" + date1 + "999999999', 127)");
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts = '" + date1 + "999999'");
|
||||
checkCount(1l, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
public void willAutomaticallyDropDigitExceedNsDigitNumberForSecondCol() {
|
||||
try (Statement stmt = conn.createStatement()) {
|
||||
stmt.executeUpdate("insert into " + ns_timestamp_db + ".weather(ts, ts2, f1) values('" + date1 + "999999999', '" + date1 + "999999999', 127)");
|
||||
ResultSet rs = stmt.executeQuery("select count(*) from " + ns_timestamp_db + ".weather where ts2 = '" + date1 + "999999'");
|
||||
checkCount(1l, rs);
|
||||
} catch (SQLException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -109,6 +109,24 @@ function convertDouble(data, num_of_rows, nbytes = 0, offset = 0, precision = 0)
|
|||
return res;
|
||||
}
|
||||
|
||||
function convertBinary(data, num_of_rows, nbytes = 0, offset = 0, precision = 0) {
|
||||
data = ref.reinterpret(data.deref(), nbytes * num_of_rows, offset);
|
||||
let res = [];
|
||||
|
||||
let currOffset = 0;
|
||||
while (currOffset < data.length) {
|
||||
let len = data.readIntLE(currOffset, 2);
|
||||
let dataEntry = data.slice(currOffset + 2, currOffset + len + 2); //one entry in a row under a column;
|
||||
if (dataEntry[0] == 255) {
|
||||
res.push(null)
|
||||
} else {
|
||||
res.push(dataEntry.toString("utf-8"));
|
||||
}
|
||||
currOffset += nbytes;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
function convertNchar(data, num_of_rows, nbytes = 0, offset = 0, precision = 0) {
|
||||
data = ref.reinterpret(data.deref(), nbytes * num_of_rows, offset);
|
||||
let res = [];
|
||||
|
@ -117,7 +135,11 @@ function convertNchar(data, num_of_rows, nbytes = 0, offset = 0, precision = 0)
|
|||
while (currOffset < data.length) {
|
||||
let len = data.readIntLE(currOffset, 2);
|
||||
let dataEntry = data.slice(currOffset + 2, currOffset + len + 2); //one entry in a row under a column;
|
||||
res.push(dataEntry.toString("utf-8"));
|
||||
if (dataEntry[0] == 255 && dataEntry[1] == 255) {
|
||||
res.push(null)
|
||||
} else {
|
||||
res.push(dataEntry.toString("utf-8"));
|
||||
}
|
||||
currOffset += nbytes;
|
||||
}
|
||||
return res;
|
||||
|
@ -132,7 +154,7 @@ let convertFunctions = {
|
|||
[FieldTypes.C_BIGINT]: convertBigint,
|
||||
[FieldTypes.C_FLOAT]: convertFloat,
|
||||
[FieldTypes.C_DOUBLE]: convertDouble,
|
||||
[FieldTypes.C_BINARY]: convertNchar,
|
||||
[FieldTypes.C_BINARY]: convertBinary,
|
||||
[FieldTypes.C_TIMESTAMP]: convertTimestamp,
|
||||
[FieldTypes.C_NCHAR]: convertNchar
|
||||
}
|
||||
|
|
|
@ -47,7 +47,8 @@ class TaosTimestamp extends Date {
|
|||
super(Math.floor(date / 1000));
|
||||
this.precisionExtras = date % 1000;
|
||||
} else if (precision === 2) {
|
||||
super(parseInt(date / 1000000));
|
||||
// use BigInt to fix: 1623254400999999999 / 1000000 = 1623254401000 which not expected
|
||||
super(parseInt(BigInt(date) / 1000000n));
|
||||
// use BigInt to fix: 1625801548423914405 % 1000000 = 914496 which not expected (914405)
|
||||
this.precisionExtras = parseInt(BigInt(date) % 1000000n);
|
||||
} else {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "td2.0-connector",
|
||||
"version": "2.0.9",
|
||||
"version": "2.0.10",
|
||||
"description": "A Node.js connector for TDengine.",
|
||||
"main": "tdengine.js",
|
||||
"directories": {
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
const taos = require('../tdengine');
|
||||
var conn = taos.connect({ host: "localhost" });
|
||||
var c1 = conn.cursor();
|
||||
|
||||
|
||||
function checkData(data, row, col, expect) {
|
||||
let checkdata = data[row][col];
|
||||
if (checkdata == expect) {
|
||||
// console.log('check pass')
|
||||
}
|
||||
else {
|
||||
console.log('check failed, expect ' + expect + ', but is ' + checkdata)
|
||||
}
|
||||
}
|
||||
|
||||
c1.execute('drop database if exists testnodejsnchar')
|
||||
c1.execute('create database testnodejsnchar')
|
||||
c1.execute('use testnodejsnchar');
|
||||
c1.execute('create table tb (ts timestamp, value float, text binary(200))')
|
||||
c1.execute("insert into tb values('2021-06-10 00:00:00', 24.7, '中文10000000000000000000000');") -
|
||||
c1.execute('insert into tb values(1623254400150, 24.7, NULL);')
|
||||
c1.execute('import into tb values(1623254400300, 24.7, "中文3中文10000000000000000000000中文10000000000000000000000中文10000000000000000000000中文10000000000000000000000");')
|
||||
sql = 'select * from tb;'
|
||||
|
||||
console.log('*******************************************')
|
||||
|
||||
c1.execute(sql);
|
||||
data = c1.fetchall();
|
||||
console.log(data)
|
||||
//check data about insert data
|
||||
checkData(data, 0, 2, '中文10000000000000000000000')
|
||||
checkData(data, 1, 2, null)
|
||||
checkData(data, 2, 2, '中文3中文10000000000000000000000中文10000000000000000000000中文10000000000000000000000中文10000000000000000000000')
|
|
@ -166,7 +166,6 @@ int32_t dnodeInitSystem() {
|
|||
taosInitGlobalCfg();
|
||||
taosReadGlobalLogCfg();
|
||||
taosSetCoreDump();
|
||||
taosInitNotes();
|
||||
dnodeInitTmr();
|
||||
|
||||
if (dnodeCreateDir(tsLogDir) < 0) {
|
||||
|
@ -188,6 +187,8 @@ int32_t dnodeInitSystem() {
|
|||
|
||||
dInfo("start to initialize TDengine");
|
||||
|
||||
taosInitNotes();
|
||||
|
||||
if (dnodeInitComponents() != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
@ -195,6 +196,7 @@ int32_t dnodeInitSystem() {
|
|||
dnodeSetRunStatus(TSDB_RUN_STATUS_RUNING);
|
||||
moduleStart();
|
||||
|
||||
tsDnodeStartTime = taosGetTimestampMs();
|
||||
dnodeReportStep("TDengine", "initialized successfully", 1);
|
||||
dInfo("TDengine is initialized successfully");
|
||||
|
||||
|
|
|
@ -42,6 +42,8 @@ int32_t main(int32_t argc, char *argv[]) {
|
|||
}
|
||||
} else if (strcmp(argv[i], "-C") == 0) {
|
||||
dump_config = 1;
|
||||
} else if (strcmp(argv[i], "--force-keep-file") == 0) {
|
||||
tsdbForceKeepFile = true;
|
||||
} else if (strcmp(argv[i], "--compact-mnode-wal") == 0) {
|
||||
tsCompactMnodeWal = 1;
|
||||
} else if (strcmp(argv[i], "-V") == 0) {
|
||||
|
|
|
@ -88,6 +88,8 @@ extern const int32_t TYPE_BYTES[15];
|
|||
#define TSDB_DEFAULT_PASS "taosdata"
|
||||
#endif
|
||||
|
||||
#define SHELL_MAX_PASSWORD_LEN 20
|
||||
|
||||
#define TSDB_TRUE 1
|
||||
#define TSDB_FALSE 0
|
||||
#define TSDB_OK 0
|
||||
|
|
|
@ -471,6 +471,7 @@ typedef struct {
|
|||
|
||||
bool stableQuery; // super table query or not
|
||||
bool topBotQuery; // TODO used bitwise flag
|
||||
bool interpQuery; // interp query or not
|
||||
bool groupbyColumn; // denote if this is a groupby normal column query
|
||||
bool hasTagResults; // if there are tag values in final result or not
|
||||
bool timeWindowInterpo;// if the time window start/end required interpolation
|
||||
|
@ -535,6 +536,8 @@ typedef struct SRetrieveTableRsp {
|
|||
int16_t precision;
|
||||
int64_t offset; // updated offset value for multi-vnode projection query
|
||||
int64_t useconds;
|
||||
int8_t compressed;
|
||||
int32_t compLen;
|
||||
char data[];
|
||||
} SRetrieveTableRsp;
|
||||
|
||||
|
@ -878,7 +881,7 @@ typedef struct {
|
|||
uint64_t sqlObjId;
|
||||
int32_t pid;
|
||||
char fqdn[TSDB_FQDN_LEN];
|
||||
bool stableQuery;
|
||||
uint8_t stableQuery;
|
||||
int32_t numOfSub;
|
||||
char subSqlInfo[TSDB_SHOW_SUBQUERY_LEN]; //include subqueries' index, Obj IDs and states(C-complete/I-imcomplete)
|
||||
} SQueryDesc;
|
||||
|
|
|
@ -41,9 +41,16 @@ typedef struct {
|
|||
int64_t avail;
|
||||
} SFSMeta;
|
||||
|
||||
typedef struct {
|
||||
int64_t size;
|
||||
int64_t used;
|
||||
int64_t free;
|
||||
int16_t nAvailDisks; // # of Available disks
|
||||
} STierMeta;
|
||||
|
||||
int tfsInit(SDiskCfg *pDiskCfg, int ndisk);
|
||||
void tfsDestroy();
|
||||
void tfsUpdateInfo(SFSMeta *pFSMeta);
|
||||
void tfsUpdateInfo(SFSMeta *pFSMeta, STierMeta *tierMetas, int8_t numLevels);
|
||||
void tfsGetMeta(SFSMeta *pMeta);
|
||||
void tfsAllocDisk(int expLevel, int *level, int *id);
|
||||
|
||||
|
|
|
@ -32,7 +32,7 @@ typedef enum {
|
|||
|
||||
typedef struct {
|
||||
int8_t msgType;
|
||||
int8_t sver;
|
||||
int8_t sver; // sver 2 for WAL SDataRow/SMemRow compatibility
|
||||
int8_t reserved[2];
|
||||
int32_t len;
|
||||
uint64_t version;
|
||||
|
|
|
@ -25,7 +25,6 @@
|
|||
#define MAX_USERNAME_SIZE 64
|
||||
#define MAX_DBNAME_SIZE 64
|
||||
#define MAX_IP_SIZE 20
|
||||
#define MAX_PASSWORD_SIZE 20
|
||||
#define MAX_HISTORY_SIZE 1000
|
||||
#define MAX_COMMAND_SIZE 1048586
|
||||
#define HISTORY_FILE ".taos_history"
|
||||
|
@ -56,6 +55,8 @@ typedef struct SShellArguments {
|
|||
int abort;
|
||||
int port;
|
||||
int pktLen;
|
||||
int pktNum;
|
||||
char* pktType;
|
||||
char* netTestRole;
|
||||
} SShellArguments;
|
||||
|
||||
|
|
|
@ -64,6 +64,10 @@ void printHelp() {
|
|||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
char DARWINCLIENT_VERSION[] = "Welcome to the TDengine shell from %s, Client Version:%s\n"
|
||||
"Copyright (c) 2020 by TAOS Data, Inc. All rights reserved.\n\n";
|
||||
char g_password[SHELL_MAX_PASSWORD_LEN];
|
||||
|
||||
void shellParseArgument(int argc, char *argv[], SShellArguments *arguments) {
|
||||
wordexp_t full_path;
|
||||
for (int i = 1; i < argc; i++) {
|
||||
|
@ -77,10 +81,27 @@ void shellParseArgument(int argc, char *argv[], SShellArguments *arguments) {
|
|||
}
|
||||
}
|
||||
// for password
|
||||
else if (strcmp(argv[i], "-p") == 0) {
|
||||
arguments->is_use_passwd = true;
|
||||
else if ((strncmp(argv[i], "-p", 2) == 0)
|
||||
|| (strncmp(argv[i], "--password", 10) == 0)) {
|
||||
strcpy(tsOsName, "Darwin");
|
||||
printf(DARWINCLIENT_VERSION, tsOsName, taos_get_client_info());
|
||||
if ((strlen(argv[i]) == 2)
|
||||
|| (strncmp(argv[i], "--password", 10) == 0)) {
|
||||
printf("Enter password: ");
|
||||
taosSetConsoleEcho(false);
|
||||
if (scanf("%s", g_password) > 1) {
|
||||
fprintf(stderr, "password read error\n");
|
||||
}
|
||||
taosSetConsoleEcho(true);
|
||||
getchar();
|
||||
} else {
|
||||
tstrncpy(g_password, (char *)(argv[i] + 2), SHELL_MAX_PASSWORD_LEN);
|
||||
}
|
||||
arguments->password = g_password;
|
||||
strcpy(argv[i], "");
|
||||
argc -= 1;
|
||||
}
|
||||
// for management port
|
||||
// for management port
|
||||
else if (strcmp(argv[i], "-P") == 0) {
|
||||
if (i < argc - 1) {
|
||||
arguments->port = atoi(argv[++i]);
|
||||
|
@ -98,7 +119,7 @@ void shellParseArgument(int argc, char *argv[], SShellArguments *arguments) {
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else if (strcmp(argv[i], "-c") == 0) {
|
||||
if (i < argc - 1) {
|
||||
if (i < argc - 1) {
|
||||
if (strlen(argv[++i]) >= TSDB_FILENAME_LEN) {
|
||||
fprintf(stderr, "config file path: %s overflow max len %d\n", argv[i], TSDB_FILENAME_LEN - 1);
|
||||
exit(EXIT_FAILURE);
|
||||
|
|
|
@ -65,7 +65,15 @@ extern TAOS *taos_connect_auth(const char *ip, const char *user, const char *aut
|
|||
*/
|
||||
TAOS *shellInit(SShellArguments *_args) {
|
||||
printf("\n");
|
||||
printf(CLIENT_VERSION, tsOsName, taos_get_client_info());
|
||||
if (!_args->is_use_passwd) {
|
||||
#ifdef TD_WINDOWS
|
||||
strcpy(tsOsName, "Windows");
|
||||
#elif defined(TD_DARWIN)
|
||||
strcpy(tsOsName, "Darwin");
|
||||
#endif
|
||||
printf(CLIENT_VERSION, tsOsName, taos_get_client_info());
|
||||
}
|
||||
|
||||
fflush(stdout);
|
||||
|
||||
// set options before initializing
|
||||
|
@ -73,9 +81,7 @@ TAOS *shellInit(SShellArguments *_args) {
|
|||
taos_options(TSDB_OPTION_TIMEZONE, _args->timezone);
|
||||
}
|
||||
|
||||
if (_args->is_use_passwd) {
|
||||
if (_args->password == NULL) _args->password = getpass("Enter password: ");
|
||||
} else {
|
||||
if (!_args->is_use_passwd) {
|
||||
_args->password = TSDB_DEFAULT_PASS;
|
||||
}
|
||||
|
||||
|
@ -169,7 +175,7 @@ static int32_t shellRunSingleCommand(TAOS *con, char *command) {
|
|||
system("clear");
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if (regex_match(command, "^[\t ]*set[ \t]+max_binary_display_width[ \t]+(default|[1-9][0-9]*)[ \t;]*$", REG_EXTENDED | REG_ICASE)) {
|
||||
strtok(command, " \t");
|
||||
strtok(NULL, " \t");
|
||||
|
@ -181,7 +187,7 @@ static int32_t shellRunSingleCommand(TAOS *con, char *command) {
|
|||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
if (regex_match(command, "^[ \t]*source[\t ]+[^ ]+[ \t;]*$", REG_EXTENDED | REG_ICASE)) {
|
||||
/* If source file. */
|
||||
char *c_ptr = strtok(command, " ;");
|
||||
|
@ -246,7 +252,7 @@ int32_t shellRunCommand(TAOS* con, char* command) {
|
|||
esc = false;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (c == '\\') {
|
||||
esc = true;
|
||||
continue;
|
||||
|
@ -335,8 +341,8 @@ void shellRunCommandOnServer(TAOS *con, char command[]) {
|
|||
}
|
||||
|
||||
if (!tscIsUpdateQuery(pSql)) { // select and show kinds of commands
|
||||
int error_no = 0;
|
||||
|
||||
int error_no = 0;
|
||||
|
||||
int numOfRows = shellDumpResult(pSql, fname, &error_no, printMode);
|
||||
if (numOfRows < 0) {
|
||||
atomic_store_64(&result, 0);
|
||||
|
@ -529,7 +535,7 @@ static int dumpResultToFile(const char* fname, TAOS_RES* tres) {
|
|||
fprintf(fp, "%s", fields[col].name);
|
||||
}
|
||||
fputc('\n', fp);
|
||||
|
||||
|
||||
int numOfRows = 0;
|
||||
do {
|
||||
int32_t* length = taos_fetch_lengths(tres);
|
||||
|
@ -715,7 +721,7 @@ static int verticalPrintResult(TAOS_RES* tres) {
|
|||
|
||||
int numOfRows = 0;
|
||||
int showMore = 1;
|
||||
do {
|
||||
do {
|
||||
if (numOfRows < resShowMaxNum) {
|
||||
printf("*************************** %d.row ***************************\n", numOfRows + 1);
|
||||
|
||||
|
@ -850,7 +856,7 @@ static int horizontalPrintResult(TAOS_RES* tres) {
|
|||
|
||||
int numOfRows = 0;
|
||||
int showMore = 1;
|
||||
|
||||
|
||||
do {
|
||||
int32_t* length = taos_fetch_lengths(tres);
|
||||
if (numOfRows < resShowMaxNum) {
|
||||
|
@ -866,7 +872,7 @@ static int horizontalPrintResult(TAOS_RES* tres) {
|
|||
printf("[You can add limit statement to show more or redirect results to specific file to get all.]\n");
|
||||
showMore = 0;
|
||||
}
|
||||
|
||||
|
||||
numOfRows++;
|
||||
row = taos_fetch_row(tres);
|
||||
} while(row != NULL);
|
||||
|
@ -908,7 +914,7 @@ void read_history() {
|
|||
if (errno != ENOENT) {
|
||||
fprintf(stderr, "Failed to open file %s, reason:%s\n", f_history, strerror(errno));
|
||||
}
|
||||
#endif
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -933,9 +939,9 @@ void write_history() {
|
|||
|
||||
FILE *f = fopen(f_history, "w");
|
||||
if (f == NULL) {
|
||||
#ifndef WINDOWS
|
||||
#ifndef WINDOWS
|
||||
fprintf(stderr, "Failed to open file %s for write, reason:%s\n", f_history, strerror(errno));
|
||||
#endif
|
||||
#endif
|
||||
return;
|
||||
}
|
||||
|
||||
|
@ -981,13 +987,13 @@ void source_file(TAOS *con, char *fptr) {
|
|||
/*
|
||||
if (access(fname, F_OK) != 0) {
|
||||
fprintf(stderr, "ERROR: file %s is not exist\n", fptr);
|
||||
|
||||
|
||||
wordfree(&full_path);
|
||||
free(cmd);
|
||||
return;
|
||||
}
|
||||
*/
|
||||
|
||||
|
||||
FILE *f = fopen(fname, "r");
|
||||
if (f == NULL) {
|
||||
fprintf(stderr, "ERROR: failed to open file %s\n", fname);
|
||||
|
|
|
@ -34,7 +34,7 @@ static char doc[] = "";
|
|||
static char args_doc[] = "";
|
||||
static struct argp_option options[] = {
|
||||
{"host", 'h', "HOST", 0, "TDengine server FQDN to connect. The default host is localhost."},
|
||||
{"password", 'p', "PASSWORD", OPTION_ARG_OPTIONAL, "The password to use when connecting to the server."},
|
||||
{"password", 'p', 0, 0, "The password to use when connecting to the server."},
|
||||
{"port", 'P', "PORT", 0, "The TCP/IP port number to use for the connection."},
|
||||
{"user", 'u', "USER", 0, "The user name to use when connecting to the server."},
|
||||
{"auth", 'A', "Auth", 0, "The auth string to use when connecting to the server."},
|
||||
|
@ -47,9 +47,11 @@ static struct argp_option options[] = {
|
|||
{"thread", 'T', "THREADNUM", 0, "Number of threads when using multi-thread to import data."},
|
||||
{"check", 'k', "CHECK", 0, "Check tables."},
|
||||
{"database", 'd', "DATABASE", 0, "Database to use when connecting to the server."},
|
||||
{"timezone", 't', "TIMEZONE", 0, "Time zone of the shell, default is local."},
|
||||
{"netrole", 'n', "NETROLE", 0, "Net role when network connectivity test, default is startup, options: client|server|rpc|startup|sync."},
|
||||
{"timezone", 'z', "TIMEZONE", 0, "Time zone of the shell, default is local."},
|
||||
{"netrole", 'n', "NETROLE", 0, "Net role when network connectivity test, default is startup, options: client|server|rpc|startup|sync|speen|fqdn."},
|
||||
{"pktlen", 'l', "PKTLEN", 0, "Packet length used for net test, default is 1000 bytes."},
|
||||
{"pktnum", 'N', "PKTNUM", 0, "Packet numbers used for net test, default is 100."},
|
||||
{"pkttype", 'S', "PKTTYPE", 0, "Packet type used for net test, default is TCP."},
|
||||
{0}};
|
||||
|
||||
static error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
||||
|
@ -63,8 +65,6 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||
arguments->host = arg;
|
||||
break;
|
||||
case 'p':
|
||||
arguments->is_use_passwd = true;
|
||||
if (arg) arguments->password = arg;
|
||||
break;
|
||||
case 'P':
|
||||
if (arg) {
|
||||
|
@ -76,7 +76,7 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||
}
|
||||
|
||||
break;
|
||||
case 't':
|
||||
case 'z':
|
||||
arguments->timezone = arg;
|
||||
break;
|
||||
case 'u':
|
||||
|
@ -148,6 +148,17 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||
return -1;
|
||||
}
|
||||
break;
|
||||
case 'N':
|
||||
if (arg) {
|
||||
arguments->pktNum = atoi(arg);
|
||||
} else {
|
||||
fprintf(stderr, "Invalid packet number\n");
|
||||
return -1;
|
||||
}
|
||||
break;
|
||||
case 'S':
|
||||
arguments->pktType = arg;
|
||||
break;
|
||||
case OPT_ABORT:
|
||||
arguments->abort = 1;
|
||||
break;
|
||||
|
@ -160,12 +171,46 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||
/* Our argp parser. */
|
||||
static struct argp argp = {options, parse_opt, args_doc, doc};
|
||||
|
||||
char LINUXCLIENT_VERSION[] = "Welcome to the TDengine shell from %s, Client Version:%s\n"
|
||||
"Copyright (c) 2020 by TAOS Data, Inc. All rights reserved.\n\n";
|
||||
char g_password[SHELL_MAX_PASSWORD_LEN];
|
||||
|
||||
static void parse_args(
|
||||
int argc, char *argv[], SShellArguments *arguments) {
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if ((strncmp(argv[i], "-p", 2) == 0)
|
||||
|| (strncmp(argv[i], "--password", 10) == 0)) {
|
||||
strcpy(tsOsName, "Linux");
|
||||
printf(LINUXCLIENT_VERSION, tsOsName, taos_get_client_info());
|
||||
if ((strlen(argv[i]) == 2)
|
||||
|| (strncmp(argv[i], "--password", 10) == 0)) {
|
||||
printf("Enter password: ");
|
||||
taosSetConsoleEcho(false);
|
||||
if (scanf("%20s", g_password) > 1) {
|
||||
fprintf(stderr, "password reading error\n");
|
||||
}
|
||||
taosSetConsoleEcho(true);
|
||||
getchar();
|
||||
} else {
|
||||
tstrncpy(g_password, (char *)(argv[i] + 2), SHELL_MAX_PASSWORD_LEN);
|
||||
strcpy(argv[i], "-p");
|
||||
}
|
||||
arguments->password = g_password;
|
||||
arguments->is_use_passwd = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void shellParseArgument(int argc, char *argv[], SShellArguments *arguments) {
|
||||
static char verType[32] = {0};
|
||||
sprintf(verType, "version: %s\n", version);
|
||||
|
||||
argp_program_version = verType;
|
||||
|
||||
|
||||
if (argc > 1) {
|
||||
parse_args(argc, argv, arguments);
|
||||
}
|
||||
|
||||
argp_parse(&argp, argc, argv, 0, 0, arguments);
|
||||
if (arguments->abort) {
|
||||
#ifndef _ALPINE
|
||||
|
|
|
@ -71,7 +71,9 @@ int checkVersion() {
|
|||
// Global configurations
|
||||
SShellArguments args = {
|
||||
.host = NULL,
|
||||
#ifndef TD_WINDOWS
|
||||
.password = NULL,
|
||||
#endif
|
||||
.user = NULL,
|
||||
.database = NULL,
|
||||
.timezone = NULL,
|
||||
|
@ -83,6 +85,8 @@ SShellArguments args = {
|
|||
.threadNum = 5,
|
||||
.commands = NULL,
|
||||
.pktLen = 1000,
|
||||
.pktNum = 100,
|
||||
.pktType = "TCP",
|
||||
.netTestRole = NULL
|
||||
};
|
||||
|
||||
|
@ -116,7 +120,7 @@ int main(int argc, char* argv[]) {
|
|||
printf("Failed to init taos");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
taosNetTest(args.netTestRole, args.host, args.port, args.pktLen);
|
||||
taosNetTest(args.netTestRole, args.host, args.port, args.pktLen, args.pktNum, args.pktType);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
|
|
|
@ -19,6 +19,9 @@
|
|||
|
||||
extern char configDir[];
|
||||
|
||||
char WINCLIENT_VERSION[] = "Welcome to the TDengine shell from %s, Client Version:%s\n"
|
||||
"Copyright (c) 2020 by TAOS Data, Inc. All rights reserved.\n\n";
|
||||
|
||||
void printVersion() {
|
||||
printf("version: %s\n", version);
|
||||
}
|
||||
|
@ -52,15 +55,21 @@ void printHelp() {
|
|||
printf("%s%s\n", indent, "-t");
|
||||
printf("%s%s%s\n", indent, indent, "Time zone of the shell, default is local.");
|
||||
printf("%s%s\n", indent, "-n");
|
||||
printf("%s%s%s\n", indent, indent, "Net role when network connectivity test, default is startup, options: client|server|rpc|startup|sync.");
|
||||
printf("%s%s%s\n", indent, indent, "Net role when network connectivity test, default is startup, options: client|server|rpc|startup|sync|speed|fqdn.");
|
||||
printf("%s%s\n", indent, "-l");
|
||||
printf("%s%s%s\n", indent, indent, "Packet length used for net test, default is 1000 bytes.");
|
||||
printf("%s%s\n", indent, "-N");
|
||||
printf("%s%s%s\n", indent, indent, "Packet numbers used for net test, default is 100.");
|
||||
printf("%s%s\n", indent, "-S");
|
||||
printf("%s%s%s\n", indent, indent, "Packet type used for net test, default is TCP.");
|
||||
printf("%s%s\n", indent, "-V");
|
||||
printf("%s%s%s\n", indent, indent, "Print program version.");
|
||||
|
||||
exit(EXIT_SUCCESS);
|
||||
}
|
||||
|
||||
char g_password[SHELL_MAX_PASSWORD_LEN];
|
||||
|
||||
void shellParseArgument(int argc, char *argv[], SShellArguments *arguments) {
|
||||
for (int i = 1; i < argc; i++) {
|
||||
// for host
|
||||
|
@ -73,11 +82,26 @@ void shellParseArgument(int argc, char *argv[], SShellArguments *arguments) {
|
|||
}
|
||||
}
|
||||
// for password
|
||||
else if (strcmp(argv[i], "-p") == 0) {
|
||||
arguments->is_use_passwd = true;
|
||||
if (i < argc - 1 && argv[i + 1][0] != '-') {
|
||||
arguments->password = argv[++i];
|
||||
}
|
||||
else if ((strncmp(argv[i], "-p", 2) == 0)
|
||||
|| (strncmp(argv[i], "--password", 10) == 0)) {
|
||||
arguments->is_use_passwd = true;
|
||||
strcpy(tsOsName, "Windows");
|
||||
printf(WINCLIENT_VERSION, tsOsName, taos_get_client_info());
|
||||
if ((strlen(argv[i]) == 2)
|
||||
|| (strncmp(argv[i], "--password", 10) == 0)) {
|
||||
printf("Enter password: ");
|
||||
taosSetConsoleEcho(false);
|
||||
if (scanf("%s", g_password) > 1) {
|
||||
fprintf(stderr, "password read error!\n");
|
||||
}
|
||||
taosSetConsoleEcho(true);
|
||||
getchar();
|
||||
} else {
|
||||
tstrncpy(g_password, (char *)(argv[i] + 2), SHELL_MAX_PASSWORD_LEN);
|
||||
}
|
||||
arguments->password = g_password;
|
||||
strcpy(argv[i], "");
|
||||
argc -= 1;
|
||||
}
|
||||
// for management port
|
||||
else if (strcmp(argv[i], "-P") == 0) {
|
||||
|
@ -104,7 +128,7 @@ void shellParseArgument(int argc, char *argv[], SShellArguments *arguments) {
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
} else if (strcmp(argv[i], "-c") == 0) {
|
||||
if (i < argc - 1) {
|
||||
if (i < argc - 1) {
|
||||
char *tmp = argv[++i];
|
||||
if (strlen(tmp) >= TSDB_FILENAME_LEN) {
|
||||
fprintf(stderr, "config file path: %s overflow max len %d\n", tmp, TSDB_FILENAME_LEN - 1);
|
||||
|
@ -170,6 +194,22 @@ void shellParseArgument(int argc, char *argv[], SShellArguments *arguments) {
|
|||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
else if (strcmp(argv[i], "-N") == 0) {
|
||||
if (i < argc - 1) {
|
||||
arguments->pktNum = atoi(argv[++i]);
|
||||
} else {
|
||||
fprintf(stderr, "option -N requires an argument\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
else if (strcmp(argv[i], "-S") == 0) {
|
||||
if (i < argc - 1) {
|
||||
arguments->pktType = argv[++i];
|
||||
} else {
|
||||
fprintf(stderr, "option -S requires an argument\n");
|
||||
exit(EXIT_FAILURE);
|
||||
}
|
||||
}
|
||||
else if (strcmp(argv[i], "-V") == 0) {
|
||||
printVersion();
|
||||
exit(EXIT_SUCCESS);
|
||||
|
@ -265,7 +305,7 @@ void *shellLoopQuery(void *arg) {
|
|||
if (command == NULL) return NULL;
|
||||
|
||||
int32_t err = 0;
|
||||
|
||||
|
||||
do {
|
||||
memset(command, 0, MAX_COMMAND_SIZE);
|
||||
shellPrintPrompt();
|
||||
|
@ -274,7 +314,7 @@ void *shellLoopQuery(void *arg) {
|
|||
err = shellReadCommand(con, command);
|
||||
if (err) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
} while (shellRunCommand(con, command) == 0);
|
||||
|
||||
return NULL;
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -206,9 +206,9 @@ static struct argp_option options[] = {
|
|||
{"host", 'h', "HOST", 0, "Server host dumping data from. Default is localhost.", 0},
|
||||
{"user", 'u', "USER", 0, "User name used to connect to server. Default is root.", 0},
|
||||
#ifdef _TD_POWER_
|
||||
{"password", 'p', "PASSWORD", 0, "User password to connect to server. Default is powerdb.", 0},
|
||||
{"password", 'p', 0, 0, "User password to connect to server. Default is powerdb.", 0},
|
||||
#else
|
||||
{"password", 'p', "PASSWORD", 0, "User password to connect to server. Default is taosdata.", 0},
|
||||
{"password", 'p', 0, 0, "User password to connect to server. Default is taosdata.", 0},
|
||||
#endif
|
||||
{"port", 'P', "PORT", 0, "Port to connect", 0},
|
||||
{"cversion", 'v', "CVERION", 0, "client version", 0},
|
||||
|
@ -243,8 +243,6 @@ static struct argp_option options[] = {
|
|||
{"table-batch", 't', "TABLE_BATCH", 0, "Number of table dumpout into one output file. Default is 1.", 3},
|
||||
{"thread_num", 'T', "THREAD_NUM", 0, "Number of thread for dump in file. Default is 5.", 3},
|
||||
{"debug", 'g', 0, 0, "Print debug info.", 8},
|
||||
{"verbose", 'b', 0, 0, "Print verbose debug info.", 9},
|
||||
{"performanceprint", 'm', 0, 0, "Print performance debug info.", 10},
|
||||
{0}
|
||||
};
|
||||
|
||||
|
@ -253,7 +251,7 @@ typedef struct arguments {
|
|||
// connection option
|
||||
char *host;
|
||||
char *user;
|
||||
char *password;
|
||||
char password[SHELL_MAX_PASSWORD_LEN];
|
||||
uint16_t port;
|
||||
char cversion[12];
|
||||
uint16_t mysqlFlag;
|
||||
|
@ -376,7 +374,6 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||
g_args.user = arg;
|
||||
break;
|
||||
case 'p':
|
||||
g_args.password = arg;
|
||||
break;
|
||||
case 'P':
|
||||
g_args.port = atoi(arg);
|
||||
|
@ -431,7 +428,6 @@ static error_t parse_opt(int key, char *arg, struct argp_state *state) {
|
|||
break;
|
||||
// dump unit option
|
||||
case 'A':
|
||||
g_args.all_databases = true;
|
||||
break;
|
||||
case 'D':
|
||||
g_args.databases = true;
|
||||
|
@ -554,6 +550,40 @@ static void parse_precision_first(
|
|||
}
|
||||
}
|
||||
|
||||
static void parse_args(
|
||||
int argc, char *argv[], SArguments *arguments) {
|
||||
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if ((strncmp(argv[i], "-p", 2) == 0)
|
||||
|| (strncmp(argv[i], "--password", 10) == 0)) {
|
||||
if ((strlen(argv[i]) == 2)
|
||||
|| (strncmp(argv[i], "--password", 10) == 0)) {
|
||||
printf("Enter password: ");
|
||||
taosSetConsoleEcho(false);
|
||||
if(scanf("%20s", arguments->password) > 1) {
|
||||
errorPrint("%s() LN%d, password read error!\n", __func__, __LINE__);
|
||||
}
|
||||
taosSetConsoleEcho(true);
|
||||
} else {
|
||||
tstrncpy(arguments->password, (char *)(argv[i] + 2),
|
||||
SHELL_MAX_PASSWORD_LEN);
|
||||
strcpy(argv[i], "-p");
|
||||
}
|
||||
} else if (strcmp(argv[i], "-gg") == 0) {
|
||||
arguments->verbose_print = true;
|
||||
strcpy(argv[i], "");
|
||||
} else if (strcmp(argv[i], "-PP") == 0) {
|
||||
arguments->performance_print = true;
|
||||
strcpy(argv[i], "");
|
||||
} else if (strcmp(argv[i], "-A") == 0) {
|
||||
g_args.all_databases = true;
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
static void parse_timestamp(
|
||||
int argc, char *argv[], SArguments *arguments) {
|
||||
for (int i = 1; i < argc; i++) {
|
||||
|
@ -616,9 +646,10 @@ int main(int argc, char *argv[]) {
|
|||
int ret = 0;
|
||||
/* Parse our arguments; every option seen by parse_opt will be
|
||||
reflected in arguments. */
|
||||
if (argc > 2) {
|
||||
if (argc > 1) {
|
||||
parse_precision_first(argc, argv, &g_args);
|
||||
parse_timestamp(argc, argv, &g_args);
|
||||
parse_args(argc, argv, &g_args);
|
||||
}
|
||||
|
||||
argp_parse(&argp, argc, argv, 0, 0, &g_args);
|
||||
|
|
|
@ -274,6 +274,7 @@ typedef struct {
|
|||
int32_t rowSize;
|
||||
int32_t numOfRows;
|
||||
void * pIter;
|
||||
void * pVgIter;
|
||||
void ** ppShow;
|
||||
int16_t offset[TSDB_MAX_COLUMNS];
|
||||
int32_t bytes[TSDB_MAX_COLUMNS];
|
||||
|
|
|
@ -196,14 +196,20 @@ int32_t mnodeInitDnodes() {
|
|||
mnodeAddWriteMsgHandle(TSDB_MSG_TYPE_CM_CREATE_DNODE, mnodeProcessCreateDnodeMsg);
|
||||
mnodeAddWriteMsgHandle(TSDB_MSG_TYPE_CM_DROP_DNODE, mnodeProcessDropDnodeMsg);
|
||||
mnodeAddWriteMsgHandle(TSDB_MSG_TYPE_CM_CONFIG_DNODE, mnodeProcessCfgDnodeMsg);
|
||||
|
||||
mnodeAddPeerRspHandle(TSDB_MSG_TYPE_MD_CONFIG_DNODE_RSP, mnodeProcessCfgDnodeMsgRsp);
|
||||
mnodeAddPeerMsgHandle(TSDB_MSG_TYPE_DM_STATUS, mnodeProcessDnodeStatusMsg);
|
||||
|
||||
mnodeAddShowMetaHandle(TSDB_MGMT_TABLE_MODULE, mnodeGetModuleMeta);
|
||||
mnodeAddShowRetrieveHandle(TSDB_MGMT_TABLE_MODULE, mnodeRetrieveModules);
|
||||
|
||||
mnodeAddShowMetaHandle(TSDB_MGMT_TABLE_VARIABLES, mnodeGetConfigMeta);
|
||||
mnodeAddShowRetrieveHandle(TSDB_MGMT_TABLE_VARIABLES, mnodeRetrieveConfigs);
|
||||
|
||||
mnodeAddShowMetaHandle(TSDB_MGMT_TABLE_VNODES, mnodeGetVnodeMeta);
|
||||
mnodeAddShowRetrieveHandle(TSDB_MGMT_TABLE_VNODES, mnodeRetrieveVnodes);
|
||||
mnodeAddShowFreeIterHandle(TSDB_MGMT_TABLE_VNODES, mnodeCancelGetNextVgroup);
|
||||
|
||||
mnodeAddShowMetaHandle(TSDB_MGMT_TABLE_DNODE, mnodeGetDnodeMeta);
|
||||
mnodeAddShowRetrieveHandle(TSDB_MGMT_TABLE_DNODE, mnodeRetrieveDnodes);
|
||||
mnodeAddShowFreeIterHandle(TSDB_MGMT_TABLE_DNODE, mnodeCancelGetNextDnode);
|
||||
|
@ -298,7 +304,7 @@ void *mnodeGetDnodeByEp(char *ep) {
|
|||
while (1) {
|
||||
pIter = mnodeGetNextDnode(pIter, &pDnode);
|
||||
if (pDnode == NULL) break;
|
||||
if (strcmp(ep, pDnode->dnodeEp) == 0) {
|
||||
if (strncasecmp(ep, pDnode->dnodeEp, TSDB_EP_LEN) == 0) {
|
||||
mnodeCancelGetNextDnode(pIter);
|
||||
return pDnode;
|
||||
}
|
||||
|
@ -1199,7 +1205,12 @@ static int32_t mnodeGetVnodeMeta(STableMetaMsg *pMeta, SShowObj *pShow, void *pC
|
|||
|
||||
SDnodeObj *pDnode = NULL;
|
||||
if (pShow->payloadLen > 0 ) {
|
||||
pDnode = mnodeGetDnodeByEp(pShow->payload);
|
||||
char ep[TSDB_EP_LEN] = {0};
|
||||
// not use tstrncpy to make runtime happy
|
||||
uint16_t len = (pShow->payloadLen + 1) > TSDB_EP_LEN ? TSDB_EP_LEN :(pShow->payloadLen + 1);
|
||||
strncpy(ep, pShow->payload, len - 1);
|
||||
|
||||
pDnode = mnodeGetDnodeByEp(ep);
|
||||
} else {
|
||||
void *pIter = mnodeGetNextDnode(NULL, (SDnodeObj **)&pDnode);
|
||||
mnodeCancelGetNextDnode(pIter);
|
||||
|
@ -1227,13 +1238,12 @@ static int32_t mnodeRetrieveVnodes(SShowObj *pShow, char *data, int32_t rows, vo
|
|||
|
||||
pDnode = (SDnodeObj *)(pShow->pIter);
|
||||
if (pDnode != NULL) {
|
||||
void *pIter = NULL;
|
||||
SVgObj *pVgroup;
|
||||
while (1) {
|
||||
pIter = mnodeGetNextVgroup(pIter, &pVgroup);
|
||||
pShow->pVgIter = mnodeGetNextVgroup(pShow->pVgIter, &pVgroup);
|
||||
if (pVgroup == NULL) break;
|
||||
|
||||
for (int32_t i = 0; i < pVgroup->numOfVnodes; ++i) {
|
||||
for (int32_t i = 0; i < pVgroup->numOfVnodes && numOfRows < rows; ++i) {
|
||||
SVnodeGid *pVgid = &pVgroup->vnodeGid[i];
|
||||
if (pVgid->pDnode == pDnode) {
|
||||
cols = 0;
|
||||
|
@ -1245,10 +1255,13 @@ static int32_t mnodeRetrieveVnodes(SShowObj *pShow, char *data, int32_t rows, vo
|
|||
pWrite = data + pShow->offset[cols] * rows + pShow->bytes[cols] * numOfRows;
|
||||
STR_TO_VARSTR(pWrite, syncRole[pVgid->role]);
|
||||
cols++;
|
||||
|
||||
numOfRows++;
|
||||
|
||||
}
|
||||
}
|
||||
if (numOfRows >= rows) {
|
||||
break;
|
||||
}
|
||||
|
||||
mnodeDecVgroupRef(pVgroup);
|
||||
}
|
||||
|
|
|
@ -253,11 +253,15 @@ static int32_t mnodeProcessHeartBeatMsg(SMnodeMsg *pMsg) {
|
|||
|
||||
int32_t connId = htonl(pHBMsg->connId);
|
||||
SConnObj *pConn = mnodeAccquireConn(connId, connInfo.user, connInfo.clientIp, connInfo.clientPort);
|
||||
if (pConn == NULL) {
|
||||
pHBMsg->pid = htonl(pHBMsg->pid);
|
||||
pConn = mnodeCreateConn(connInfo.user, connInfo.clientIp, connInfo.clientPort, pHBMsg->pid, pHBMsg->appName);
|
||||
}
|
||||
|
||||
if (pConn == NULL) {
|
||||
// do not close existing links, otherwise
|
||||
// mError("failed to create connId, close connect");
|
||||
// pRsp->killConnection = 1;
|
||||
// pRsp->killConnection = 1;
|
||||
} else {
|
||||
pRsp->connId = htonl(pConn->connId);
|
||||
mnodeSaveQueryStreamList(pConn, pHBMsg);
|
||||
|
@ -418,8 +422,13 @@ static void* mnodePutShowObj(SShowObj *pShow) {
|
|||
|
||||
static void mnodeFreeShowObj(void *data) {
|
||||
SShowObj *pShow = *(SShowObj **)data;
|
||||
if (tsMnodeShowFreeIterFp[pShow->type] != NULL && pShow->pIter != NULL) {
|
||||
(*tsMnodeShowFreeIterFp[pShow->type])(pShow->pIter);
|
||||
if (tsMnodeShowFreeIterFp[pShow->type] != NULL) {
|
||||
if (pShow->pVgIter != NULL) {
|
||||
// only used in 'show vnodes "ep"'
|
||||
(*tsMnodeShowFreeIterFp[pShow->type])(pShow->pVgIter);
|
||||
} else {
|
||||
if (pShow->pIter != NULL) (*tsMnodeShowFreeIterFp[pShow->type])(pShow->pIter);
|
||||
}
|
||||
}
|
||||
|
||||
mDebug("%p, show is destroyed, data:%p index:%d", pShow, data, pShow->index);
|
||||
|
|
|
@ -65,7 +65,14 @@ int32_t mnodeProcessWrite(SMnodeMsg *pMsg) {
|
|||
return TSDB_CODE_MND_MSG_NOT_PROCESSED;
|
||||
}
|
||||
|
||||
int32_t code = mnodeInitMsg(pMsg);
|
||||
int32_t code = grantCheck(TSDB_GRANT_TIME);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
mError("msg:%p, app:%p type:%s not processed, reason:%s", pMsg, pMsg->rpcMsg.ahandle, taosMsg[pMsg->rpcMsg.msgType],
|
||||
tstrerror(code));
|
||||
return code;
|
||||
}
|
||||
|
||||
code = mnodeInitMsg(pMsg);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
mError("msg:%p, app:%p type:%s not processed, reason:%s", pMsg, pMsg->rpcMsg.ahandle, taosMsg[pMsg->rpcMsg.msgType],
|
||||
tstrerror(code));
|
||||
|
|
|
@ -28,8 +28,11 @@ typedef struct {
|
|||
|
||||
int32_t taosGetDiskSize(char *dataDir, SysDiskSize *diskSize);
|
||||
|
||||
int32_t taosGetCpuCores();
|
||||
void taosGetSystemInfo();
|
||||
bool taosReadProcIO(int64_t* rchars, int64_t* wchars);
|
||||
bool taosGetProcIO(float *readKB, float *writeKB);
|
||||
bool taosGetCardInfo(int64_t *bytes, int64_t *rbytes, int64_t *tbytes);
|
||||
bool taosGetBandSpeed(float *bandSpeedKb);
|
||||
void taosGetDisk();
|
||||
bool taosGetCpuUsage(float *sysCpuUsage, float *procCpuUsage) ;
|
||||
|
|
|
@ -24,6 +24,8 @@ void* taosLoadDll(const char *filename);
|
|||
void* taosLoadSym(void* handle, char* name);
|
||||
void taosCloseDll(void *handle);
|
||||
|
||||
int taosSetConsoleEcho(bool on);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
|
|
@ -29,4 +29,30 @@ void* taosLoadSym(void* handle, char* name) {
|
|||
void taosCloseDll(void *handle) {
|
||||
}
|
||||
|
||||
int taosSetConsoleEcho(bool on)
|
||||
{
|
||||
#if 0
|
||||
#define ECHOFLAGS (ECHO | ECHOE | ECHOK | ECHONL)
|
||||
int err;
|
||||
struct termios term;
|
||||
|
||||
if (tcgetattr(STDIN_FILENO, &term) == -1) {
|
||||
perror("Cannot get the attribution of the terminal");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (on)
|
||||
term.c_lflag|=ECHOFLAGS;
|
||||
else
|
||||
term.c_lflag &=~ECHOFLAGS;
|
||||
|
||||
err = tcsetattr(STDIN_FILENO,TCSAFLUSH,&term);
|
||||
if (err == -1 && err == EINTR) {
|
||||
perror("Cannot set the attribution of the terminal");
|
||||
return -1;
|
||||
}
|
||||
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -164,6 +164,10 @@ void taosKillSystem() {
|
|||
exit(0);
|
||||
}
|
||||
|
||||
int32_t taosGetCpuCores() {
|
||||
return sysconf(_SC_NPROCESSORS_ONLN);
|
||||
}
|
||||
|
||||
void taosGetSystemInfo() {
|
||||
// taosGetProcInfos();
|
||||
|
||||
|
@ -185,12 +189,25 @@ void taosGetSystemInfo() {
|
|||
taosGetSystemLocale();
|
||||
}
|
||||
|
||||
bool taosReadProcIO(int64_t *rchars, int64_t *wchars) {
|
||||
if (rchars) *rchars = 0;
|
||||
if (wchars) *wchars = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool taosGetProcIO(float *readKB, float *writeKB) {
|
||||
*readKB = 0;
|
||||
*writeKB = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool taosGetCardInfo(int64_t *bytes, int64_t *rbytes, int64_t *tbytes) {
|
||||
if (bytes) *bytes = 0;
|
||||
if (rbytes) *rbytes = 0;
|
||||
if (tbytes) *tbytes = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool taosGetBandSpeed(float *bandSpeedKb) {
|
||||
*bandSpeedKb = 0;
|
||||
return true;
|
||||
|
|
|
@ -277,7 +277,7 @@ static void taosGetSystemLocale() { // get and set default locale
|
|||
}
|
||||
}
|
||||
|
||||
static int32_t taosGetCpuCores() { return (int32_t)sysconf(_SC_NPROCESSORS_ONLN); }
|
||||
int32_t taosGetCpuCores() { return (int32_t)sysconf(_SC_NPROCESSORS_ONLN); }
|
||||
|
||||
bool taosGetCpuUsage(float *sysCpuUsage, float *procCpuUsage) {
|
||||
static uint64_t lastSysUsed = 0;
|
||||
|
@ -332,7 +332,7 @@ int32_t taosGetDiskSize(char *dataDir, SysDiskSize *diskSize) {
|
|||
}
|
||||
}
|
||||
|
||||
static bool taosGetCardInfo(int64_t *bytes) {
|
||||
bool taosGetCardInfo(int64_t *bytes, int64_t *rbytes, int64_t *tbytes) {
|
||||
*bytes = 0;
|
||||
FILE *fp = fopen(tsSysNetFile, "r");
|
||||
if (fp == NULL) {
|
||||
|
@ -347,9 +347,9 @@ static bool taosGetCardInfo(int64_t *bytes) {
|
|||
while (!feof(fp)) {
|
||||
memset(line, 0, len);
|
||||
|
||||
int64_t rbytes = 0;
|
||||
int64_t o_rbytes = 0;
|
||||
int64_t rpackts = 0;
|
||||
int64_t tbytes = 0;
|
||||
int64_t o_tbytes = 0;
|
||||
int64_t tpackets = 0;
|
||||
int64_t nouse1 = 0;
|
||||
int64_t nouse2 = 0;
|
||||
|
@ -374,8 +374,10 @@ static bool taosGetCardInfo(int64_t *bytes) {
|
|||
sscanf(line,
|
||||
"%s %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64 " %" PRId64
|
||||
" %" PRId64,
|
||||
nouse0, &rbytes, &rpackts, &nouse1, &nouse2, &nouse3, &nouse4, &nouse5, &nouse6, &tbytes, &tpackets);
|
||||
*bytes += (rbytes + tbytes);
|
||||
nouse0, &o_rbytes, &rpackts, &nouse1, &nouse2, &nouse3, &nouse4, &nouse5, &nouse6, &o_tbytes, &tpackets);
|
||||
if (rbytes) *rbytes = o_rbytes;
|
||||
if (tbytes) *tbytes = o_tbytes;
|
||||
*bytes += (o_rbytes + o_tbytes);
|
||||
}
|
||||
|
||||
tfree(line);
|
||||
|
@ -390,7 +392,7 @@ bool taosGetBandSpeed(float *bandSpeedKb) {
|
|||
int64_t curBytes = 0;
|
||||
time_t curTime = time(NULL);
|
||||
|
||||
if (!taosGetCardInfo(&curBytes)) {
|
||||
if (!taosGetCardInfo(&curBytes, NULL, NULL)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -420,7 +422,7 @@ bool taosGetBandSpeed(float *bandSpeedKb) {
|
|||
return true;
|
||||
}
|
||||
|
||||
static bool taosReadProcIO(int64_t *readbyte, int64_t *writebyte) {
|
||||
bool taosReadProcIO(int64_t *rchars, int64_t *wchars) {
|
||||
FILE *fp = fopen(tsProcIOFile, "r");
|
||||
if (fp == NULL) {
|
||||
uError("open file:%s failed", tsProcIOFile);
|
||||
|
@ -441,10 +443,10 @@ static bool taosReadProcIO(int64_t *readbyte, int64_t *writebyte) {
|
|||
break;
|
||||
}
|
||||
if (strstr(line, "rchar:") != NULL) {
|
||||
sscanf(line, "%s %" PRId64, tmp, readbyte);
|
||||
sscanf(line, "%s %" PRId64, tmp, rchars);
|
||||
readIndex++;
|
||||
} else if (strstr(line, "wchar:") != NULL) {
|
||||
sscanf(line, "%s %" PRId64, tmp, writebyte);
|
||||
sscanf(line, "%s %" PRId64, tmp, wchars);
|
||||
readIndex++;
|
||||
} else {
|
||||
}
|
||||
|
|
|
@ -51,4 +51,28 @@ void taosCloseDll(void *handle) {
|
|||
}
|
||||
}
|
||||
|
||||
int taosSetConsoleEcho(bool on)
|
||||
{
|
||||
#define ECHOFLAGS (ECHO | ECHOE | ECHOK | ECHONL)
|
||||
int err;
|
||||
struct termios term;
|
||||
|
||||
if (tcgetattr(STDIN_FILENO, &term) == -1) {
|
||||
perror("Cannot get the attribution of the terminal");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (on)
|
||||
term.c_lflag|=ECHOFLAGS;
|
||||
else
|
||||
term.c_lflag &=~ECHOFLAGS;
|
||||
|
||||
err = tcsetattr(STDIN_FILENO,TCSAFLUSH,&term);
|
||||
if (err == -1 && err == EINTR) {
|
||||
perror("Cannot set the attribution of the terminal");
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -115,7 +115,7 @@ static void taosGetSystemLocale() {
|
|||
}
|
||||
}
|
||||
|
||||
static int32_t taosGetCpuCores() {
|
||||
int32_t taosGetCpuCores() {
|
||||
SYSTEM_INFO info;
|
||||
GetSystemInfo(&info);
|
||||
return (int32_t)info.dwNumberOfProcessors;
|
||||
|
@ -146,6 +146,13 @@ int32_t taosGetDiskSize(char *dataDir, SysDiskSize *diskSize) {
|
|||
}
|
||||
}
|
||||
|
||||
bool taosGetCardInfo(int64_t *bytes, int64_t *rbytes, int64_t *tbytes) {
|
||||
if (bytes) *bytes = 0;
|
||||
if (rbytes) *rbytes = 0;
|
||||
if (tbytes) *tbytes = 0;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool taosGetBandSpeed(float *bandSpeedKb) {
|
||||
*bandSpeedKb = 0;
|
||||
return true;
|
||||
|
|
|
@ -30,3 +30,17 @@ void taosCloseDll(void *handle) {
|
|||
}
|
||||
|
||||
|
||||
int taosSetConsoleEcho(bool on)
|
||||
{
|
||||
HANDLE hStdin = GetStdHandle(STD_INPUT_HANDLE);
|
||||
DWORD mode = 0;
|
||||
GetConsoleMode(hStdin, &mode );
|
||||
if (on) {
|
||||
mode |= ENABLE_ECHO_INPUT;
|
||||
} else {
|
||||
mode &= ~ENABLE_ECHO_INPUT;
|
||||
}
|
||||
SetConsoleMode(hStdin, mode);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -0,0 +1,27 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* This program is free software: you can use, redistribute, and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3
|
||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#ifndef TDENGINE_HTTPMETRICSHANDLE_H
|
||||
#define TDENGINE_HTTPMETRICSHANDLE_H
|
||||
|
||||
#include "http.h"
|
||||
#include "httpInt.h"
|
||||
#include "httpUtil.h"
|
||||
#include "httpResp.h"
|
||||
|
||||
void metricsInitHandle(HttpServer* httpServer);
|
||||
|
||||
bool metricsProcessRequest(struct HttpContext* httpContext);
|
||||
|
||||
#endif // TDENGINE_HTTPMETRICHANDLE_H
|
|
@ -0,0 +1,184 @@
|
|||
/*
|
||||
* Copyright (c) 2019 TAOS Data, Inc. <jhtao@taosdata.com>
|
||||
*
|
||||
* This program is free software: you can use, redistribute, and/or modify
|
||||
* it under the terms of the GNU Affero General Public License, version 3
|
||||
* or later ("AGPL"), as published by the Free Software Foundation.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful, but WITHOUT
|
||||
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
||||
* FITNESS FOR A PARTICULAR PURPOSE.
|
||||
*
|
||||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#define _DEFAULT_SOURCE
|
||||
#include "os.h"
|
||||
#include "taoserror.h"
|
||||
#include "tfs.h"
|
||||
|
||||
#include "httpMetricsHandle.h"
|
||||
#include "dnode.h"
|
||||
#include "httpLog.h"
|
||||
|
||||
static HttpDecodeMethod metricsDecodeMethod = {"metrics", metricsProcessRequest};
|
||||
|
||||
void metricsInitHandle(HttpServer* pServer) {
|
||||
httpAddMethod(pServer, &metricsDecodeMethod);
|
||||
}
|
||||
|
||||
bool metricsProcessRequest(HttpContext* pContext) {
|
||||
httpDebug("context:%p, fd:%d, user:%s, process admin grant msg", pContext, pContext->fd, pContext->user);
|
||||
|
||||
JsonBuf* jsonBuf = httpMallocJsonBuf(pContext);
|
||||
if (jsonBuf == NULL) {
|
||||
httpError("failed to allocate memory for metrics");
|
||||
httpSendErrorResp(pContext, TSDB_CODE_HTTP_NO_ENOUGH_MEMORY);
|
||||
return false;
|
||||
}
|
||||
|
||||
httpInitJsonBuf(jsonBuf, pContext);
|
||||
httpWriteJsonBufHead(jsonBuf);
|
||||
|
||||
httpJsonToken(jsonBuf, JsonObjStt);
|
||||
{
|
||||
char* keyDisks = "tags";
|
||||
httpJsonPairHead(jsonBuf, keyDisks, (int32_t)strlen(keyDisks));
|
||||
httpJsonToken(jsonBuf, JsonArrStt);
|
||||
{
|
||||
httpJsonItemToken(jsonBuf);
|
||||
httpJsonToken(jsonBuf, JsonObjStt);
|
||||
char* keyTagName = "name";
|
||||
char* keyTagValue = "value";
|
||||
httpJsonPairOriginString(jsonBuf, keyTagName, (int32_t)strlen(keyTagName), "\"dnode_id\"",
|
||||
(int32_t)strlen("\"dnode_id\""));
|
||||
int32_t dnodeId = dnodeGetDnodeId();
|
||||
httpJsonPairIntVal(jsonBuf, keyTagValue, (int32_t)strlen(keyTagValue), dnodeId);
|
||||
httpJsonToken(jsonBuf, JsonObjEnd);
|
||||
}
|
||||
httpJsonToken(jsonBuf, JsonArrEnd);
|
||||
}
|
||||
|
||||
{
|
||||
if (tsDnodeStartTime != 0) {
|
||||
int64_t now = taosGetTimestampMs();
|
||||
int64_t upTime = now-tsDnodeStartTime;
|
||||
char* keyUpTime = "up_time";
|
||||
httpJsonPairInt64Val(jsonBuf, keyUpTime, (int32_t)strlen(keyUpTime), upTime);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int32_t cpuCores = taosGetCpuCores();
|
||||
char* keyCpuCores = "cpu_cores";
|
||||
httpJsonPairIntVal(jsonBuf, keyCpuCores, (int32_t)strlen(keyCpuCores), cpuCores);
|
||||
|
||||
float sysCpuUsage = 0;
|
||||
float procCpuUsage = 0;
|
||||
bool succeeded = taosGetCpuUsage(&sysCpuUsage, &procCpuUsage);
|
||||
if (!succeeded) {
|
||||
httpError("failed to get cpu usage");
|
||||
} else {
|
||||
if (sysCpuUsage <= procCpuUsage) {
|
||||
sysCpuUsage = procCpuUsage + 0.1f;
|
||||
}
|
||||
char* keyCpuSystem = "cpu_system";
|
||||
char* keyCpuEngine = "cpu_engine";
|
||||
httpJsonPairFloatVal(jsonBuf, keyCpuSystem, (int32_t)strlen(keyCpuSystem), sysCpuUsage);
|
||||
httpJsonPairFloatVal(jsonBuf, keyCpuEngine, (int32_t)strlen(keyCpuEngine), procCpuUsage);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
float sysMemoryUsedMB = 0;
|
||||
bool succeeded = taosGetSysMemory(&sysMemoryUsedMB);
|
||||
if (!succeeded) {
|
||||
httpError("failed to get sys memory info");
|
||||
} else {
|
||||
char* keyMemSystem = "mem_system";
|
||||
httpJsonPairFloatVal(jsonBuf, keyMemSystem, (int32_t)strlen(keyMemSystem), sysMemoryUsedMB);
|
||||
}
|
||||
|
||||
float procMemoryUsedMB = 0;
|
||||
succeeded = taosGetProcMemory(&procMemoryUsedMB);
|
||||
if (!succeeded) {
|
||||
httpError("failed to get proc memory info");
|
||||
} else {
|
||||
char* keyMemEngine = "mem_engine";
|
||||
httpJsonPairFloatVal(jsonBuf, keyMemEngine, (int32_t)strlen(keyMemEngine), procMemoryUsedMB);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int64_t bytes = 0, rbytes = 0, tbytes = 0;
|
||||
bool succeeded = taosGetCardInfo(&bytes, &rbytes, &tbytes);
|
||||
if (!succeeded) {
|
||||
httpError("failed to get network info");
|
||||
} else {
|
||||
char* keyNetIn = "net_in";
|
||||
char* keyNetOut = "net_out";
|
||||
httpJsonPairInt64Val(jsonBuf, keyNetIn, (int32_t)strlen(keyNetIn), rbytes);
|
||||
httpJsonPairInt64Val(jsonBuf, keyNetOut, (int32_t)strlen(keyNetOut), tbytes);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
int64_t rchars = 0;
|
||||
int64_t wchars = 0;
|
||||
bool succeeded = taosReadProcIO(&rchars, &wchars);
|
||||
if (!succeeded) {
|
||||
httpError("failed to get io info");
|
||||
} else {
|
||||
char* keyIORead = "io_read";
|
||||
char* keyIOWrite = "io_write";
|
||||
httpJsonPairInt64Val(jsonBuf, keyIORead, (int32_t)strlen(keyIORead), rchars);
|
||||
httpJsonPairInt64Val(jsonBuf, keyIOWrite, (int32_t)strlen(keyIOWrite), wchars);
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
const int8_t numTiers = 3;
|
||||
SFSMeta fsMeta;
|
||||
STierMeta* tierMetas = calloc(numTiers, sizeof(STierMeta));
|
||||
tfsUpdateInfo(&fsMeta, tierMetas, numTiers);
|
||||
{
|
||||
char* keyDiskUsed = "disk_used";
|
||||
char* keyDiskTotal = "disk_total";
|
||||
httpJsonPairInt64Val(jsonBuf, keyDiskTotal, (int32_t)strlen(keyDiskTotal), fsMeta.tsize);
|
||||
httpJsonPairInt64Val(jsonBuf, keyDiskUsed, (int32_t)strlen(keyDiskUsed), fsMeta.used);
|
||||
char* keyDisks = "disks";
|
||||
httpJsonPairHead(jsonBuf, keyDisks, (int32_t)strlen(keyDisks));
|
||||
httpJsonToken(jsonBuf, JsonArrStt);
|
||||
for (int i = 0; i < numTiers; ++i) {
|
||||
httpJsonItemToken(jsonBuf);
|
||||
httpJsonToken(jsonBuf, JsonObjStt);
|
||||
char* keyDataDirLevelUsed = "datadir_used";
|
||||
char* keyDataDirLevelTotal = "datadir_total";
|
||||
httpJsonPairInt64Val(jsonBuf, keyDataDirLevelUsed, (int32_t)strlen(keyDataDirLevelUsed), tierMetas[i].used);
|
||||
httpJsonPairInt64Val(jsonBuf, keyDataDirLevelTotal, (int32_t)strlen(keyDataDirLevelTotal), tierMetas[i].size);
|
||||
httpJsonToken(jsonBuf, JsonObjEnd);
|
||||
}
|
||||
httpJsonToken(jsonBuf, JsonArrEnd);
|
||||
}
|
||||
free(tierMetas);
|
||||
}
|
||||
|
||||
{
|
||||
SStatisInfo info = dnodeGetStatisInfo();
|
||||
{
|
||||
char* keyReqHttp = "req_http";
|
||||
char* keyReqSelect = "req_select";
|
||||
char* keyReqInsert = "req_insert";
|
||||
httpJsonPairInt64Val(jsonBuf, keyReqHttp, (int32_t)strlen(keyReqHttp), info.httpReqNum);
|
||||
httpJsonPairInt64Val(jsonBuf, keyReqSelect, (int32_t)strlen(keyReqSelect), info.queryReqNum);
|
||||
httpJsonPairInt64Val(jsonBuf, keyReqInsert, (int32_t)strlen(keyReqInsert), info.submitReqNum);
|
||||
}
|
||||
}
|
||||
|
||||
httpJsonToken(jsonBuf, JsonObjEnd);
|
||||
|
||||
httpWriteJsonBufEnd(jsonBuf);
|
||||
pContext->reqType = HTTP_REQTYPE_OTHERS;
|
||||
httpFreeJsonBuf(pContext);
|
||||
return false;
|
||||
}
|
|
@ -30,6 +30,7 @@
|
|||
#include "httpGcHandle.h"
|
||||
#include "httpRestHandle.h"
|
||||
#include "httpTgHandle.h"
|
||||
#include "httpMetricsHandle.h"
|
||||
|
||||
#ifndef _ADMIN
|
||||
void adminInitHandle(HttpServer* pServer) {}
|
||||
|
@ -52,7 +53,7 @@ int32_t httpInitSystem() {
|
|||
gcInitHandle(&tsHttpServer);
|
||||
tgInitHandle(&tsHttpServer);
|
||||
opInitHandle(&tsHttpServer);
|
||||
|
||||
metricsInitHandle(&tsHttpServer);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
|
@ -43,6 +43,10 @@ typedef int32_t (*__block_search_fn_t)(char* data, int32_t num, int64_t key, int
|
|||
|
||||
#define GET_NUM_OF_RESULTS(_r) (((_r)->outputBuf) == NULL? 0:((_r)->outputBuf)->info.rows)
|
||||
|
||||
//TODO: may need to fine tune this threshold
|
||||
#define QUERY_COMP_THRESHOLD (1024 * 512)
|
||||
#define NEEDTO_COMPRESS_QUERY(size) ((size) > QUERY_COMP_THRESHOLD ? 1 : 0)
|
||||
|
||||
enum {
|
||||
// when query starts to execute, this status will set
|
||||
QUERY_NOT_COMPLETED = 0x1u,
|
||||
|
@ -333,6 +337,9 @@ enum OPERATOR_TYPE_E {
|
|||
OP_Distinct = 20,
|
||||
OP_Join = 21,
|
||||
OP_StateWindow = 22,
|
||||
OP_AllTimeWindow = 23,
|
||||
OP_AllMultiTableTimeInterval = 24,
|
||||
OP_Order = 25,
|
||||
};
|
||||
|
||||
typedef struct SOperatorInfo {
|
||||
|
@ -420,7 +427,6 @@ typedef struct STableScanInfo {
|
|||
int32_t *rowCellInfoOffset;
|
||||
SExprInfo *pExpr;
|
||||
SSDataBlock block;
|
||||
bool loadExternalRows; // load external rows (prev & next rows)
|
||||
int32_t numOfOutput;
|
||||
int64_t elapsedTime;
|
||||
|
||||
|
@ -511,7 +517,13 @@ typedef struct SStateWindowOperatorInfo {
|
|||
int32_t start;
|
||||
char* prevData; // previous data
|
||||
bool reptScan;
|
||||
} SStateWindowOperatorInfo ;
|
||||
} SStateWindowOperatorInfo;
|
||||
|
||||
typedef struct SDistinctDataInfo {
|
||||
int32_t index;
|
||||
int32_t type;
|
||||
int32_t bytes;
|
||||
} SDistinctDataInfo;
|
||||
|
||||
typedef struct SDistinctOperatorInfo {
|
||||
SHashObj *pSet;
|
||||
|
@ -519,7 +531,9 @@ typedef struct SDistinctOperatorInfo {
|
|||
bool recordNullVal; //has already record the null value, no need to try again
|
||||
int64_t threshold;
|
||||
int64_t outputCapacity;
|
||||
int32_t colIndex;
|
||||
int32_t totalBytes;
|
||||
char* buf;
|
||||
SArray* pDistinctDataInfo;
|
||||
} SDistinctOperatorInfo;
|
||||
|
||||
struct SGlobalMerger;
|
||||
|
@ -544,6 +558,13 @@ typedef struct SMultiwayMergeInfo {
|
|||
SArray *udfInfo;
|
||||
} SMultiwayMergeInfo;
|
||||
|
||||
// todo support the disk-based sort
|
||||
typedef struct SOrderOperatorInfo {
|
||||
int32_t colIndex;
|
||||
int32_t order;
|
||||
SSDataBlock *pDataBlock;
|
||||
} SOrderOperatorInfo;
|
||||
|
||||
void appendUpstream(SOperatorInfo* p, SOperatorInfo* pUpstream);
|
||||
|
||||
SOperatorInfo* createDataBlocksOptScanInfo(void* pTsdbQueryHandle, SQueryRuntimeEnv* pRuntimeEnv, int32_t repeatTime, int32_t reverseTime);
|
||||
|
@ -554,11 +575,13 @@ SOperatorInfo* createAggregateOperatorInfo(SQueryRuntimeEnv* pRuntimeEnv, SOpera
|
|||
SOperatorInfo* createProjectOperatorInfo(SQueryRuntimeEnv* pRuntimeEnv, SOperatorInfo* upstream, SExprInfo* pExpr, int32_t numOfOutput);
|
||||
SOperatorInfo* createLimitOperatorInfo(SQueryRuntimeEnv* pRuntimeEnv, SOperatorInfo* upstream);
|
||||
SOperatorInfo* createTimeIntervalOperatorInfo(SQueryRuntimeEnv* pRuntimeEnv, SOperatorInfo* upstream, SExprInfo* pExpr, int32_t numOfOutput);
|
||||
SOperatorInfo* createAllTimeIntervalOperatorInfo(SQueryRuntimeEnv* pRuntimeEnv, SOperatorInfo* upstream, SExprInfo* pExpr, int32_t numOfOutput);
|
||||
SOperatorInfo* createSWindowOperatorInfo(SQueryRuntimeEnv* pRuntimeEnv, SOperatorInfo* upstream, SExprInfo* pExpr, int32_t numOfOutput);
|
||||
SOperatorInfo* createFillOperatorInfo(SQueryRuntimeEnv* pRuntimeEnv, SOperatorInfo* upstream, SExprInfo* pExpr, int32_t numOfOutput);
|
||||
SOperatorInfo* createGroupbyOperatorInfo(SQueryRuntimeEnv* pRuntimeEnv, SOperatorInfo* upstream, SExprInfo* pExpr, int32_t numOfOutput);
|
||||
SOperatorInfo* createMultiTableAggOperatorInfo(SQueryRuntimeEnv* pRuntimeEnv, SOperatorInfo* upstream, SExprInfo* pExpr, int32_t numOfOutput);
|
||||
SOperatorInfo* createMultiTableTimeIntervalOperatorInfo(SQueryRuntimeEnv* pRuntimeEnv, SOperatorInfo* upstream, SExprInfo* pExpr, int32_t numOfOutput);
|
||||
SOperatorInfo* createAllMultiTableTimeIntervalOperatorInfo(SQueryRuntimeEnv* pRuntimeEnv, SOperatorInfo* upstream, SExprInfo* pExpr, int32_t numOfOutput);
|
||||
SOperatorInfo* createTagScanOperatorInfo(SQueryRuntimeEnv* pRuntimeEnv, SExprInfo* pExpr, int32_t numOfOutput);
|
||||
SOperatorInfo* createDistinctOperatorInfo(SQueryRuntimeEnv* pRuntimeEnv, SOperatorInfo* upstream, SExprInfo* pExpr, int32_t numOfOutput);
|
||||
SOperatorInfo* createTableBlockInfoScanOperator(void* pTsdbQueryHandle, SQueryRuntimeEnv* pRuntimeEnv);
|
||||
|
@ -571,6 +594,7 @@ SOperatorInfo* createFilterOperatorInfo(SQueryRuntimeEnv* pRuntimeEnv, SOperator
|
|||
int32_t numOfOutput, SColumnInfo* pCols, int32_t numOfFilter);
|
||||
|
||||
SOperatorInfo* createJoinOperatorInfo(SOperatorInfo** pUpstream, int32_t numOfUpstream, SSchema* pSchema, int32_t numOfOutput);
|
||||
SOperatorInfo* createOrderOperatorInfo(SQueryRuntimeEnv* pRuntimeEnv, SOperatorInfo* upstream, SExprInfo* pExpr, int32_t numOfOutput, SOrderVal* pOrderVal);
|
||||
|
||||
SSDataBlock* doGlobalAggregate(void* param, bool* newgroup);
|
||||
SSDataBlock* doMultiwayMergeSort(void* param, bool* newgroup);
|
||||
|
@ -578,7 +602,6 @@ SSDataBlock* doSLimit(void* param, bool* newgroup);
|
|||
|
||||
int32_t doCreateFilterInfo(SColumnInfo* pCols, int32_t numOfCols, int32_t numOfFilterCols, SSingleColumnFilterInfo** pFilterInfo, uint64_t qId);
|
||||
void doSetFilterColumnInfo(SSingleColumnFilterInfo* pFilterInfo, int32_t numOfFilterCols, SSDataBlock* pBlock);
|
||||
void doSetFilterColInfo(SFilterInfo *pFilters, SSDataBlock* pBlock);
|
||||
bool doFilterDataBlock(SSingleColumnFilterInfo* pFilterInfo, int32_t numOfFilterCols, int32_t numOfRows, int8_t* p);
|
||||
void doCompactSDataBlock(SSDataBlock* pBlock, int32_t numOfRows, int8_t* p);
|
||||
|
||||
|
@ -619,6 +642,7 @@ int32_t buildArithmeticExprFromMsg(SExprInfo *pArithExprInfo, void *pQueryMsg);
|
|||
|
||||
bool isQueryKilled(SQInfo *pQInfo);
|
||||
int32_t checkForQueryBuf(size_t numOfTables);
|
||||
bool checkNeedToCompressQueryCol(SQInfo *pQInfo);
|
||||
bool doBuildResCheck(SQInfo* pQInfo);
|
||||
void setQueryStatus(SQueryRuntimeEnv *pRuntimeEnv, int8_t status);
|
||||
|
||||
|
@ -627,7 +651,7 @@ void destroyUdfInfo(SUdfInfo* pUdfInfo);
|
|||
|
||||
bool isValidQInfo(void *param);
|
||||
|
||||
int32_t doDumpQueryResult(SQInfo *pQInfo, char *data);
|
||||
int32_t doDumpQueryResult(SQInfo *pQInfo, char *data, int8_t compressed, int32_t *compLen);
|
||||
|
||||
size_t getResultSize(SQInfo *pQInfo, int64_t *numOfRows);
|
||||
void setQueryKilled(SQInfo *pQInfo);
|
||||
|
|
|
@ -227,6 +227,8 @@ typedef int (*__col_compar_fn_t)(tOrderDescriptor *, int32_t numOfRows, int32_t
|
|||
|
||||
void tColDataQSort(tOrderDescriptor *, int32_t numOfRows, int32_t start, int32_t end, char *data, int32_t orderType);
|
||||
|
||||
void taoscQSort(void** pCols, SSchema* pSchema, int32_t numOfCols, int32_t numOfRows, int32_t index, __compar_fn_t compareFn);
|
||||
|
||||
int32_t compare_sa(tOrderDescriptor *, int32_t numOfRows, int32_t idx1, int32_t idx2, char *data);
|
||||
|
||||
int32_t compare_sd(tOrderDescriptor *, int32_t numOfRows, int32_t idx1, int32_t idx2, char *data);
|
||||
|
|
|
@ -31,10 +31,11 @@ extern "C" {
|
|||
#define FILTER_DEFAULT_GROUP_UNIT_SIZE 2
|
||||
|
||||
#define FILTER_DUMMY_EMPTY_OPTR 127
|
||||
#define FILTER_DUMMY_RANGE_OPTR 126
|
||||
|
||||
#define MAX_NUM_STR_SIZE 40
|
||||
|
||||
#define FILTER_RM_UNIT_MIN_ROWS 100
|
||||
|
||||
enum {
|
||||
FLD_TYPE_COLUMN = 1,
|
||||
FLD_TYPE_VALUE = 2,
|
||||
|
@ -70,6 +71,12 @@ enum {
|
|||
FI_STATUS_CLONED = 8,
|
||||
};
|
||||
|
||||
enum {
|
||||
FI_STATUS_BLK_ALL = 1,
|
||||
FI_STATUS_BLK_EMPTY = 2,
|
||||
FI_STATUS_BLK_ACTIVE = 4,
|
||||
};
|
||||
|
||||
enum {
|
||||
RANGE_TYPE_UNIT = 1,
|
||||
RANGE_TYPE_VAR_HASH = 2,
|
||||
|
@ -98,7 +105,7 @@ typedef struct SFilterColRange {
|
|||
|
||||
typedef bool (*rangeCompFunc) (const void *, const void *, const void *, const void *, __compar_fn_t);
|
||||
typedef int32_t(*filter_desc_compare_func)(const void *, const void *);
|
||||
typedef bool(*filter_exec_func)(void *, int32_t, int8_t*);
|
||||
typedef bool(*filter_exec_func)(void *, int32_t, int8_t**, SDataStatis *, int16_t);
|
||||
|
||||
typedef struct SFilterRangeCompare {
|
||||
int64_t s;
|
||||
|
@ -197,6 +204,7 @@ typedef struct SFilterComUnit {
|
|||
void *colData;
|
||||
void *valData;
|
||||
void *valData2;
|
||||
uint16_t colId;
|
||||
uint16_t dataSize;
|
||||
uint8_t dataType;
|
||||
uint8_t optr;
|
||||
|
@ -224,7 +232,11 @@ typedef struct SFilterInfo {
|
|||
uint8_t *unitRes; // result
|
||||
uint8_t *unitFlags; // got result
|
||||
SFilterRangeCtx **colRange;
|
||||
filter_exec_func func;
|
||||
filter_exec_func func;
|
||||
uint8_t blkFlag;
|
||||
uint16_t blkGroupNum;
|
||||
uint16_t *blkUnits;
|
||||
int8_t *blkUnitRes;
|
||||
|
||||
SFilterPCtx pctx;
|
||||
} SFilterInfo;
|
||||
|
@ -265,12 +277,13 @@ typedef struct SFilterInfo {
|
|||
#define CHK_RET(c, r) do { if (c) { return r; } } while (0)
|
||||
#define CHK_JMP(c) do { if (c) { goto _return; } } while (0)
|
||||
#define CHK_LRETV(c,...) do { if (c) { qError(__VA_ARGS__); return; } } while (0)
|
||||
#define CHK_LRET(c, r,...) do { if (c) { qError(__VA_ARGS__); return r; } } while (0)
|
||||
#define CHK_LRET(c, r,...) do { if (c) { if (r) {qError(__VA_ARGS__); } else { qDebug(__VA_ARGS__); } return r; } } while (0)
|
||||
|
||||
#define FILTER_GET_FIELD(i, id) (&((i)->fields[(id).type].fields[(id).idx]))
|
||||
#define FILTER_GET_COL_FIELD(i, idx) (&((i)->fields[FLD_TYPE_COLUMN].fields[idx]))
|
||||
#define FILTER_GET_COL_FIELD_TYPE(fi) (((SSchema *)((fi)->desc))->type)
|
||||
#define FILTER_GET_COL_FIELD_SIZE(fi) (((SSchema *)((fi)->desc))->bytes)
|
||||
#define FILTER_GET_COL_FIELD_ID(fi) (((SSchema *)((fi)->desc))->colId)
|
||||
#define FILTER_GET_COL_FIELD_DESC(fi) ((SSchema *)((fi)->desc))
|
||||
#define FILTER_GET_COL_FIELD_DATA(fi, ri) ((char *)(fi)->data + ((SSchema *)((fi)->desc))->bytes * (ri))
|
||||
#define FILTER_GET_VAL_FIELD_TYPE(fi) (((tVariant *)((fi)->desc))->nType)
|
||||
|
@ -280,10 +293,12 @@ typedef struct SFilterInfo {
|
|||
#define FILTER_GROUP_UNIT(i, g, uid) ((i)->units + (g)->unitIdxs[uid])
|
||||
#define FILTER_UNIT_LEFT_FIELD(i, u) FILTER_GET_FIELD(i, (u)->left)
|
||||
#define FILTER_UNIT_RIGHT_FIELD(i, u) FILTER_GET_FIELD(i, (u)->right)
|
||||
#define FILTER_UNIT_RIGHT2_FIELD(i, u) FILTER_GET_FIELD(i, (u)->right2)
|
||||
#define FILTER_UNIT_DATA_TYPE(u) ((u)->compare.type)
|
||||
#define FILTER_UNIT_COL_DESC(i, u) FILTER_GET_COL_FIELD_DESC(FILTER_UNIT_LEFT_FIELD(i, u))
|
||||
#define FILTER_UNIT_COL_DATA(i, u, ri) FILTER_GET_COL_FIELD_DATA(FILTER_UNIT_LEFT_FIELD(i, u), ri)
|
||||
#define FILTER_UNIT_COL_SIZE(i, u) FILTER_GET_COL_FIELD_SIZE(FILTER_UNIT_LEFT_FIELD(i, u))
|
||||
#define FILTER_UNIT_COL_ID(i, u) FILTER_GET_COL_FIELD_ID(FILTER_UNIT_LEFT_FIELD(i, u))
|
||||
#define FILTER_UNIT_VAL_DATA(i, u) FILTER_GET_VAL_FIELD_DATA(FILTER_UNIT_RIGHT_FIELD(i, u))
|
||||
#define FILTER_UNIT_COL_IDX(u) ((u)->left.idx)
|
||||
#define FILTER_UNIT_OPTR(u) ((u)->compare.optr)
|
||||
|
@ -309,8 +324,8 @@ typedef struct SFilterInfo {
|
|||
|
||||
|
||||
extern int32_t filterInitFromTree(tExprNode* tree, SFilterInfo **pinfo, uint32_t options);
|
||||
extern bool filterExecute(SFilterInfo *info, int32_t numOfRows, int8_t* p);
|
||||
extern int32_t filterSetColFieldData(SFilterInfo *info, int16_t colId, void *data);
|
||||
extern bool filterExecute(SFilterInfo *info, int32_t numOfRows, int8_t** p, SDataStatis *statis, int16_t numOfCols);
|
||||
extern int32_t filterSetColFieldData(SFilterInfo *info, int32_t numOfCols, SArray* pDataBlock);
|
||||
extern int32_t filterGetTimeRange(SFilterInfo *info, STimeWindow *win);
|
||||
extern int32_t filterConverNcharColumns(SFilterInfo* pFilterInfo, int32_t rows, bool *gotNchar);
|
||||
extern int32_t filterFreeNcharColumns(SFilterInfo* pFilterInfo);
|
||||
|
|
|
@ -39,7 +39,6 @@
|
|||
#define GET_QID(_r) (((SQInfo*)((_r)->qinfo))->qId)
|
||||
|
||||
#define curTimeWindowIndex(_winres) ((_winres)->curIndex)
|
||||
#define GET_ROW_PARAM_FOR_MULTIOUTPUT(_q, tbq, sq) (((tbq) && (!(sq)))? (_q)->pExpr1[1].base.param[0].i64:1)
|
||||
|
||||
int32_t getOutputInterResultBufSize(SQueryAttr* pQueryAttr);
|
||||
|
||||
|
@ -60,6 +59,7 @@ SResultRowCellInfo* getResultCell(const SResultRow* pRow, int32_t index, int32_t
|
|||
|
||||
void* destroyQueryFuncExpr(SExprInfo* pExprInfo, int32_t numOfExpr);
|
||||
void* freeColumnInfo(SColumnInfo* pColumnInfo, int32_t numOfCols);
|
||||
int32_t getRowNumForMultioutput(SQueryAttr* pQueryAttr, bool topBottomQuery, bool stable);
|
||||
|
||||
static FORCE_INLINE SResultRow *getResultRow(SResultRowInfo *pResultRowInfo, int32_t slot) {
|
||||
assert(pResultRowInfo != NULL && slot >= 0 && slot < pResultRowInfo->size);
|
||||
|
@ -70,7 +70,7 @@ static FORCE_INLINE char* getPosInResultPage(SQueryAttr* pQueryAttr, tFilePage*
|
|||
int32_t offset) {
|
||||
assert(rowOffset >= 0 && pQueryAttr != NULL);
|
||||
|
||||
int32_t numOfRows = (int32_t)GET_ROW_PARAM_FOR_MULTIOUTPUT(pQueryAttr, pQueryAttr->topBotQuery, pQueryAttr->stableQuery);
|
||||
int32_t numOfRows = (int32_t)getRowNumForMultioutput(pQueryAttr, pQueryAttr->topBotQuery, pQueryAttr->stableQuery);
|
||||
return ((char *)page->data) + rowOffset + offset * numOfRows;
|
||||
}
|
||||
|
||||
|
|
|
@ -3708,27 +3708,59 @@ static void interp_function_impl(SQLFunctionCtx *pCtx) {
|
|||
}
|
||||
} else {
|
||||
// no data generated yet
|
||||
if (pCtx->size == 1) {
|
||||
if (pCtx->size < 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// check the timestamp in input buffer
|
||||
TSKEY skey = GET_TS_DATA(pCtx, 0);
|
||||
TSKEY ekey = GET_TS_DATA(pCtx, 1);
|
||||
|
||||
// no data generated yet
|
||||
if (!(skey < pCtx->startTs && ekey > pCtx->startTs)) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(pCtx->start.key == INT64_MIN && skey < pCtx->startTs && ekey > pCtx->startTs);
|
||||
|
||||
if (type == TSDB_FILL_PREV) {
|
||||
if (skey > pCtx->startTs) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (pCtx->size > 1) {
|
||||
TSKEY ekey = GET_TS_DATA(pCtx, 1);
|
||||
if (ekey > skey && ekey <= pCtx->startTs) {
|
||||
skey = ekey;
|
||||
}
|
||||
}
|
||||
assignVal(pCtx->pOutput, pCtx->pInput, pCtx->outputBytes, pCtx->inputType);
|
||||
} else if (type == TSDB_FILL_NEXT) {
|
||||
char* val = ((char*)pCtx->pInput) + pCtx->inputBytes;
|
||||
TSKEY ekey = skey;
|
||||
char* val = NULL;
|
||||
|
||||
if (ekey < pCtx->startTs) {
|
||||
if (pCtx->size > 1) {
|
||||
ekey = GET_TS_DATA(pCtx, 1);
|
||||
if (ekey < pCtx->startTs) {
|
||||
return;
|
||||
}
|
||||
|
||||
val = ((char*)pCtx->pInput) + pCtx->inputBytes;
|
||||
} else {
|
||||
return;
|
||||
}
|
||||
} else {
|
||||
val = (char*)pCtx->pInput;
|
||||
}
|
||||
|
||||
assignVal(pCtx->pOutput, val, pCtx->outputBytes, pCtx->inputType);
|
||||
} else if (type == TSDB_FILL_LINEAR) {
|
||||
if (pCtx->size <= 1) {
|
||||
return;
|
||||
}
|
||||
|
||||
TSKEY ekey = GET_TS_DATA(pCtx, 1);
|
||||
|
||||
// no data generated yet
|
||||
if (!(skey < pCtx->startTs && ekey > pCtx->startTs)) {
|
||||
return;
|
||||
}
|
||||
|
||||
assert(pCtx->start.key == INT64_MIN && skey < pCtx->startTs && ekey > pCtx->startTs);
|
||||
|
||||
char *start = GET_INPUT_DATA(pCtx, 0);
|
||||
char *end = GET_INPUT_DATA(pCtx, 1);
|
||||
|
||||
|
@ -4030,12 +4062,15 @@ static void mergeTableBlockDist(SResultRowCellInfo* pResInfo, const STableBlockD
|
|||
pDist->maxRows = pSrc->maxRows;
|
||||
pDist->minRows = pSrc->minRows;
|
||||
|
||||
int32_t numSteps = tsMaxRowsInFileBlock/TSDB_BLOCK_DIST_STEP_ROWS;
|
||||
pDist->dataBlockInfos = taosArrayInit(numSteps, sizeof(SFileBlockInfo));
|
||||
taosArraySetSize(pDist->dataBlockInfos, numSteps);
|
||||
int32_t maxSteps = TSDB_MAX_MAX_ROW_FBLOCK/TSDB_BLOCK_DIST_STEP_ROWS;
|
||||
if (TSDB_MAX_MAX_ROW_FBLOCK % TSDB_BLOCK_DIST_STEP_ROWS != 0) {
|
||||
++maxSteps;
|
||||
}
|
||||
pDist->dataBlockInfos = taosArrayInit(maxSteps, sizeof(SFileBlockInfo));
|
||||
taosArraySetSize(pDist->dataBlockInfos, maxSteps);
|
||||
}
|
||||
|
||||
size_t steps = taosArrayGetSize(pDist->dataBlockInfos);
|
||||
size_t steps = taosArrayGetSize(pSrc->dataBlockInfos);
|
||||
for (int32_t i = 0; i < steps; ++i) {
|
||||
int32_t srcNumBlocks = ((SFileBlockInfo*)taosArrayGet(pSrc->dataBlockInfos, i))->numBlocksOfStep;
|
||||
SFileBlockInfo* blockInfo = (SFileBlockInfo*)taosArrayGet(pDist->dataBlockInfos, i);
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -12,7 +12,6 @@
|
|||
* You should have received a copy of the GNU Affero General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "qExtbuffer.h"
|
||||
#include "os.h"
|
||||
#include "qAggMain.h"
|
||||
#include "queryLog.h"
|
||||
|
@ -21,6 +20,8 @@
|
|||
#include "taosmsg.h"
|
||||
#include "tulog.h"
|
||||
#include "qExecutor.h"
|
||||
#include "qExtbuffer.h"
|
||||
#include "tcompare.h"
|
||||
|
||||
#define COLMODEL_GET_VAL(data, schema, allrow, rowId, colId) \
|
||||
(data + (schema)->pFields[colId].offset * (allrow) + (rowId) * (schema)->pFields[colId].field.bytes)
|
||||
|
@ -767,6 +768,60 @@ void tColDataQSort(tOrderDescriptor *pDescriptor, int32_t numOfRows, int32_t sta
|
|||
free(buf);
|
||||
}
|
||||
|
||||
void taoscQSort(void** pCols, SSchema* pSchema, int32_t numOfCols, int32_t numOfRows, int32_t index, __compar_fn_t compareFn) {
|
||||
assert(numOfRows > 0 && numOfCols > 0 && index >= 0 && index < numOfCols);
|
||||
|
||||
int32_t bytes = pSchema[index].bytes;
|
||||
int32_t size = bytes + sizeof(int32_t);
|
||||
|
||||
char* buf = calloc(1, size * numOfRows);
|
||||
|
||||
for(int32_t i = 0; i < numOfRows; ++i) {
|
||||
char* dest = buf + size * i;
|
||||
memcpy(dest, ((char*)pCols[index]) + bytes * i, bytes);
|
||||
*(int32_t*)(dest+bytes) = i;
|
||||
}
|
||||
|
||||
qsort(buf, numOfRows, size, compareFn);
|
||||
|
||||
int32_t prevLength = 0;
|
||||
char* p = NULL;
|
||||
|
||||
for(int32_t i = 0; i < numOfCols; ++i) {
|
||||
int32_t bytes1 = pSchema[i].bytes;
|
||||
|
||||
if (i == index) {
|
||||
for(int32_t j = 0; j < numOfRows; ++j){
|
||||
char* src = buf + (j * size);
|
||||
char* dest = (char*) pCols[i] + (j * bytes1);
|
||||
memcpy(dest, src, bytes1);
|
||||
}
|
||||
} else {
|
||||
// make sure memory buffer is enough
|
||||
if (prevLength < bytes1) {
|
||||
char *tmp = realloc(p, bytes1 * numOfRows);
|
||||
assert(tmp);
|
||||
|
||||
p = tmp;
|
||||
prevLength = bytes1;
|
||||
}
|
||||
|
||||
memcpy(p, pCols[i], bytes1 * numOfRows);
|
||||
|
||||
for(int32_t j = 0; j < numOfRows; ++j){
|
||||
char* dest = (char*) pCols[i] + bytes1 * j;
|
||||
|
||||
int32_t newPos = *(int32_t*)(buf + (j * size) + bytes);
|
||||
char* src = p + (newPos * bytes1);
|
||||
memcpy(dest, src, bytes1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
tfree(buf);
|
||||
tfree(p);
|
||||
}
|
||||
|
||||
/*
|
||||
* deep copy of sschema
|
||||
*/
|
||||
|
|
|
@ -206,6 +206,12 @@ static int32_t fillResultImpl(SFillInfo* pFillInfo, void** data, int32_t outputR
|
|||
} else {
|
||||
assert(pFillInfo->currentKey == ts);
|
||||
initBeforeAfterDataBuf(pFillInfo, prev);
|
||||
if (pFillInfo->type == TSDB_FILL_NEXT && (pFillInfo->index + 1) < pFillInfo->numOfRows) {
|
||||
initBeforeAfterDataBuf(pFillInfo, next);
|
||||
++pFillInfo->index;
|
||||
copyCurrentRowIntoBuf(pFillInfo, srcData, *next);
|
||||
--pFillInfo->index;
|
||||
}
|
||||
|
||||
// assign rows to dst buffer
|
||||
for (int32_t i = 0; i < pFillInfo->numOfCols; ++i) {
|
||||
|
@ -227,6 +233,12 @@ static int32_t fillResultImpl(SFillInfo* pFillInfo, void** data, int32_t outputR
|
|||
} else if (pFillInfo->type == TSDB_FILL_LINEAR) {
|
||||
assignVal(output, src, pCol->col.bytes, pCol->col.type);
|
||||
memcpy(*prev + pCol->col.offset, src, pCol->col.bytes);
|
||||
} else if (pFillInfo->type == TSDB_FILL_NEXT) {
|
||||
if (*next) {
|
||||
assignVal(output, *next + pCol->col.offset, pCol->col.bytes, pCol->col.type);
|
||||
} else {
|
||||
setNull(output, pCol->col.type, pCol->col.bytes);
|
||||
}
|
||||
} else {
|
||||
assignVal(output, (char*)&pCol->fillVal.i, pCol->col.bytes, pCol->col.type);
|
||||
}
|
||||
|
|
|
@ -157,7 +157,7 @@ __compar_fn_t gDataCompare[] = {compareInt32Val, compareInt8Val, compareInt16Val
|
|||
compareDoubleVal, compareLenPrefixedStr, compareStrPatternComp, compareFindItemInSet, compareWStrPatternComp,
|
||||
compareLenPrefixedWStr, compareUint8Val, compareUint16Val, compareUint32Val, compareUint64Val,
|
||||
setCompareBytes1, setCompareBytes2, setCompareBytes4, setCompareBytes8
|
||||
};
|
||||
};
|
||||
|
||||
int8_t filterGetCompFuncIdx(int32_t type, int32_t optr) {
|
||||
int8_t comparFn = 0;
|
||||
|
@ -1521,7 +1521,7 @@ void filterDumpInfoToString(SFilterInfo *info, const char *msg, int32_t options)
|
|||
int32_t type = FILTER_UNIT_DATA_TYPE(unit);
|
||||
int32_t len = 0;
|
||||
int32_t tlen = 0;
|
||||
char str[256] = {0};
|
||||
char str[512] = {0};
|
||||
|
||||
SFilterField *left = FILTER_UNIT_LEFT_FIELD(info, unit);
|
||||
SSchema *sch = left->desc;
|
||||
|
@ -1539,6 +1539,24 @@ void filterDumpInfoToString(SFilterInfo *info, const char *msg, int32_t options)
|
|||
strcat(str, "NULL");
|
||||
}
|
||||
strcat(str, "]");
|
||||
|
||||
if (unit->compare.optr2) {
|
||||
strcat(str, " && ");
|
||||
sprintf(str + strlen(str), "[%d][%s] %s [", sch->colId, sch->name, gOptrStr[unit->compare.optr2].str);
|
||||
|
||||
if (unit->right2.type == FLD_TYPE_VALUE && FILTER_UNIT_OPTR(unit) != TSDB_RELATION_IN) {
|
||||
SFilterField *right = FILTER_UNIT_RIGHT2_FIELD(info, unit);
|
||||
char *data = right->data;
|
||||
if (IS_VAR_DATA_TYPE(type)) {
|
||||
tlen = varDataLen(data);
|
||||
data += VARSTR_HEADER_SIZE;
|
||||
}
|
||||
converToStr(str + strlen(str), type, data, tlen > 32 ? 32 : tlen, &tlen);
|
||||
} else {
|
||||
strcat(str, "NULL");
|
||||
}
|
||||
strcat(str, "]");
|
||||
}
|
||||
|
||||
qDebug("%s", str); //TODO
|
||||
}
|
||||
|
@ -1556,37 +1574,63 @@ void filterDumpInfoToString(SFilterInfo *info, const char *msg, int32_t options)
|
|||
return;
|
||||
}
|
||||
|
||||
qDebug("%s - RANGE info:", msg);
|
||||
if (options == 1) {
|
||||
qDebug("%s - RANGE info:", msg);
|
||||
|
||||
qDebug("RANGE Num:%u", info->colRangeNum);
|
||||
for (uint16_t i = 0; i < info->colRangeNum; ++i) {
|
||||
SFilterRangeCtx *ctx = info->colRange[i];
|
||||
qDebug("Column ID[%d] RANGE: isnull[%d],notnull[%d],range[%d]", ctx->colId, ctx->isnull, ctx->notnull, ctx->isrange);
|
||||
if (ctx->isrange) {
|
||||
SFilterRangeNode *r = ctx->rs;
|
||||
while (r) {
|
||||
char str[256] = {0};
|
||||
int32_t tlen = 0;
|
||||
if (FILTER_GET_FLAG(r->ra.sflag, RANGE_FLG_NULL)) {
|
||||
strcat(str,"(NULL)");
|
||||
} else {
|
||||
FILTER_GET_FLAG(r->ra.sflag, RANGE_FLG_EXCLUDE) ? strcat(str,"(") : strcat(str,"[");
|
||||
converToStr(str + strlen(str), ctx->type, &r->ra.s, tlen > 32 ? 32 : tlen, &tlen);
|
||||
FILTER_GET_FLAG(r->ra.sflag, RANGE_FLG_EXCLUDE) ? strcat(str,")") : strcat(str,"]");
|
||||
qDebug("RANGE Num:%u", info->colRangeNum);
|
||||
for (uint16_t i = 0; i < info->colRangeNum; ++i) {
|
||||
SFilterRangeCtx *ctx = info->colRange[i];
|
||||
qDebug("Column ID[%d] RANGE: isnull[%d],notnull[%d],range[%d]", ctx->colId, ctx->isnull, ctx->notnull, ctx->isrange);
|
||||
if (ctx->isrange) {
|
||||
SFilterRangeNode *r = ctx->rs;
|
||||
while (r) {
|
||||
char str[256] = {0};
|
||||
int32_t tlen = 0;
|
||||
if (FILTER_GET_FLAG(r->ra.sflag, RANGE_FLG_NULL)) {
|
||||
strcat(str,"(NULL)");
|
||||
} else {
|
||||
FILTER_GET_FLAG(r->ra.sflag, RANGE_FLG_EXCLUDE) ? strcat(str,"(") : strcat(str,"[");
|
||||
converToStr(str + strlen(str), ctx->type, &r->ra.s, tlen > 32 ? 32 : tlen, &tlen);
|
||||
FILTER_GET_FLAG(r->ra.sflag, RANGE_FLG_EXCLUDE) ? strcat(str,")") : strcat(str,"]");
|
||||
}
|
||||
strcat(str, " - ");
|
||||
if (FILTER_GET_FLAG(r->ra.eflag, RANGE_FLG_NULL)) {
|
||||
strcat(str, "(NULL)");
|
||||
} else {
|
||||
FILTER_GET_FLAG(r->ra.eflag, RANGE_FLG_EXCLUDE) ? strcat(str,"(") : strcat(str,"[");
|
||||
converToStr(str + strlen(str), ctx->type, &r->ra.e, tlen > 32 ? 32 : tlen, &tlen);
|
||||
FILTER_GET_FLAG(r->ra.eflag, RANGE_FLG_EXCLUDE) ? strcat(str,")") : strcat(str,"]");
|
||||
}
|
||||
qDebug("range: %s", str);
|
||||
|
||||
r = r->next;
|
||||
}
|
||||
strcat(str, " - ");
|
||||
if (FILTER_GET_FLAG(r->ra.eflag, RANGE_FLG_NULL)) {
|
||||
strcat(str, "(NULL)");
|
||||
} else {
|
||||
FILTER_GET_FLAG(r->ra.eflag, RANGE_FLG_EXCLUDE) ? strcat(str,"(") : strcat(str,"[");
|
||||
converToStr(str + strlen(str), ctx->type, &r->ra.e, tlen > 32 ? 32 : tlen, &tlen);
|
||||
FILTER_GET_FLAG(r->ra.eflag, RANGE_FLG_EXCLUDE) ? strcat(str,")") : strcat(str,"]");
|
||||
}
|
||||
qDebug("range: %s", str);
|
||||
|
||||
r = r->next;
|
||||
}
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug("%s - Block Filter info:", msg);
|
||||
|
||||
if (FILTER_GET_FLAG(info->blkFlag, FI_STATUS_BLK_ALL)) {
|
||||
qDebug("Flag:%s", "ALL");
|
||||
return;
|
||||
} else if (FILTER_GET_FLAG(info->blkFlag, FI_STATUS_BLK_EMPTY)) {
|
||||
qDebug("Flag:%s", "EMPTY");
|
||||
return;
|
||||
} else if (FILTER_GET_FLAG(info->blkFlag, FI_STATUS_BLK_ACTIVE)){
|
||||
qDebug("Flag:%s", "ACTIVE");
|
||||
}
|
||||
|
||||
qDebug("GroupNum:%d", info->blkGroupNum);
|
||||
uint16_t *unitIdx = info->blkUnits;
|
||||
for (uint16_t i = 0; i < info->blkGroupNum; ++i) {
|
||||
qDebug("Group[%d] UnitNum: %d:", i, *unitIdx);
|
||||
uint16_t unitNum = *(unitIdx++);
|
||||
for (uint16_t m = 0; m < unitNum; ++m) {
|
||||
qDebug("uidx[%d]", *(unitIdx++));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1674,7 +1718,9 @@ void filterFreeInfo(SFilterInfo *info) {
|
|||
CHK_RETV(info == NULL);
|
||||
|
||||
tfree(info->cunits);
|
||||
|
||||
tfree(info->blkUnitRes);
|
||||
tfree(info->blkUnits);
|
||||
|
||||
for (int32_t i = 0; i < FLD_TYPE_MAX; ++i) {
|
||||
for (uint16_t f = 0; f < info->fields[i].num; ++f) {
|
||||
filterFreeField(&info->fields[i].fields[f], i);
|
||||
|
@ -2485,7 +2531,9 @@ int32_t filterGenerateComInfo(SFilterInfo *info) {
|
|||
uint16_t n = 0;
|
||||
|
||||
info->cunits = malloc(info->unitNum * sizeof(*info->cunits));
|
||||
|
||||
info->blkUnitRes = malloc(sizeof(*info->blkUnitRes) * info->unitNum);
|
||||
info->blkUnits = malloc(sizeof(*info->blkUnits) * (info->unitNum + 1) * info->groupNum);
|
||||
|
||||
for (uint16_t i = 0; i < info->unitNum; ++i) {
|
||||
SFilterUnit *unit = &info->units[i];
|
||||
|
||||
|
@ -2493,6 +2541,7 @@ int32_t filterGenerateComInfo(SFilterInfo *info) {
|
|||
info->cunits[i].rfunc = filterGetRangeCompFuncFromOptrs(unit->compare.optr, unit->compare.optr2);
|
||||
info->cunits[i].optr = FILTER_UNIT_OPTR(unit);
|
||||
info->cunits[i].colData = NULL;
|
||||
info->cunits[i].colId = FILTER_UNIT_COL_ID(info, unit);
|
||||
|
||||
if (unit->right.type == FLD_TYPE_VALUE) {
|
||||
info->cunits[i].valData = FILTER_UNIT_VAL_DATA(info, unit);
|
||||
|
@ -2541,36 +2590,317 @@ int32_t filterUpdateComUnits(SFilterInfo *info) {
|
|||
}
|
||||
|
||||
|
||||
static FORCE_INLINE bool filterExecuteImplAll(void *info, int32_t numOfRows, int8_t* p) {
|
||||
return true;
|
||||
int32_t filterRmUnitByRange(SFilterInfo *info, SDataStatis *pDataStatis, int32_t numOfCols, int32_t numOfRows) {
|
||||
int32_t rmUnit = 0;
|
||||
|
||||
memset(info->blkUnitRes, 0, sizeof(*info->blkUnitRes) * info->unitNum);
|
||||
|
||||
for (int32_t k = 0; k < info->unitNum; ++k) {
|
||||
int32_t index = -1;
|
||||
SFilterComUnit *cunit = &info->cunits[k];
|
||||
|
||||
if (FILTER_NO_MERGE_DATA_TYPE(cunit->dataType)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
for(int32_t i = 0; i < numOfCols; ++i) {
|
||||
if (pDataStatis[i].colId == cunit->colId) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (index == -1) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (pDataStatis[index].numOfNull <= 0) {
|
||||
if (cunit->optr == TSDB_RELATION_ISNULL) {
|
||||
info->blkUnitRes[k] = -1;
|
||||
rmUnit = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (cunit->optr == TSDB_RELATION_NOTNULL) {
|
||||
info->blkUnitRes[k] = 1;
|
||||
rmUnit = 1;
|
||||
continue;
|
||||
}
|
||||
} else {
|
||||
if (pDataStatis[index].numOfNull == numOfRows) {
|
||||
if (cunit->optr == TSDB_RELATION_ISNULL) {
|
||||
info->blkUnitRes[k] = 1;
|
||||
rmUnit = 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
info->blkUnitRes[k] = -1;
|
||||
rmUnit = 1;
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (cunit->optr == TSDB_RELATION_ISNULL || cunit->optr == TSDB_RELATION_NOTNULL
|
||||
|| cunit->optr == TSDB_RELATION_IN || cunit->optr == TSDB_RELATION_LIKE
|
||||
|| cunit->optr == TSDB_RELATION_NOT_EQUAL) {
|
||||
continue;
|
||||
}
|
||||
|
||||
SDataStatis* pDataBlockst = &pDataStatis[index];
|
||||
void *minVal, *maxVal;
|
||||
|
||||
if (cunit->dataType == TSDB_DATA_TYPE_FLOAT) {
|
||||
float minv = (float)(*(double *)(&pDataBlockst->min));
|
||||
float maxv = (float)(*(double *)(&pDataBlockst->max));
|
||||
|
||||
minVal = &minv;
|
||||
maxVal = &maxv;
|
||||
} else {
|
||||
minVal = &pDataBlockst->min;
|
||||
maxVal = &pDataBlockst->max;
|
||||
}
|
||||
|
||||
bool minRes = false, maxRes = false;
|
||||
|
||||
if (cunit->rfunc >= 0) {
|
||||
minRes = (*gRangeCompare[cunit->rfunc])(minVal, minVal, cunit->valData, cunit->valData2, gDataCompare[cunit->func]);
|
||||
maxRes = (*gRangeCompare[cunit->rfunc])(maxVal, maxVal, cunit->valData, cunit->valData2, gDataCompare[cunit->func]);
|
||||
|
||||
if (minRes && maxRes) {
|
||||
info->blkUnitRes[k] = 1;
|
||||
rmUnit = 1;
|
||||
} else if ((!minRes) && (!maxRes)) {
|
||||
minRes = filterDoCompare(gDataCompare[cunit->func], TSDB_RELATION_LESS_EQUAL, minVal, cunit->valData);
|
||||
maxRes = filterDoCompare(gDataCompare[cunit->func], TSDB_RELATION_GREATER_EQUAL, maxVal, cunit->valData2);
|
||||
|
||||
if (minRes && maxRes) {
|
||||
continue;
|
||||
}
|
||||
|
||||
info->blkUnitRes[k] = -1;
|
||||
rmUnit = 1;
|
||||
}
|
||||
} else {
|
||||
minRes = filterDoCompare(gDataCompare[cunit->func], cunit->optr, minVal, cunit->valData);
|
||||
maxRes = filterDoCompare(gDataCompare[cunit->func], cunit->optr, maxVal, cunit->valData);
|
||||
|
||||
if (minRes && maxRes) {
|
||||
info->blkUnitRes[k] = 1;
|
||||
rmUnit = 1;
|
||||
} else if ((!minRes) && (!maxRes)) {
|
||||
if (cunit->optr == TSDB_RELATION_EQUAL) {
|
||||
minRes = filterDoCompare(gDataCompare[cunit->func], TSDB_RELATION_GREATER, minVal, cunit->valData);
|
||||
maxRes = filterDoCompare(gDataCompare[cunit->func], TSDB_RELATION_LESS, maxVal, cunit->valData);
|
||||
if (minRes || maxRes) {
|
||||
info->blkUnitRes[k] = -1;
|
||||
rmUnit = 1;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
info->blkUnitRes[k] = -1;
|
||||
rmUnit = 1;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
CHK_LRET(rmUnit == 0, TSDB_CODE_SUCCESS, "NO Block Filter APPLY");
|
||||
|
||||
info->blkGroupNum = info->groupNum;
|
||||
|
||||
uint16_t *unitNum = info->blkUnits;
|
||||
uint16_t *unitIdx = unitNum + 1;
|
||||
int32_t all = 0, empty = 0;
|
||||
|
||||
for (uint32_t g = 0; g < info->groupNum; ++g) {
|
||||
SFilterGroup *group = &info->groups[g];
|
||||
*unitNum = group->unitNum;
|
||||
all = 0;
|
||||
empty = 0;
|
||||
|
||||
for (uint32_t u = 0; u < group->unitNum; ++u) {
|
||||
uint16_t uidx = group->unitIdxs[u];
|
||||
if (info->blkUnitRes[uidx] == 1) {
|
||||
--(*unitNum);
|
||||
all = 1;
|
||||
continue;
|
||||
} else if (info->blkUnitRes[uidx] == -1) {
|
||||
*unitNum = 0;
|
||||
empty = 1;
|
||||
break;
|
||||
}
|
||||
|
||||
*(unitIdx++) = uidx;
|
||||
}
|
||||
|
||||
if (*unitNum == 0) {
|
||||
--info->blkGroupNum;
|
||||
assert(empty || all);
|
||||
|
||||
if (empty) {
|
||||
FILTER_SET_FLAG(info->blkFlag, FI_STATUS_BLK_EMPTY);
|
||||
} else {
|
||||
FILTER_SET_FLAG(info->blkFlag, FI_STATUS_BLK_ALL);
|
||||
goto _return;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
unitNum = unitIdx;
|
||||
++unitIdx;
|
||||
}
|
||||
|
||||
if (info->blkGroupNum) {
|
||||
FILTER_CLR_FLAG(info->blkFlag, FI_STATUS_BLK_EMPTY);
|
||||
FILTER_SET_FLAG(info->blkFlag, FI_STATUS_BLK_ACTIVE);
|
||||
}
|
||||
|
||||
_return:
|
||||
|
||||
filterDumpInfoToString(info, "Block Filter", 2);
|
||||
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
static FORCE_INLINE bool filterExecuteImplEmpty(void *info, int32_t numOfRows, int8_t* p) {
|
||||
return false;
|
||||
}
|
||||
static FORCE_INLINE bool filterExecuteImplIsNull(void *pinfo, int32_t numOfRows, int8_t* p) {
|
||||
|
||||
bool filterExecuteBasedOnStatisImpl(void *pinfo, int32_t numOfRows, int8_t** p, SDataStatis *statis, int16_t numOfCols) {
|
||||
SFilterInfo *info = (SFilterInfo *)pinfo;
|
||||
bool all = true;
|
||||
|
||||
uint16_t *unitIdx = NULL;
|
||||
|
||||
*p = calloc(numOfRows, sizeof(int8_t));
|
||||
|
||||
for (int32_t i = 0; i < numOfRows; ++i) {
|
||||
uint16_t uidx = info->groups[0].unitIdxs[0];
|
||||
void *colData = (char *)info->cunits[uidx].colData + info->cunits[uidx].dataSize * i;
|
||||
p[i] = isNull(colData, info->cunits[uidx].dataType);
|
||||
if (p[i] == 0) {
|
||||
//FILTER_UNIT_CLR_F(info);
|
||||
|
||||
unitIdx = info->blkUnits;
|
||||
|
||||
for (uint32_t g = 0; g < info->blkGroupNum; ++g) {
|
||||
uint16_t unitNum = *(unitIdx++);
|
||||
for (uint32_t u = 0; u < unitNum; ++u) {
|
||||
SFilterComUnit *cunit = &info->cunits[*(unitIdx + u)];
|
||||
void *colData = (char *)cunit->colData + cunit->dataSize * i;
|
||||
|
||||
//if (FILTER_UNIT_GET_F(info, uidx)) {
|
||||
// p[i] = FILTER_UNIT_GET_R(info, uidx);
|
||||
//} else {
|
||||
uint8_t optr = cunit->optr;
|
||||
|
||||
if (isNull(colData, cunit->dataType)) {
|
||||
(*p)[i] = optr == TSDB_RELATION_ISNULL ? true : false;
|
||||
} else {
|
||||
if (optr == TSDB_RELATION_NOTNULL) {
|
||||
(*p)[i] = 1;
|
||||
} else if (optr == TSDB_RELATION_ISNULL) {
|
||||
(*p)[i] = 0;
|
||||
} else if (cunit->rfunc >= 0) {
|
||||
(*p)[i] = (*gRangeCompare[cunit->rfunc])(colData, colData, cunit->valData, cunit->valData2, gDataCompare[cunit->func]);
|
||||
} else {
|
||||
(*p)[i] = filterDoCompare(gDataCompare[cunit->func], cunit->optr, colData, cunit->valData);
|
||||
}
|
||||
|
||||
//FILTER_UNIT_SET_R(info, uidx, p[i]);
|
||||
//FILTER_UNIT_SET_F(info, uidx);
|
||||
}
|
||||
|
||||
if ((*p)[i] == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ((*p)[i]) {
|
||||
break;
|
||||
}
|
||||
|
||||
unitIdx += unitNum;
|
||||
}
|
||||
|
||||
if ((*p)[i] == 0) {
|
||||
all = false;
|
||||
}
|
||||
}
|
||||
|
||||
return all;
|
||||
}
|
||||
static FORCE_INLINE bool filterExecuteImplNotNull(void *pinfo, int32_t numOfRows, int8_t* p) {
|
||||
|
||||
|
||||
|
||||
int32_t filterExecuteBasedOnStatis(SFilterInfo *info, int32_t numOfRows, int8_t** p, SDataStatis *statis, int16_t numOfCols, bool* all) {
|
||||
if (statis && numOfRows >= FILTER_RM_UNIT_MIN_ROWS) {
|
||||
info->blkFlag = 0;
|
||||
|
||||
filterRmUnitByRange(info, statis, numOfCols, numOfRows);
|
||||
|
||||
if (info->blkFlag) {
|
||||
if (FILTER_GET_FLAG(info->blkFlag, FI_STATUS_BLK_ALL)) {
|
||||
*all = true;
|
||||
goto _return;
|
||||
} else if (FILTER_GET_FLAG(info->blkFlag, FI_STATUS_BLK_EMPTY)) {
|
||||
*all = false;
|
||||
goto _return;
|
||||
}
|
||||
|
||||
assert(info->unitNum > 1);
|
||||
|
||||
*all = filterExecuteBasedOnStatisImpl(info, numOfRows, p, statis, numOfCols);
|
||||
|
||||
goto _return;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
_return:
|
||||
info->blkFlag = 0;
|
||||
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static FORCE_INLINE bool filterExecuteImplAll(void *info, int32_t numOfRows, int8_t** p, SDataStatis *statis, int16_t numOfCols) {
|
||||
return true;
|
||||
}
|
||||
static FORCE_INLINE bool filterExecuteImplEmpty(void *info, int32_t numOfRows, int8_t** p, SDataStatis *statis, int16_t numOfCols) {
|
||||
return false;
|
||||
}
|
||||
static FORCE_INLINE bool filterExecuteImplIsNull(void *pinfo, int32_t numOfRows, int8_t** p, SDataStatis *statis, int16_t numOfCols) {
|
||||
SFilterInfo *info = (SFilterInfo *)pinfo;
|
||||
bool all = true;
|
||||
|
||||
if (filterExecuteBasedOnStatis(info, numOfRows, p, statis, numOfCols, &all) == 0) {
|
||||
return all;
|
||||
}
|
||||
|
||||
*p = calloc(numOfRows, sizeof(int8_t));
|
||||
|
||||
for (int32_t i = 0; i < numOfRows; ++i) {
|
||||
uint16_t uidx = info->groups[0].unitIdxs[0];
|
||||
void *colData = (char *)info->cunits[uidx].colData + info->cunits[uidx].dataSize * i;
|
||||
p[i] = !isNull(colData, info->cunits[uidx].dataType);
|
||||
if (p[i] == 0) {
|
||||
(*p)[i] = isNull(colData, info->cunits[uidx].dataType);
|
||||
if ((*p)[i] == 0) {
|
||||
all = false;
|
||||
}
|
||||
}
|
||||
|
||||
return all;
|
||||
}
|
||||
static FORCE_INLINE bool filterExecuteImplNotNull(void *pinfo, int32_t numOfRows, int8_t** p, SDataStatis *statis, int16_t numOfCols) {
|
||||
SFilterInfo *info = (SFilterInfo *)pinfo;
|
||||
bool all = true;
|
||||
|
||||
if (filterExecuteBasedOnStatis(info, numOfRows, p, statis, numOfCols, &all) == 0) {
|
||||
return all;
|
||||
}
|
||||
|
||||
*p = calloc(numOfRows, sizeof(int8_t));
|
||||
|
||||
for (int32_t i = 0; i < numOfRows; ++i) {
|
||||
uint16_t uidx = info->groups[0].unitIdxs[0];
|
||||
void *colData = (char *)info->cunits[uidx].colData + info->cunits[uidx].dataSize * i;
|
||||
(*p)[i] = !isNull(colData, info->cunits[uidx].dataType);
|
||||
if ((*p)[i] == 0) {
|
||||
all = false;
|
||||
}
|
||||
}
|
||||
|
@ -2578,7 +2908,7 @@ static FORCE_INLINE bool filterExecuteImplNotNull(void *pinfo, int32_t numOfRows
|
|||
return all;
|
||||
}
|
||||
|
||||
bool filterExecuteImplRange(void *pinfo, int32_t numOfRows, int8_t* p) {
|
||||
bool filterExecuteImplRange(void *pinfo, int32_t numOfRows, int8_t** p, SDataStatis *statis, int16_t numOfCols) {
|
||||
SFilterInfo *info = (SFilterInfo *)pinfo;
|
||||
bool all = true;
|
||||
uint16_t dataSize = info->cunits[0].dataSize;
|
||||
|
@ -2587,6 +2917,12 @@ bool filterExecuteImplRange(void *pinfo, int32_t numOfRows, int8_t* p) {
|
|||
void *valData = info->cunits[0].valData;
|
||||
void *valData2 = info->cunits[0].valData2;
|
||||
__compar_fn_t func = gDataCompare[info->cunits[0].func];
|
||||
|
||||
if (filterExecuteBasedOnStatis(info, numOfRows, p, statis, numOfCols, &all) == 0) {
|
||||
return all;
|
||||
}
|
||||
|
||||
*p = calloc(numOfRows, sizeof(int8_t));
|
||||
|
||||
for (int32_t i = 0; i < numOfRows; ++i) {
|
||||
if (isNull(colData, info->cunits[0].dataType)) {
|
||||
|
@ -2595,9 +2931,9 @@ bool filterExecuteImplRange(void *pinfo, int32_t numOfRows, int8_t* p) {
|
|||
continue;
|
||||
}
|
||||
|
||||
p[i] = (*rfunc)(colData, colData, valData, valData2, func);
|
||||
(*p)[i] = (*rfunc)(colData, colData, valData, valData2, func);
|
||||
|
||||
if (p[i] == 0) {
|
||||
if ((*p)[i] == 0) {
|
||||
all = false;
|
||||
}
|
||||
|
||||
|
@ -2607,9 +2943,15 @@ bool filterExecuteImplRange(void *pinfo, int32_t numOfRows, int8_t* p) {
|
|||
return all;
|
||||
}
|
||||
|
||||
bool filterExecuteImplMisc(void *pinfo, int32_t numOfRows, int8_t* p) {
|
||||
bool filterExecuteImplMisc(void *pinfo, int32_t numOfRows, int8_t** p, SDataStatis *statis, int16_t numOfCols) {
|
||||
SFilterInfo *info = (SFilterInfo *)pinfo;
|
||||
bool all = true;
|
||||
|
||||
if (filterExecuteBasedOnStatis(info, numOfRows, p, statis, numOfCols, &all) == 0) {
|
||||
return all;
|
||||
}
|
||||
|
||||
*p = calloc(numOfRows, sizeof(int8_t));
|
||||
|
||||
for (int32_t i = 0; i < numOfRows; ++i) {
|
||||
uint16_t uidx = info->groups[0].unitIdxs[0];
|
||||
|
@ -2619,9 +2961,9 @@ bool filterExecuteImplMisc(void *pinfo, int32_t numOfRows, int8_t* p) {
|
|||
continue;
|
||||
}
|
||||
|
||||
p[i] = filterDoCompare(gDataCompare[info->cunits[uidx].func], info->cunits[uidx].optr, colData, info->cunits[uidx].valData);
|
||||
(*p)[i] = filterDoCompare(gDataCompare[info->cunits[uidx].func], info->cunits[uidx].optr, colData, info->cunits[uidx].valData);
|
||||
|
||||
if (p[i] == 0) {
|
||||
if ((*p)[i] == 0) {
|
||||
all = false;
|
||||
}
|
||||
}
|
||||
|
@ -2630,10 +2972,16 @@ bool filterExecuteImplMisc(void *pinfo, int32_t numOfRows, int8_t* p) {
|
|||
}
|
||||
|
||||
|
||||
bool filterExecuteImpl(void *pinfo, int32_t numOfRows, int8_t* p) {
|
||||
bool filterExecuteImpl(void *pinfo, int32_t numOfRows, int8_t** p, SDataStatis *statis, int16_t numOfCols) {
|
||||
SFilterInfo *info = (SFilterInfo *)pinfo;
|
||||
bool all = true;
|
||||
|
||||
if (filterExecuteBasedOnStatis(info, numOfRows, p, statis, numOfCols, &all) == 0) {
|
||||
return all;
|
||||
}
|
||||
|
||||
*p = calloc(numOfRows, sizeof(int8_t));
|
||||
|
||||
for (int32_t i = 0; i < numOfRows; ++i) {
|
||||
//FILTER_UNIT_CLR_F(info);
|
||||
|
||||
|
@ -2650,33 +2998,33 @@ bool filterExecuteImpl(void *pinfo, int32_t numOfRows, int8_t* p) {
|
|||
uint8_t optr = cunit->optr;
|
||||
|
||||
if (isNull(colData, cunit->dataType)) {
|
||||
p[i] = optr == TSDB_RELATION_ISNULL ? true : false;
|
||||
(*p)[i] = optr == TSDB_RELATION_ISNULL ? true : false;
|
||||
} else {
|
||||
if (optr == TSDB_RELATION_NOTNULL) {
|
||||
p[i] = 1;
|
||||
(*p)[i] = 1;
|
||||
} else if (optr == TSDB_RELATION_ISNULL) {
|
||||
p[i] = 0;
|
||||
(*p)[i] = 0;
|
||||
} else if (cunit->rfunc >= 0) {
|
||||
p[i] = (*gRangeCompare[cunit->rfunc])(colData, colData, cunit->valData, cunit->valData2, gDataCompare[cunit->func]);
|
||||
(*p)[i] = (*gRangeCompare[cunit->rfunc])(colData, colData, cunit->valData, cunit->valData2, gDataCompare[cunit->func]);
|
||||
} else {
|
||||
p[i] = filterDoCompare(gDataCompare[cunit->func], cunit->optr, colData, cunit->valData);
|
||||
(*p)[i] = filterDoCompare(gDataCompare[cunit->func], cunit->optr, colData, cunit->valData);
|
||||
}
|
||||
|
||||
//FILTER_UNIT_SET_R(info, uidx, p[i]);
|
||||
//FILTER_UNIT_SET_F(info, uidx);
|
||||
}
|
||||
|
||||
if (p[i] == 0) {
|
||||
if ((*p)[i] == 0) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (p[i]) {
|
||||
if ((*p)[i]) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (p[i] == 0) {
|
||||
if ((*p)[i] == 0) {
|
||||
all = false;
|
||||
}
|
||||
}
|
||||
|
@ -2684,8 +3032,9 @@ bool filterExecuteImpl(void *pinfo, int32_t numOfRows, int8_t* p) {
|
|||
return all;
|
||||
}
|
||||
|
||||
FORCE_INLINE bool filterExecute(SFilterInfo *info, int32_t numOfRows, int8_t* p) {
|
||||
return (*info->func)(info, numOfRows, p);
|
||||
|
||||
FORCE_INLINE bool filterExecute(SFilterInfo *info, int32_t numOfRows, int8_t** p, SDataStatis *statis, int16_t numOfCols) {
|
||||
return (*info->func)(info, numOfRows, p, statis, numOfCols);
|
||||
}
|
||||
|
||||
int32_t filterSetExecFunc(SFilterInfo *info) {
|
||||
|
@ -2767,7 +3116,7 @@ _return:
|
|||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
int32_t filterSetColFieldData(SFilterInfo *info, int16_t colId, void *data) {
|
||||
int32_t filterSetColFieldData(SFilterInfo *info, int32_t numOfCols, SArray* pDataBlock) {
|
||||
CHK_LRET(info == NULL, TSDB_CODE_QRY_APP_ERROR, "info NULL");
|
||||
CHK_LRET(info->fields[FLD_TYPE_COLUMN].num <= 0, TSDB_CODE_QRY_APP_ERROR, "no column fileds");
|
||||
|
||||
|
@ -2778,10 +3127,14 @@ int32_t filterSetColFieldData(SFilterInfo *info, int16_t colId, void *data) {
|
|||
for (uint16_t i = 0; i < info->fields[FLD_TYPE_COLUMN].num; ++i) {
|
||||
SFilterField* fi = &info->fields[FLD_TYPE_COLUMN].fields[i];
|
||||
SSchema* sch = fi->desc;
|
||||
if (sch->colId == colId) {
|
||||
fi->data = data;
|
||||
|
||||
break;
|
||||
|
||||
for (int32_t j = 0; j < numOfCols; ++j) {
|
||||
SColumnInfoData* pColInfo = taosArrayGet(pDataBlock, j);
|
||||
if (sch->colId == pColInfo->info.colId) {
|
||||
fi->data = pColInfo->pData;
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2880,16 +3233,17 @@ bool filterRangeExecute(SFilterInfo *info, SDataStatis *pDataStatis, int32_t num
|
|||
|
||||
// no statistics data, load the true data block
|
||||
if (index == -1) {
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
// not support pre-filter operation on binary/nchar data type
|
||||
if (FILTER_NO_MERGE_DATA_TYPE(ctx->type)) {
|
||||
return true;
|
||||
break;
|
||||
}
|
||||
|
||||
if ((pDataStatis[index].numOfNull <= 0) && (ctx->isnull && !ctx->notnull && !ctx->isrange)) {
|
||||
return false;
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
|
||||
// all data in current column are NULL, no need to check its boundary value
|
||||
|
@ -2897,7 +3251,8 @@ bool filterRangeExecute(SFilterInfo *info, SDataStatis *pDataStatis, int32_t num
|
|||
|
||||
// if isNULL query exists, load the null data column
|
||||
if ((ctx->notnull || ctx->isrange) && (!ctx->isnull)) {
|
||||
return false;
|
||||
ret = false;
|
||||
break;
|
||||
}
|
||||
|
||||
continue;
|
||||
|
|
|
@ -237,7 +237,7 @@ tMemBucket *tMemBucketCreate(int16_t nElemSize, int16_t dataType, double minval,
|
|||
}
|
||||
|
||||
pBucket->elemPerPage = (pBucket->bufPageSize - sizeof(tFilePage))/pBucket->bytes;
|
||||
pBucket->comparFn = getKeyComparFunc(pBucket->type);
|
||||
pBucket->comparFn = getKeyComparFunc(pBucket->type, TSDB_ORDER_ASC);
|
||||
|
||||
pBucket->hashFunc = getHashFunc(pBucket->type);
|
||||
if (pBucket->hashFunc == NULL) {
|
||||
|
|
|
@ -557,20 +557,27 @@ SArray* createExecOperatorPlan(SQueryAttr* pQueryAttr) {
|
|||
int32_t op = 0;
|
||||
|
||||
if (onlyQueryTags(pQueryAttr)) { // do nothing for tags query
|
||||
if (onlyQueryTags(pQueryAttr)) {
|
||||
op = OP_TagScan;
|
||||
taosArrayPush(plan, &op);
|
||||
}
|
||||
op = OP_TagScan;
|
||||
taosArrayPush(plan, &op);
|
||||
|
||||
if (pQueryAttr->distinct) {
|
||||
op = OP_Distinct;
|
||||
taosArrayPush(plan, &op);
|
||||
}
|
||||
} else if (pQueryAttr->interval.interval > 0) {
|
||||
if (pQueryAttr->stableQuery) {
|
||||
op = OP_MultiTableTimeInterval;
|
||||
if (pQueryAttr->pointInterpQuery) {
|
||||
op = OP_AllMultiTableTimeInterval;
|
||||
} else {
|
||||
op = OP_MultiTableTimeInterval;
|
||||
}
|
||||
taosArrayPush(plan, &op);
|
||||
} else {
|
||||
op = OP_TimeWindow;
|
||||
} else {
|
||||
if (pQueryAttr->pointInterpQuery) {
|
||||
op = OP_AllTimeWindow;
|
||||
} else {
|
||||
op = OP_TimeWindow;
|
||||
}
|
||||
taosArrayPush(plan, &op);
|
||||
|
||||
if (pQueryAttr->pExpr2 != NULL) {
|
||||
|
@ -578,7 +585,7 @@ SArray* createExecOperatorPlan(SQueryAttr* pQueryAttr) {
|
|||
taosArrayPush(plan, &op);
|
||||
}
|
||||
|
||||
if (pQueryAttr->fillType != TSDB_FILL_NONE && (!pQueryAttr->pointInterpQuery)) {
|
||||
if (pQueryAttr->fillType != TSDB_FILL_NONE) {
|
||||
op = OP_Fill;
|
||||
taosArrayPush(plan, &op);
|
||||
}
|
||||
|
@ -643,8 +650,14 @@ SArray* createExecOperatorPlan(SQueryAttr* pQueryAttr) {
|
|||
taosArrayPush(plan, &op);
|
||||
}
|
||||
}
|
||||
|
||||
// outer query order by support
|
||||
int32_t orderColId = pQueryAttr->order.orderColId;
|
||||
if (pQueryAttr->vgId == 0 && orderColId != PRIMARYKEY_TIMESTAMP_COL_INDEX && orderColId != INT32_MIN) {
|
||||
op = OP_Order;
|
||||
taosArrayPush(plan, &op);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (pQueryAttr->limit.limit > 0 || pQueryAttr->limit.offset > 0) {
|
||||
op = OP_Limit;
|
||||
|
|
|
@ -30,6 +30,18 @@ typedef struct SCompSupporter {
|
|||
int32_t order;
|
||||
} SCompSupporter;
|
||||
|
||||
int32_t getRowNumForMultioutput(SQueryAttr* pQueryAttr, bool topBottomQuery, bool stable) {
|
||||
if (pQueryAttr && (!stable)) {
|
||||
for (int16_t i = 0; i < pQueryAttr->numOfOutput; ++i) {
|
||||
if (pQueryAttr->pExpr1[i].base.functionId == TSDB_FUNC_TOP || pQueryAttr->pExpr1[i].base.functionId == TSDB_FUNC_BOTTOM) {
|
||||
return (int32_t)pQueryAttr->pExpr1[i].base.param[0].i64;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int32_t getOutputInterResultBufSize(SQueryAttr* pQueryAttr) {
|
||||
int32_t size = 0;
|
||||
|
||||
|
|
|
@ -215,7 +215,6 @@ int32_t qCreateQueryInfo(void* tsdb, int32_t vgId, SQueryTableMsg* pQueryMsg, qi
|
|||
return code;
|
||||
}
|
||||
|
||||
|
||||
bool qTableQuery(qinfo_t qinfo, uint64_t *qId) {
|
||||
SQInfo *pQInfo = (SQInfo *)qinfo;
|
||||
assert(pQInfo && pQInfo->signature == pQInfo);
|
||||
|
@ -256,7 +255,11 @@ bool qTableQuery(qinfo_t qinfo, uint64_t *qId) {
|
|||
|
||||
bool newgroup = false;
|
||||
publishOperatorProfEvent(pRuntimeEnv->proot, QUERY_PROF_BEFORE_OPERATOR_EXEC);
|
||||
|
||||
int64_t st = taosGetTimestampUs();
|
||||
pRuntimeEnv->outputBuf = pRuntimeEnv->proot->exec(pRuntimeEnv->proot, &newgroup);
|
||||
pQInfo->summary.elapsedTime += (taosGetTimestampUs() - st);
|
||||
|
||||
publishOperatorProfEvent(pRuntimeEnv->proot, QUERY_PROF_AFTER_OPERATOR_EXEC);
|
||||
pRuntimeEnv->resultInfo.total += GET_NUM_OF_RESULTS(pRuntimeEnv);
|
||||
|
||||
|
@ -321,6 +324,7 @@ int32_t qRetrieveQueryResultInfo(qinfo_t qinfo, bool* buildRes, void* pRspContex
|
|||
|
||||
int32_t qDumpRetrieveResult(qinfo_t qinfo, SRetrieveTableRsp **pRsp, int32_t *contLen, bool* continueExec) {
|
||||
SQInfo *pQInfo = (SQInfo *)qinfo;
|
||||
int32_t compLen = 0;
|
||||
|
||||
if (pQInfo == NULL || !isValidQInfo(pQInfo)) {
|
||||
return TSDB_CODE_QRY_INVALID_QHANDLE;
|
||||
|
@ -353,12 +357,21 @@ int32_t qDumpRetrieveResult(qinfo_t qinfo, SRetrieveTableRsp **pRsp, int32_t *co
|
|||
}
|
||||
|
||||
(*pRsp)->precision = htons(pQueryAttr->precision);
|
||||
(*pRsp)->compressed = (int8_t)(tsCompressColData && checkNeedToCompressQueryCol(pQInfo));
|
||||
|
||||
if (GET_NUM_OF_RESULTS(&(pQInfo->runtimeEnv)) > 0 && pQInfo->code == TSDB_CODE_SUCCESS) {
|
||||
doDumpQueryResult(pQInfo, (*pRsp)->data);
|
||||
doDumpQueryResult(pQInfo, (*pRsp)->data, (*pRsp)->compressed, &compLen);
|
||||
} else {
|
||||
setQueryStatus(pRuntimeEnv, QUERY_OVER);
|
||||
}
|
||||
|
||||
if ((*pRsp)->compressed && compLen != 0) {
|
||||
int32_t numOfCols = pQueryAttr->pExpr2 ? pQueryAttr->numOfExpr2 : pQueryAttr->numOfOutput;
|
||||
*contLen = *contLen - pQueryAttr->resultRowSize * s + compLen + numOfCols * sizeof(int32_t);
|
||||
*pRsp = (SRetrieveTableRsp *)rpcReallocCont(*pRsp, *contLen);
|
||||
}
|
||||
(*pRsp)->compLen = htonl(compLen);
|
||||
|
||||
pQInfo->rspContext = NULL;
|
||||
pQInfo->dataReady = QUERY_RESULT_NOT_READY;
|
||||
|
||||
|
|
|
@ -0,0 +1,124 @@
|
|||
#include <gtest/gtest.h>
|
||||
#include <iostream>
|
||||
|
||||
#include "taos.h"
|
||||
#include "tsdb.h"
|
||||
#include "qExtbuffer.h"
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wwrite-strings"
|
||||
#pragma GCC diagnostic ignored "-Wunused-function"
|
||||
#pragma GCC diagnostic ignored "-Wunused-variable"
|
||||
#pragma GCC diagnostic ignored "-Wsign-compare"
|
||||
|
||||
namespace {
|
||||
int32_t comp(const void* p1, const void* p2) {
|
||||
int32_t* x1 = (int32_t*) p1;
|
||||
int32_t* x2 = (int32_t*) p2;
|
||||
|
||||
if (*x1 == *x2) {
|
||||
return 0;
|
||||
} else {
|
||||
return (*x1 > *x2)? 1:-1;
|
||||
}
|
||||
}
|
||||
|
||||
int32_t comp1(const void* p1, const void* p2) {
|
||||
int32_t ret = strncmp((char*) p1, (char*) p2, 20);
|
||||
|
||||
if (ret == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
return ret > 0 ? 1:-1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
TEST(testCase, colunmnwise_sort_test) {
|
||||
// void taoscQSort(void** pCols, SSchema* pSchema, int32_t numOfCols, int32_t numOfRows, int32_t index, __compar_fn_t compareFn)
|
||||
void* pCols[2] = {0};
|
||||
|
||||
SSchema s[2] = {{0}};
|
||||
s[0].type = TSDB_DATA_TYPE_INT;
|
||||
s[0].bytes = 4;
|
||||
s[0].colId = 0;
|
||||
strcpy(s[0].name, "col1");
|
||||
|
||||
s[1].type = TSDB_DATA_TYPE_BINARY;
|
||||
s[1].bytes = 20;
|
||||
s[1].colId = 1;
|
||||
strcpy(s[1].name, "col2");
|
||||
|
||||
int32_t* p = (int32_t*) calloc(5, sizeof(int32_t));
|
||||
p[0] = 12;
|
||||
p[1] = 8;
|
||||
p[2] = 99;
|
||||
p[3] = 7;
|
||||
p[4] = 1;
|
||||
|
||||
char* t1 = (char*) calloc(5, 20);
|
||||
strcpy(t1, "abc");
|
||||
strcpy(t1 + 20, "def");
|
||||
strcpy(t1 + 40, "xyz");
|
||||
strcpy(t1 + 60, "klm");
|
||||
strcpy(t1 + 80, "hij");
|
||||
|
||||
pCols[0] = (char*) p;
|
||||
pCols[1] = (char*) t1;
|
||||
taoscQSort(reinterpret_cast<void**>(pCols), s, 2, 5, 0, comp);
|
||||
|
||||
int32_t* px = (int32_t*) pCols[0];
|
||||
ASSERT_EQ(px[0], 1);
|
||||
ASSERT_EQ(px[1], 7);
|
||||
ASSERT_EQ(px[2], 8);
|
||||
ASSERT_EQ(px[3], 12);
|
||||
ASSERT_EQ(px[4], 99);
|
||||
|
||||
char* px1 = (char*) pCols[1];
|
||||
ASSERT_STRCASEEQ(px1 + 20 * 0, "hij");
|
||||
ASSERT_STRCASEEQ(px1 + 20 * 1, "klm");
|
||||
ASSERT_STRCASEEQ(px1 + 20 * 2, "def");
|
||||
ASSERT_STRCASEEQ(px1 + 20 * 3, "abc");
|
||||
ASSERT_STRCASEEQ(px1 + 20 * 4, "xyz");
|
||||
|
||||
taoscQSort(pCols, s, 2, 5, 1, comp1);
|
||||
px = (int32_t*) pCols[0];
|
||||
ASSERT_EQ(px[0], 12);
|
||||
ASSERT_EQ(px[1], 8);
|
||||
ASSERT_EQ(px[2], 1);
|
||||
ASSERT_EQ(px[3], 7);
|
||||
ASSERT_EQ(px[4], 99);
|
||||
|
||||
px1 = (char*) pCols[1];
|
||||
ASSERT_STRCASEEQ(px1 + 20 * 0, "abc");
|
||||
ASSERT_STRCASEEQ(px1 + 20 * 1, "def");
|
||||
ASSERT_STRCASEEQ(px1 + 20 * 2, "hij");
|
||||
ASSERT_STRCASEEQ(px1 + 20 * 3, "klm");
|
||||
ASSERT_STRCASEEQ(px1 + 20 * 4, "xyz");
|
||||
}
|
||||
|
||||
TEST(testCase, columnsort_test) {
|
||||
SSchema field[1] = {
|
||||
{TSDB_DATA_TYPE_INT, "k", sizeof(int32_t)},
|
||||
};
|
||||
|
||||
const int32_t num = 2000;
|
||||
|
||||
int32_t *d = (int32_t *)malloc(sizeof(int32_t) * num);
|
||||
for (int32_t i = 0; i < num; ++i) {
|
||||
d[i] = i % 4;
|
||||
}
|
||||
|
||||
const int32_t numOfOrderCols = 1;
|
||||
int32_t orderColIdx = 0;
|
||||
SColumnModel *pModel = createColumnModel(field, 1, 1000);
|
||||
tOrderDescriptor *pDesc = tOrderDesCreate(&orderColIdx, numOfOrderCols, pModel, 1);
|
||||
|
||||
tColDataQSort(pDesc, num, 0, num - 1, (char *)d, 1);
|
||||
|
||||
for (int32_t i = 0; i < num; ++i) {
|
||||
printf("%d\t", d[i]);
|
||||
}
|
||||
printf("\n");
|
||||
|
||||
destroyColumnModel(pModel);
|
||||
}
|
|
@ -1,6 +1,4 @@
|
|||
#include "os.h"
|
||||
#include <gtest/gtest.h>
|
||||
#include <cassert>
|
||||
#include <iostream>
|
||||
|
||||
#include "taos.h"
|
||||
|
|
|
@ -1133,8 +1133,8 @@ static void rpcNotifyClient(SRpcReqContext *pContext, SRpcMsg *pMsg) {
|
|||
} else {
|
||||
// for asynchronous API
|
||||
SRpcEpSet *pEpSet = NULL;
|
||||
//if (pContext->epSet.inUse != pContext->oldInUse || pContext->redirect)
|
||||
pEpSet = &pContext->epSet;
|
||||
if (pContext->epSet.inUse != pContext->oldInUse || pContext->redirect)
|
||||
pEpSet = &pContext->epSet;
|
||||
|
||||
(*pRpc->cfp)(pMsg, pEpSet);
|
||||
}
|
||||
|
|
|
@ -397,7 +397,11 @@ void *taosOpenTcpClientConnection(void *shandle, void *thandle, uint32_t ip, uin
|
|||
SThreadObj *pThreadObj = pClientObj->pThreadObj[index];
|
||||
|
||||
SOCKET fd = taosOpenTcpClientSocket(ip, port, pThreadObj->ip);
|
||||
#if defined(_TD_WINDOWS_64) || defined(_TD_WINDOWS_32)
|
||||
if (fd == (SOCKET)-1) return NULL;
|
||||
#else
|
||||
if (fd <= 0) return NULL;
|
||||
#endif
|
||||
|
||||
struct sockaddr_in sin;
|
||||
uint16_t localPort = 0;
|
||||
|
|
|
@ -65,12 +65,7 @@ SDisk *tfsFreeDisk(SDisk *pDisk);
|
|||
int tfsUpdateDiskInfo(SDisk *pDisk);
|
||||
|
||||
// ttier.c ======================================================
|
||||
typedef struct {
|
||||
int64_t size;
|
||||
int64_t used;
|
||||
int64_t free;
|
||||
int16_t nAvailDisks; // # of Available disks
|
||||
} STierMeta;
|
||||
|
||||
typedef struct STier {
|
||||
pthread_spinlock_t lock;
|
||||
int level;
|
||||
|
|
|
@ -101,7 +101,7 @@ int tfsInit(SDiskCfg *pDiskCfg, int ndisk) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
tfsUpdateInfo(NULL);
|
||||
tfsUpdateInfo(NULL, NULL, 0);
|
||||
for (int level = 0; level < TFS_NLEVEL(); level++) {
|
||||
tfsPosNextId(TFS_TIER_AT(level));
|
||||
}
|
||||
|
@ -119,7 +119,7 @@ void tfsDestroy() {
|
|||
}
|
||||
}
|
||||
|
||||
void tfsUpdateInfo(SFSMeta *pFSMeta) {
|
||||
void tfsUpdateInfo(SFSMeta *pFSMeta, STierMeta *tierMetas, int8_t numTiers) {
|
||||
SFSMeta fsMeta;
|
||||
STierMeta tierMeta;
|
||||
|
||||
|
@ -130,11 +130,16 @@ void tfsUpdateInfo(SFSMeta *pFSMeta) {
|
|||
memset(pFSMeta, 0, sizeof(*pFSMeta));
|
||||
|
||||
for (int level = 0; level < TFS_NLEVEL(); level++) {
|
||||
STierMeta *pTierMeta = &tierMeta;
|
||||
if (tierMetas && level < numTiers) {
|
||||
pTierMeta = tierMetas + level;
|
||||
}
|
||||
|
||||
STier *pTier = TFS_TIER_AT(level);
|
||||
tfsUpdateTierInfo(pTier, &tierMeta);
|
||||
pFSMeta->tsize += tierMeta.size;
|
||||
pFSMeta->avail += tierMeta.free;
|
||||
pFSMeta->used += tierMeta.used;
|
||||
tfsUpdateTierInfo(pTier, pTierMeta);
|
||||
pFSMeta->tsize += pTierMeta->size;
|
||||
pFSMeta->avail += pTierMeta->free;
|
||||
pFSMeta->used += pTierMeta->used;
|
||||
}
|
||||
|
||||
tfsLock();
|
||||
|
@ -595,7 +600,7 @@ void taosGetDisk() {
|
|||
SFSMeta fsMeta;
|
||||
|
||||
if (tscEmbedded) {
|
||||
tfsUpdateInfo(&fsMeta);
|
||||
tfsUpdateInfo(&fsMeta, NULL, 0);
|
||||
tsTotalDataDirGB = (float)(fsMeta.tsize / unit);
|
||||
tsUsedDataDirGB = (float)(fsMeta.used / unit);
|
||||
tsAvailDataDirGB = (float)(fsMeta.avail / unit);
|
||||
|
|
|
@ -24,8 +24,7 @@ typedef struct STable {
|
|||
tstr* name; // NOTE: there a flexible string here
|
||||
uint64_t suid;
|
||||
struct STable* pSuper; // super table pointer
|
||||
uint8_t numOfSchemas;
|
||||
STSchema* schema[TSDB_MAX_TABLE_SCHEMAS];
|
||||
SArray* schema;
|
||||
STSchema* tagSchema;
|
||||
SKVRow tagVal;
|
||||
SSkipList* pIndex; // For TSDB_SUPER_TABLE, it is the skiplist index
|
||||
|
@ -107,10 +106,9 @@ static FORCE_INLINE STSchema* tsdbGetTableSchemaImpl(STable* pTable, bool lock,
|
|||
|
||||
if (lock) TSDB_RLOCK_TABLE(pDTable);
|
||||
if (_version < 0) { // get the latest version of schema
|
||||
pTSchema = pDTable->schema[pDTable->numOfSchemas - 1];
|
||||
pTSchema = *(STSchema **)taosArrayGetLast(pDTable->schema);
|
||||
} else { // get the schema with version
|
||||
void* ptr = taosbsearch(&_version, pDTable->schema, pDTable->numOfSchemas, sizeof(STSchema*),
|
||||
tsdbCompareSchemaVersion, TD_EQ);
|
||||
void* ptr = taosArraySearch(pDTable->schema, &_version, tsdbCompareSchemaVersion, TD_EQ);
|
||||
if (ptr == NULL) {
|
||||
terrno = TSDB_CODE_TDB_IVD_TB_SCHEMA_VERSION;
|
||||
goto _exit;
|
||||
|
|
|
@ -1048,6 +1048,26 @@ static int tsdbRestoreMeta(STsdbRepo *pRepo) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (tsdbForceKeepFile) {
|
||||
struct stat tfstat;
|
||||
|
||||
// Get real file size
|
||||
if (fstat(pfs->cstatus->pmf->fd, &tfstat) < 0) {
|
||||
terrno = TAOS_SYSTEM_ERROR(errno);
|
||||
tsdbCloseMFile(pfs->cstatus->pmf);
|
||||
tfsClosedir(tdir);
|
||||
regfree(®ex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pfs->cstatus->pmf->info.size != tfstat.st_size) {
|
||||
int64_t tfsize = pfs->cstatus->pmf->info.size;
|
||||
pfs->cstatus->pmf->info.size = tfstat.st_size;
|
||||
tsdbInfo("vgId:%d file %s header size is changed from %" PRId64 " to %" PRId64, REPO_ID(pRepo),
|
||||
TSDB_FILE_FULL_NAME(pfs->cstatus->pmf), tfsize, pfs->cstatus->pmf->info.size);
|
||||
}
|
||||
}
|
||||
|
||||
tsdbCloseMFile(pfs->cstatus->pmf);
|
||||
}
|
||||
} else if (code == REG_NOMATCH) {
|
||||
|
@ -1212,6 +1232,24 @@ static int tsdbRestoreDFileSet(STsdbRepo *pRepo) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
if (tsdbForceKeepFile) {
|
||||
struct stat tfstat;
|
||||
|
||||
// Get real file size
|
||||
if (fstat(pDFile->fd, &tfstat) < 0) {
|
||||
terrno = TAOS_SYSTEM_ERROR(errno);
|
||||
taosArrayDestroy(fArray);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (pDFile->info.size != tfstat.st_size) {
|
||||
int64_t tfsize = pDFile->info.size;
|
||||
pDFile->info.size = tfstat.st_size;
|
||||
tsdbInfo("vgId:%d file %s header size is changed from %" PRId64 " to %" PRId64, REPO_ID(pRepo),
|
||||
TSDB_FILE_FULL_NAME(pDFile), tfsize, pDFile->info.size);
|
||||
}
|
||||
}
|
||||
|
||||
tsdbCloseDFile(pDFile);
|
||||
index++;
|
||||
}
|
||||
|
@ -1314,4 +1352,4 @@ static void tsdbScanAndTryFixDFilesHeader(STsdbRepo *pRepo, int32_t *nExpired) {
|
|||
|
||||
tsdbCloseDFileSet(&fset);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -43,6 +43,8 @@ static int tsdbRemoveTableFromStore(STsdbRepo *pRepo, STable *pTable);
|
|||
static int tsdbRmTableFromMeta(STsdbRepo *pRepo, STable *pTable);
|
||||
static int tsdbAdjustMetaTables(STsdbRepo *pRepo, int tid);
|
||||
static int tsdbCheckTableTagVal(SKVRow *pKVRow, STSchema *pSchema);
|
||||
static int tsdbAddSchema(STable *pTable, STSchema *pSchema);
|
||||
static void tsdbFreeTableSchema(STable *pTable);
|
||||
|
||||
// ------------------ OUTER FUNCTIONS ------------------
|
||||
int tsdbCreateTable(STsdbRepo *repo, STableCfg *pCfg) {
|
||||
|
@ -722,17 +724,10 @@ void tsdbUpdateTableSchema(STsdbRepo *pRepo, STable *pTable, STSchema *pSchema,
|
|||
STsdbMeta *pMeta = pRepo->tsdbMeta;
|
||||
|
||||
STable *pCTable = (TABLE_TYPE(pTable) == TSDB_CHILD_TABLE) ? pTable->pSuper : pTable;
|
||||
ASSERT(schemaVersion(pSchema) > schemaVersion(pCTable->schema[pCTable->numOfSchemas - 1]));
|
||||
ASSERT(schemaVersion(pSchema) > schemaVersion(*(STSchema **)taosArrayGetLast(pCTable->schema)));
|
||||
|
||||
TSDB_WLOCK_TABLE(pCTable);
|
||||
if (pCTable->numOfSchemas < TSDB_MAX_TABLE_SCHEMAS) {
|
||||
pCTable->schema[pCTable->numOfSchemas++] = pSchema;
|
||||
} else {
|
||||
ASSERT(pCTable->numOfSchemas == TSDB_MAX_TABLE_SCHEMAS);
|
||||
tdFreeSchema(pCTable->schema[0]);
|
||||
memmove(pCTable->schema, pCTable->schema + 1, sizeof(STSchema *) * (TSDB_MAX_TABLE_SCHEMAS - 1));
|
||||
pCTable->schema[pCTable->numOfSchemas - 1] = pSchema;
|
||||
}
|
||||
tsdbAddSchema(pCTable, pSchema);
|
||||
|
||||
if (schemaNCols(pSchema) > pMeta->maxCols) pMeta->maxCols = schemaNCols(pSchema);
|
||||
if (schemaTLen(pSchema) > pMeta->maxRowBytes) pMeta->maxRowBytes = schemaTLen(pSchema);
|
||||
|
@ -828,9 +823,7 @@ static STable *tsdbCreateTableFromCfg(STableCfg *pCfg, bool isSuper, STable *pST
|
|||
TABLE_TID(pTable) = -1;
|
||||
TABLE_SUID(pTable) = -1;
|
||||
pTable->pSuper = NULL;
|
||||
pTable->numOfSchemas = 1;
|
||||
pTable->schema[0] = tdDupSchema(pCfg->schema);
|
||||
if (pTable->schema[0] == NULL) {
|
||||
if (tsdbAddSchema(pTable, tdDupSchema(pCfg->schema)) < 0) {
|
||||
terrno = TSDB_CODE_TDB_OUT_OF_MEMORY;
|
||||
goto _err;
|
||||
}
|
||||
|
@ -841,7 +834,8 @@ static STable *tsdbCreateTableFromCfg(STableCfg *pCfg, bool isSuper, STable *pST
|
|||
}
|
||||
pTable->tagVal = NULL;
|
||||
STColumn *pCol = schemaColAt(pTable->tagSchema, DEFAULT_TAG_INDEX_COLUMN);
|
||||
pTable->pIndex = tSkipListCreate(TSDB_SUPER_TABLE_SL_LEVEL, colType(pCol), (uint8_t)(colBytes(pCol)), NULL, SL_ALLOW_DUP_KEY, getTagIndexKey);
|
||||
pTable->pIndex = tSkipListCreate(TSDB_SUPER_TABLE_SL_LEVEL, colType(pCol), (uint8_t)(colBytes(pCol)), NULL,
|
||||
SL_ALLOW_DUP_KEY, getTagIndexKey);
|
||||
if (pTable->pIndex == NULL) {
|
||||
terrno = TSDB_CODE_TDB_OUT_OF_MEMORY;
|
||||
goto _err;
|
||||
|
@ -870,9 +864,7 @@ static STable *tsdbCreateTableFromCfg(STableCfg *pCfg, bool isSuper, STable *pST
|
|||
}
|
||||
} else {
|
||||
TABLE_SUID(pTable) = -1;
|
||||
pTable->numOfSchemas = 1;
|
||||
pTable->schema[0] = tdDupSchema(pCfg->schema);
|
||||
if (pTable->schema[0] == NULL) {
|
||||
if (tsdbAddSchema(pTable, tdDupSchema(pCfg->schema)) < 0) {
|
||||
terrno = TSDB_CODE_TDB_OUT_OF_MEMORY;
|
||||
goto _err;
|
||||
}
|
||||
|
@ -906,9 +898,7 @@ static void tsdbFreeTable(STable *pTable) {
|
|||
TABLE_UID(pTable));
|
||||
tfree(TABLE_NAME(pTable));
|
||||
if (TABLE_TYPE(pTable) != TSDB_CHILD_TABLE) {
|
||||
for (int i = 0; i < TSDB_MAX_TABLE_SCHEMAS; i++) {
|
||||
tdFreeSchema(pTable->schema[i]);
|
||||
}
|
||||
tsdbFreeTableSchema(pTable);
|
||||
|
||||
if (TABLE_TYPE(pTable) == TSDB_SUPER_TABLE) {
|
||||
tdFreeSchema(pTable->tagSchema);
|
||||
|
@ -1260,9 +1250,10 @@ static int tsdbEncodeTable(void **buf, STable *pTable) {
|
|||
tlen += taosEncodeFixedU64(buf, TABLE_SUID(pTable));
|
||||
tlen += tdEncodeKVRow(buf, pTable->tagVal);
|
||||
} else {
|
||||
tlen += taosEncodeFixedU8(buf, pTable->numOfSchemas);
|
||||
for (int i = 0; i < pTable->numOfSchemas; i++) {
|
||||
tlen += tdEncodeSchema(buf, pTable->schema[i]);
|
||||
tlen += taosEncodeFixedU8(buf, (uint8_t)taosArrayGetSize(pTable->schema));
|
||||
for (int i = 0; i < taosArrayGetSize(pTable->schema); i++) {
|
||||
STSchema *pSchema = taosArrayGetP(pTable->schema, i);
|
||||
tlen += tdEncodeSchema(buf, pSchema);
|
||||
}
|
||||
|
||||
if (TABLE_TYPE(pTable) == TSDB_SUPER_TABLE) {
|
||||
|
@ -1293,9 +1284,12 @@ static void *tsdbDecodeTable(void *buf, STable **pRTable) {
|
|||
buf = taosDecodeFixedU64(buf, &TABLE_SUID(pTable));
|
||||
buf = tdDecodeKVRow(buf, &(pTable->tagVal));
|
||||
} else {
|
||||
buf = taosDecodeFixedU8(buf, &(pTable->numOfSchemas));
|
||||
for (int i = 0; i < pTable->numOfSchemas; i++) {
|
||||
buf = tdDecodeSchema(buf, &(pTable->schema[i]));
|
||||
uint8_t nSchemas;
|
||||
buf = taosDecodeFixedU8(buf, &nSchemas);
|
||||
for (int i = 0; i < nSchemas; i++) {
|
||||
STSchema *pSchema;
|
||||
buf = tdDecodeSchema(buf, &pSchema);
|
||||
tsdbAddSchema(pTable, pSchema);
|
||||
}
|
||||
|
||||
if (TABLE_TYPE(pTable) == TSDB_SUPER_TABLE) {
|
||||
|
@ -1457,3 +1451,38 @@ static int tsdbCheckTableTagVal(SKVRow *pKVRow, STSchema *pSchema) {
|
|||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tsdbAddSchema(STable *pTable, STSchema *pSchema) {
|
||||
ASSERT(TABLE_TYPE(pTable) != TSDB_CHILD_TABLE);
|
||||
|
||||
if (pTable->schema == NULL) {
|
||||
pTable->schema = taosArrayInit(TSDB_MAX_TABLE_SCHEMAS, sizeof(SSchema *));
|
||||
if (pTable->schema == NULL) {
|
||||
terrno = TAOS_SYSTEM_ERROR(errno);
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
ASSERT(taosArrayGetSize(pTable->schema) == 0 ||
|
||||
schemaVersion(pSchema) > schemaVersion(*(STSchema **)taosArrayGetLast(pTable->schema)));
|
||||
|
||||
if (taosArrayPush(pTable->schema, &pSchema) == NULL) {
|
||||
terrno = TAOS_SYSTEM_ERROR(errno);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void tsdbFreeTableSchema(STable *pTable) {
|
||||
ASSERT(pTable != NULL);
|
||||
|
||||
if (pTable->schema) {
|
||||
for (size_t i = 0; i < taosArrayGetSize(pTable->schema); i++) {
|
||||
STSchema *pSchema = taosArrayGetP(pTable->schema, i);
|
||||
tdFreeSchema(pSchema);
|
||||
}
|
||||
|
||||
taosArrayDestroy(pTable->schema);
|
||||
}
|
||||
}
|
|
@ -691,6 +691,18 @@ static STableGroupInfo* trimTableGroup(STimeWindow* window, STableGroupInfo* pGr
|
|||
TsdbQueryHandleT tsdbQueryRowsInExternalWindow(STsdbRepo *tsdb, STsdbQueryCond* pCond, STableGroupInfo *groupList, uint64_t qId, SMemRef* pRef) {
|
||||
STableGroupInfo* pNew = trimTableGroup(&pCond->twindow, groupList);
|
||||
|
||||
if (pNew->numOfTables == 0) {
|
||||
tsdbDebug("update query time range to invalidate time window");
|
||||
|
||||
assert(taosArrayGetSize(pNew->pGroupList) == 0);
|
||||
bool asc = ASCENDING_TRAVERSE(pCond->order);
|
||||
if (asc) {
|
||||
pCond->twindow.ekey = pCond->twindow.skey - 1;
|
||||
} else {
|
||||
pCond->twindow.skey = pCond->twindow.ekey - 1;
|
||||
}
|
||||
}
|
||||
|
||||
STsdbQueryHandle *pQueryHandle = (STsdbQueryHandle*) tsdbQueryTables(tsdb, pCond, pNew, qId, pRef);
|
||||
pQueryHandle->loadExternalRow = true;
|
||||
pQueryHandle->currentLoadExternalRows = true;
|
||||
|
@ -2693,7 +2705,7 @@ static void destroyHelper(void* param) {
|
|||
free(param);
|
||||
}
|
||||
|
||||
static bool loadBlockOfActiveTable(STsdbQueryHandle* pQueryHandle) {
|
||||
static bool loadBlockOfActiveTable(STsdbQueryHandle* pQueryHandle) {
|
||||
if (pQueryHandle->checkFiles) {
|
||||
// check if the query range overlaps with the file data block
|
||||
bool exists = true;
|
||||
|
|
|
@ -47,7 +47,7 @@ int WCSPatternMatch(const wchar_t *pattern, const wchar_t *str, size_t size, con
|
|||
|
||||
int32_t doCompare(const char* a, const char* b, int32_t type, size_t size);
|
||||
|
||||
__compar_fn_t getKeyComparFunc(int32_t keyType);
|
||||
__compar_fn_t getKeyComparFunc(int32_t keyType, int32_t order);
|
||||
|
||||
__compar_fn_t getComparFunc(int32_t type, int32_t optr);
|
||||
|
||||
|
|
|
@ -20,7 +20,7 @@
|
|||
extern "C" {
|
||||
#endif
|
||||
|
||||
void taosNetTest(char *role, char *host, int port, int pkgLen);
|
||||
void taosNetTest(char *role, char *host, int32_t port, int32_t pkgLen, int32_t pkgNum, char *pkgType);
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
|
|
|
@ -16,44 +16,22 @@
|
|||
#include "os.h"
|
||||
#include "ttype.h"
|
||||
#include "tcompare.h"
|
||||
#include "tarray.h"
|
||||
#include "hash.h"
|
||||
|
||||
int32_t setCompareBytes1(const void *pLeft, const void *pRight) {
|
||||
return NULL != taosHashGet((SHashObj *)pRight, pLeft, 1) ? 1 : 0;
|
||||
return NULL != taosHashGet((SHashObj *)pRight, pLeft, 1) ? 1 : 0;
|
||||
}
|
||||
|
||||
int32_t setCompareBytes2(const void *pLeft, const void *pRight) {
|
||||
return NULL != taosHashGet((SHashObj *)pRight, pLeft, 2) ? 1 : 0;
|
||||
return NULL != taosHashGet((SHashObj *)pRight, pLeft, 2) ? 1 : 0;
|
||||
}
|
||||
|
||||
int32_t setCompareBytes4(const void *pLeft, const void *pRight) {
|
||||
return NULL != taosHashGet((SHashObj *)pRight, pLeft, 4) ? 1 : 0;
|
||||
return NULL != taosHashGet((SHashObj *)pRight, pLeft, 4) ? 1 : 0;
|
||||
}
|
||||
|
||||
int32_t setCompareBytes8(const void *pLeft, const void *pRight) {
|
||||
return NULL != taosHashGet((SHashObj *)pRight, pLeft, 8) ? 1 : 0;
|
||||
}
|
||||
|
||||
int32_t compareInt32Val(const void *pLeft, const void *pRight) {
|
||||
int32_t left = GET_INT32_VAL(pLeft), right = GET_INT32_VAL(pRight);
|
||||
if (left > right) return 1;
|
||||
if (left < right) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t compareInt64Val(const void *pLeft, const void *pRight) {
|
||||
int64_t left = GET_INT64_VAL(pLeft), right = GET_INT64_VAL(pRight);
|
||||
if (left > right) return 1;
|
||||
if (left < right) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t compareInt16Val(const void *pLeft, const void *pRight) {
|
||||
int16_t left = GET_INT16_VAL(pLeft), right = GET_INT16_VAL(pRight);
|
||||
if (left > right) return 1;
|
||||
if (left < right) return -1;
|
||||
return 0;
|
||||
return NULL != taosHashGet((SHashObj *)pRight, pLeft, 8) ? 1 : 0;
|
||||
}
|
||||
|
||||
int32_t compareInt8Val(const void *pLeft, const void *pRight) {
|
||||
|
@ -63,6 +41,43 @@ int32_t compareInt8Val(const void *pLeft, const void *pRight) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int32_t compareInt8ValDesc(const void *pLeft, const void *pRight) {
|
||||
return compareInt8Val(pRight, pLeft);
|
||||
}
|
||||
|
||||
int32_t compareInt16Val(const void *pLeft, const void *pRight) {
|
||||
int16_t left = GET_INT16_VAL(pLeft), right = GET_INT16_VAL(pRight);
|
||||
if (left > right) return 1;
|
||||
if (left < right) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t compareInt16ValDesc(const void* pLeft, const void* pRight) {
|
||||
return compareInt16Val(pRight, pLeft);
|
||||
}
|
||||
|
||||
int32_t compareInt32Val(const void *pLeft, const void *pRight) {
|
||||
int32_t left = GET_INT32_VAL(pLeft), right = GET_INT32_VAL(pRight);
|
||||
if (left > right) return 1;
|
||||
if (left < right) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t compareInt32ValDesc(const void* pLeft, const void* pRight) {
|
||||
return compareInt32Val(pRight, pLeft);
|
||||
}
|
||||
|
||||
int32_t compareInt64Val(const void *pLeft, const void *pRight) {
|
||||
int64_t left = GET_INT64_VAL(pLeft), right = GET_INT64_VAL(pRight);
|
||||
if (left > right) return 1;
|
||||
if (left < right) return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int32_t compareInt64ValDesc(const void* pLeft, const void* pRight) {
|
||||
return compareInt64Val(pRight, pLeft);
|
||||
}
|
||||
|
||||
int32_t compareUint32Val(const void *pLeft, const void *pRight) {
|
||||
uint32_t left = GET_UINT32_VAL(pLeft), right = GET_UINT32_VAL(pRight);
|
||||
if (left > right) return 1;
|
||||
|
@ -70,6 +85,10 @@ int32_t compareUint32Val(const void *pLeft, const void *pRight) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int32_t compareUint32ValDesc(const void* pLeft, const void* pRight) {
|
||||
return compareUint32Val(pRight, pLeft);
|
||||
}
|
||||
|
||||
int32_t compareUint64Val(const void *pLeft, const void *pRight) {
|
||||
uint64_t left = GET_UINT64_VAL(pLeft), right = GET_UINT64_VAL(pRight);
|
||||
if (left > right) return 1;
|
||||
|
@ -77,6 +96,10 @@ int32_t compareUint64Val(const void *pLeft, const void *pRight) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int32_t compareUint64ValDesc(const void* pLeft, const void* pRight) {
|
||||
return compareUint64Val(pRight, pLeft);
|
||||
}
|
||||
|
||||
int32_t compareUint16Val(const void *pLeft, const void *pRight) {
|
||||
uint16_t left = GET_UINT16_VAL(pLeft), right = GET_UINT16_VAL(pRight);
|
||||
if (left > right) return 1;
|
||||
|
@ -84,6 +107,10 @@ int32_t compareUint16Val(const void *pLeft, const void *pRight) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int32_t compareUint16ValDesc(const void* pLeft, const void* pRight) {
|
||||
return compareUint16Val(pRight, pLeft);
|
||||
}
|
||||
|
||||
int32_t compareUint8Val(const void* pLeft, const void* pRight) {
|
||||
uint8_t left = GET_UINT8_VAL(pLeft), right = GET_UINT8_VAL(pRight);
|
||||
if (left > right) return 1;
|
||||
|
@ -91,6 +118,10 @@ int32_t compareUint8Val(const void* pLeft, const void* pRight) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
int32_t compareUint8ValDesc(const void* pLeft, const void* pRight) {
|
||||
return compareUint8Val(pRight, pLeft);
|
||||
}
|
||||
|
||||
int32_t compareFloatVal(const void *pLeft, const void *pRight) {
|
||||
float p1 = GET_FLOAT_VAL(pLeft);
|
||||
float p2 = GET_FLOAT_VAL(pRight);
|
||||
|
@ -112,6 +143,10 @@ int32_t compareFloatVal(const void *pLeft, const void *pRight) {
|
|||
return FLT_GREATER(p1, p2) ? 1: -1;
|
||||
}
|
||||
|
||||
int32_t compareFloatValDesc(const void* pLeft, const void* pRight) {
|
||||
return compareFloatVal(pRight, pLeft);
|
||||
}
|
||||
|
||||
int32_t compareDoubleVal(const void *pLeft, const void *pRight) {
|
||||
double p1 = GET_DOUBLE_VAL(pLeft);
|
||||
double p2 = GET_DOUBLE_VAL(pRight);
|
||||
|
@ -133,6 +168,10 @@ int32_t compareDoubleVal(const void *pLeft, const void *pRight) {
|
|||
return FLT_GREATER(p1, p2) ? 1: -1;
|
||||
}
|
||||
|
||||
int32_t compareDoubleValDesc(const void* pLeft, const void* pRight) {
|
||||
return compareDoubleVal(pRight, pLeft);
|
||||
}
|
||||
|
||||
int32_t compareLenPrefixedStr(const void *pLeft, const void *pRight) {
|
||||
int32_t len1 = varDataLen(pLeft);
|
||||
int32_t len2 = varDataLen(pRight);
|
||||
|
@ -149,14 +188,18 @@ int32_t compareLenPrefixedStr(const void *pLeft, const void *pRight) {
|
|||
}
|
||||
}
|
||||
|
||||
int32_t compareLenPrefixedStrDesc(const void* pLeft, const void* pRight) {
|
||||
return compareLenPrefixedStr(pRight, pLeft);
|
||||
}
|
||||
|
||||
int32_t compareLenPrefixedWStr(const void *pLeft, const void *pRight) {
|
||||
int32_t len1 = varDataLen(pLeft);
|
||||
int32_t len2 = varDataLen(pRight);
|
||||
|
||||
|
||||
if (len1 != len2) {
|
||||
return len1 > len2? 1:-1;
|
||||
} else {
|
||||
int32_t ret = wcsncmp(varDataVal(pLeft), varDataVal(pRight), len1/TSDB_NCHAR_SIZE);
|
||||
int32_t ret = memcmp((wchar_t*) pLeft, (wchar_t*) pRight, len1);
|
||||
if (ret == 0) {
|
||||
return 0;
|
||||
} else {
|
||||
|
@ -165,6 +208,10 @@ int32_t compareLenPrefixedWStr(const void *pLeft, const void *pRight) {
|
|||
}
|
||||
}
|
||||
|
||||
int32_t compareLenPrefixedWStrDesc(const void* pLeft, const void* pRight) {
|
||||
return compareLenPrefixedWStr(pRight, pLeft);
|
||||
}
|
||||
|
||||
/*
|
||||
* Compare two strings
|
||||
* TSDB_MATCH: Match
|
||||
|
@ -303,10 +350,6 @@ int32_t taosArrayCompareString(const void* a, const void* b) {
|
|||
return compareLenPrefixedStr(x, y);
|
||||
}
|
||||
|
||||
//static int32_t compareFindStrInArray(const void* pLeft, const void* pRight) {
|
||||
// const SArray* arr = (const SArray*) pRight;
|
||||
// return taosArraySearchString(arr, pLeft, taosArrayCompareString, TD_EQ) == NULL ? 0 : 1;
|
||||
//}
|
||||
int32_t compareFindItemInSet(const void *pLeft, const void* pRight) {
|
||||
return NULL != taosHashGet((SHashObj *)pRight, varDataVal(pLeft), varDataLen(pLeft)) ? 1 : 0;
|
||||
}
|
||||
|
@ -330,26 +373,26 @@ __compar_fn_t getComparFunc(int32_t type, int32_t optr) {
|
|||
if (optr == TSDB_RELATION_IN && (type != TSDB_DATA_TYPE_BINARY && type != TSDB_DATA_TYPE_NCHAR)) {
|
||||
switch (type) {
|
||||
case TSDB_DATA_TYPE_BOOL:
|
||||
case TSDB_DATA_TYPE_TINYINT:
|
||||
case TSDB_DATA_TYPE_UTINYINT:
|
||||
case TSDB_DATA_TYPE_TINYINT:
|
||||
case TSDB_DATA_TYPE_UTINYINT:
|
||||
return setCompareBytes1;
|
||||
case TSDB_DATA_TYPE_SMALLINT:
|
||||
case TSDB_DATA_TYPE_USMALLINT:
|
||||
return setCompareBytes2;
|
||||
case TSDB_DATA_TYPE_INT:
|
||||
case TSDB_DATA_TYPE_UINT:
|
||||
case TSDB_DATA_TYPE_FLOAT:
|
||||
case TSDB_DATA_TYPE_FLOAT:
|
||||
return setCompareBytes4;
|
||||
case TSDB_DATA_TYPE_BIGINT:
|
||||
case TSDB_DATA_TYPE_UBIGINT:
|
||||
case TSDB_DATA_TYPE_DOUBLE:
|
||||
case TSDB_DATA_TYPE_TIMESTAMP:
|
||||
case TSDB_DATA_TYPE_BIGINT:
|
||||
case TSDB_DATA_TYPE_UBIGINT:
|
||||
case TSDB_DATA_TYPE_DOUBLE:
|
||||
case TSDB_DATA_TYPE_TIMESTAMP:
|
||||
return setCompareBytes8;
|
||||
default:
|
||||
assert(0);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
switch (type) {
|
||||
case TSDB_DATA_TYPE_BOOL:
|
||||
case TSDB_DATA_TYPE_TINYINT: comparFn = compareInt8Val; break;
|
||||
|
@ -395,50 +438,50 @@ __compar_fn_t getComparFunc(int32_t type, int32_t optr) {
|
|||
return comparFn;
|
||||
}
|
||||
|
||||
__compar_fn_t getKeyComparFunc(int32_t keyType) {
|
||||
__compar_fn_t getKeyComparFunc(int32_t keyType, int32_t order) {
|
||||
__compar_fn_t comparFn = NULL;
|
||||
|
||||
switch (keyType) {
|
||||
case TSDB_DATA_TYPE_TINYINT:
|
||||
case TSDB_DATA_TYPE_BOOL:
|
||||
comparFn = compareInt8Val;
|
||||
comparFn = (order == TSDB_ORDER_ASC)? compareInt8Val:compareInt8ValDesc;
|
||||
break;
|
||||
case TSDB_DATA_TYPE_SMALLINT:
|
||||
comparFn = compareInt16Val;
|
||||
comparFn = (order == TSDB_ORDER_ASC)? compareInt16Val:compareInt16ValDesc;
|
||||
break;
|
||||
case TSDB_DATA_TYPE_INT:
|
||||
comparFn = compareInt32Val;
|
||||
comparFn = (order == TSDB_ORDER_ASC)? compareInt32Val:compareInt32ValDesc;
|
||||
break;
|
||||
case TSDB_DATA_TYPE_BIGINT:
|
||||
case TSDB_DATA_TYPE_TIMESTAMP:
|
||||
comparFn = compareInt64Val;
|
||||
comparFn = (order == TSDB_ORDER_ASC)? compareInt64Val:compareInt64ValDesc;
|
||||
break;
|
||||
case TSDB_DATA_TYPE_FLOAT:
|
||||
comparFn = compareFloatVal;
|
||||
comparFn = (order == TSDB_ORDER_ASC)? compareFloatVal:compareFloatValDesc;
|
||||
break;
|
||||
case TSDB_DATA_TYPE_DOUBLE:
|
||||
comparFn = compareDoubleVal;
|
||||
comparFn = (order == TSDB_ORDER_ASC)? compareDoubleVal:compareDoubleValDesc;
|
||||
break;
|
||||
case TSDB_DATA_TYPE_UTINYINT:
|
||||
comparFn = compareUint8Val;
|
||||
comparFn = (order == TSDB_ORDER_ASC)? compareUint8Val:compareUint8ValDesc;
|
||||
break;
|
||||
case TSDB_DATA_TYPE_USMALLINT:
|
||||
comparFn = compareUint16Val;
|
||||
comparFn = (order == TSDB_ORDER_ASC)? compareUint16Val:compareUint16ValDesc;
|
||||
break;
|
||||
case TSDB_DATA_TYPE_UINT:
|
||||
comparFn = compareUint32Val;
|
||||
comparFn = (order == TSDB_ORDER_ASC)? compareUint32Val:compareUint32ValDesc;
|
||||
break;
|
||||
case TSDB_DATA_TYPE_UBIGINT:
|
||||
comparFn = compareUint64Val;
|
||||
comparFn = (order == TSDB_ORDER_ASC)? compareUint64Val:compareUint64ValDesc;
|
||||
break;
|
||||
case TSDB_DATA_TYPE_BINARY:
|
||||
comparFn = compareLenPrefixedStr;
|
||||
comparFn = (order == TSDB_ORDER_ASC)? compareLenPrefixedStr:compareLenPrefixedStrDesc;
|
||||
break;
|
||||
case TSDB_DATA_TYPE_NCHAR:
|
||||
comparFn = compareLenPrefixedWStr;
|
||||
comparFn = (order == TSDB_ORDER_ASC)? compareLenPrefixedWStr:compareLenPrefixedWStrDesc;
|
||||
break;
|
||||
default:
|
||||
comparFn = compareInt32Val;
|
||||
comparFn = (order == TSDB_ORDER_ASC)? compareInt32Val:compareInt32ValDesc;
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -465,8 +508,7 @@ int32_t doCompare(const char* f1, const char* f2, int32_t type, size_t size) {
|
|||
if (t1->len != t2->len) {
|
||||
return t1->len > t2->len? 1:-1;
|
||||
}
|
||||
|
||||
int32_t ret = wcsncmp((wchar_t*) t1->data, (wchar_t*) t2->data, t2->len/TSDB_NCHAR_SIZE);
|
||||
int32_t ret = memcmp((wchar_t*) t1, (wchar_t*) t2, t2->len);
|
||||
if (ret == 0) {
|
||||
return ret;
|
||||
}
|
||||
|
|
|
@ -27,6 +27,10 @@
|
|||
#include "syncMsg.h"
|
||||
|
||||
#define MAX_PKG_LEN (64 * 1000)
|
||||
#define MAX_SPEED_PKG_LEN (1024 * 1024 * 1024)
|
||||
#define MIN_SPEED_PKG_LEN 1024
|
||||
#define MAX_SPEED_PKG_NUM 10000
|
||||
#define MIN_SPEED_PKG_NUM 1
|
||||
#define BUFFER_SIZE (MAX_PKG_LEN + 1024)
|
||||
|
||||
extern int32_t tsRpcMaxUdpSize;
|
||||
|
@ -466,6 +470,7 @@ static void taosNetTestRpc(char *host, int32_t startPort, int32_t pkgLen) {
|
|||
sendpkgLen = pkgLen;
|
||||
}
|
||||
|
||||
tsRpcForceTcp = 1;
|
||||
int32_t ret = taosNetCheckRpc(host, port, sendpkgLen, spi, NULL);
|
||||
if (ret < 0) {
|
||||
printf("failed to test TCP port:%d\n", port);
|
||||
|
@ -479,6 +484,7 @@ static void taosNetTestRpc(char *host, int32_t startPort, int32_t pkgLen) {
|
|||
sendpkgLen = pkgLen;
|
||||
}
|
||||
|
||||
tsRpcForceTcp = 0;
|
||||
ret = taosNetCheckRpc(host, port, pkgLen, spi, NULL);
|
||||
if (ret < 0) {
|
||||
printf("failed to test UDP port:%d\n", port);
|
||||
|
@ -542,12 +548,111 @@ static void taosNetTestServer(char *host, int32_t startPort, int32_t pkgLen) {
|
|||
}
|
||||
}
|
||||
|
||||
void taosNetTest(char *role, char *host, int32_t port, int32_t pkgLen) {
|
||||
static void taosNetTestFqdn(char *host) {
|
||||
int code = 0;
|
||||
uint64_t startTime = taosGetTimestampUs();
|
||||
uint32_t ip = taosGetIpv4FromFqdn(host);
|
||||
if (ip == 0xffffffff) {
|
||||
uError("failed to get IP address from %s since %s", host, strerror(errno));
|
||||
code = -1;
|
||||
}
|
||||
uint64_t endTime = taosGetTimestampUs();
|
||||
uint64_t el = endTime - startTime;
|
||||
printf("check convert fqdn spend, status: %d\tcost: %" PRIu64 " us\n", code, el);
|
||||
return;
|
||||
}
|
||||
|
||||
static void taosNetCheckSpeed(char *host, int32_t port, int32_t pkgLen,
|
||||
int32_t pkgNum, char *pkgType) {
|
||||
// record config
|
||||
int32_t compressTmp = tsCompressMsgSize;
|
||||
int32_t maxUdpSize = tsRpcMaxUdpSize;
|
||||
int32_t forceTcp = tsRpcForceTcp;
|
||||
|
||||
if (0 == strcmp("tcp", pkgType)){
|
||||
tsRpcForceTcp = 1;
|
||||
tsRpcMaxUdpSize = 0; // force tcp
|
||||
} else {
|
||||
tsRpcForceTcp = 0;
|
||||
tsRpcMaxUdpSize = INT_MAX;
|
||||
}
|
||||
tsCompressMsgSize = -1;
|
||||
|
||||
SRpcEpSet epSet;
|
||||
SRpcMsg reqMsg;
|
||||
SRpcMsg rspMsg;
|
||||
void * pRpcConn;
|
||||
char secretEncrypt[32] = {0};
|
||||
char spi = 0;
|
||||
pRpcConn = taosNetInitRpc(secretEncrypt, spi);
|
||||
if (NULL == pRpcConn) {
|
||||
uError("failed to init client rpc");
|
||||
return;
|
||||
}
|
||||
|
||||
printf("check net spend, host:%s port:%d pkgLen:%d pkgNum:%d pkgType:%s\n\n", host, port, pkgLen, pkgNum, pkgType);
|
||||
int32_t totalSucc = 0;
|
||||
uint64_t startT = taosGetTimestampUs();
|
||||
for (int32_t i = 1; i <= pkgNum; i++) {
|
||||
uint64_t startTime = taosGetTimestampUs();
|
||||
|
||||
memset(&epSet, 0, sizeof(SRpcEpSet));
|
||||
epSet.inUse = 0;
|
||||
epSet.numOfEps = 1;
|
||||
epSet.port[0] = port;
|
||||
strcpy(epSet.fqdn[0], host);
|
||||
|
||||
reqMsg.msgType = TSDB_MSG_TYPE_NETWORK_TEST;
|
||||
reqMsg.pCont = rpcMallocCont(pkgLen);
|
||||
reqMsg.contLen = pkgLen;
|
||||
reqMsg.code = 0;
|
||||
reqMsg.handle = NULL; // rpc handle returned to app
|
||||
reqMsg.ahandle = NULL; // app handle set by client
|
||||
strcpy(reqMsg.pCont, "nettest speed");
|
||||
|
||||
rpcSendRecv(pRpcConn, &epSet, &reqMsg, &rspMsg);
|
||||
|
||||
int code = 0;
|
||||
if ((rspMsg.code != 0) || (rspMsg.msgType != TSDB_MSG_TYPE_NETWORK_TEST + 1)) {
|
||||
uError("ret code 0x%x %s", rspMsg.code, tstrerror(rspMsg.code));
|
||||
code = -1;
|
||||
}else{
|
||||
totalSucc ++;
|
||||
}
|
||||
|
||||
rpcFreeCont(rspMsg.pCont);
|
||||
|
||||
uint64_t endTime = taosGetTimestampUs();
|
||||
uint64_t el = endTime - startTime;
|
||||
printf("progress:%5d/%d\tstatus:%d\tcost:%8.2lf ms\tspeed:%8.2lf MB/s\n", i, pkgNum, code, el/1000.0, pkgLen/(el/1000000.0)/1024.0/1024.0);
|
||||
}
|
||||
int64_t endT = taosGetTimestampUs();
|
||||
uint64_t elT = endT - startT;
|
||||
printf("\ntotal succ:%5d/%d\tcost:%8.2lf ms\tspeed:%8.2lf MB/s\n", totalSucc, pkgNum, elT/1000.0, pkgLen/(elT/1000000.0)/1024.0/1024.0*totalSucc);
|
||||
|
||||
rpcClose(pRpcConn);
|
||||
|
||||
// return config
|
||||
tsCompressMsgSize = compressTmp;
|
||||
tsRpcMaxUdpSize = maxUdpSize;
|
||||
tsRpcForceTcp = forceTcp;
|
||||
return;
|
||||
}
|
||||
|
||||
void taosNetTest(char *role, char *host, int32_t port, int32_t pkgLen,
|
||||
int32_t pkgNum, char *pkgType) {
|
||||
tscEmbedded = 1;
|
||||
if (host == NULL) host = tsLocalFqdn;
|
||||
if (port == 0) port = tsServerPort;
|
||||
if (pkgLen <= 10) pkgLen = 1000;
|
||||
if (pkgLen > MAX_PKG_LEN) pkgLen = MAX_PKG_LEN;
|
||||
if (0 == strcmp("speed", role)){
|
||||
if (pkgLen <= MIN_SPEED_PKG_LEN) pkgLen = MIN_SPEED_PKG_LEN;
|
||||
if (pkgLen > MAX_SPEED_PKG_LEN) pkgLen = MAX_SPEED_PKG_LEN;
|
||||
if (pkgNum <= MIN_SPEED_PKG_NUM) pkgNum = MIN_SPEED_PKG_NUM;
|
||||
if (pkgNum > MAX_SPEED_PKG_NUM) pkgNum = MAX_SPEED_PKG_NUM;
|
||||
}else{
|
||||
if (pkgLen <= 10) pkgLen = 1000;
|
||||
if (pkgLen > MAX_PKG_LEN) pkgLen = MAX_PKG_LEN;
|
||||
}
|
||||
|
||||
if (0 == strcmp("client", role)) {
|
||||
taosNetTestClient(host, port, pkgLen);
|
||||
|
@ -560,7 +665,13 @@ void taosNetTest(char *role, char *host, int32_t port, int32_t pkgLen) {
|
|||
taosNetCheckSync(host, port);
|
||||
} else if (0 == strcmp("startup", role)) {
|
||||
taosNetTestStartup(host, port);
|
||||
} else {
|
||||
} else if (0 == strcmp("speed", role)) {
|
||||
tscEmbedded = 0;
|
||||
char type[10] = {0};
|
||||
taosNetCheckSpeed(host, port, pkgLen, pkgNum, strtolower(type, pkgType));
|
||||
}else if (0 == strcmp("fqdn", role)) {
|
||||
taosNetTestFqdn(host);
|
||||
}else {
|
||||
taosNetTestStartup(host, port);
|
||||
}
|
||||
|
||||
|
|
|
@ -54,7 +54,7 @@ SSkipList *tSkipListCreate(uint8_t maxLevel, uint8_t keyType, uint16_t keyLen, _
|
|||
pSkipList->keyFn = fn;
|
||||
pSkipList->seed = rand();
|
||||
if (comparFn == NULL) {
|
||||
pSkipList->comparFn = getKeyComparFunc(keyType);
|
||||
pSkipList->comparFn = getKeyComparFunc(keyType, TSDB_ORDER_ASC);
|
||||
} else {
|
||||
pSkipList->comparFn = comparFn;
|
||||
}
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue