未验证 提交 28d56f54 编写于 作者: H Haojun Liao 提交者: GitHub

Merge branch 'develop' into hjxilinx-patch-11

...@@ -301,20 +301,6 @@ Master Vnode 遵循下面的写入流程: ...@@ -301,20 +301,6 @@ Master Vnode 遵循下面的写入流程:
与 master vnode 相比,slave vnode 不存在转发环节,也不存在回复确认环节,少了两步。但写内存与 WAL 是完全一样的。 与 master vnode 相比,slave vnode 不存在转发环节,也不存在回复确认环节,少了两步。但写内存与 WAL 是完全一样的。
### 异地容灾、IDC迁移
从上述 master 和 slave 流程可以看出,TDengine 采用的是异步复制的方式进行数据同步。这种方式能够大幅提高写入性能,网络延时对写入速度不会有大的影响。通过配置每个物理节点的IDC和机架号,可以保证对于一个虚拟节点组,虚拟节点由来自不同 IDC、不同机架的物理节点组成,从而实现异地容灾。因此 TDengine 原生支持异地容灾,无需再使用其他工具。
另一方面,TDengine 支持动态修改副本数,一旦副本数增加,新加入的虚拟节点将立即进入数据同步流程,同步结束后,新加入的虚拟节点即可提供服务。而在同步过程中,master 以及其他已经同步的虚拟节点都可以对外提供服务。利用这一特性,TDengine 可以实现无服务中断的 IDC 机房迁移。只需要将新 IDC 的物理节点加入现有集群,等数据同步完成后,再将老的 IDC 的物理节点从集群中剔除即可。
但是,这种异步复制的方式,存在极小的时间窗口,丢失写入的数据。具体场景如下:
1. master vnode 完成了它的 5 步操作,已经给 APP 确认写入成功,然后宕机
2. slave vnode 收到写入请求后,在第 2 步写入日志之前,处理失败
3. slave vnode 将成为新的 master,从而丢失了一条记录
理论上,只要是异步复制,就无法保证 100% 不丢失。但是这个窗口极小,master 与 slave 要同时发生故障,而且发生在刚给应用确认写入成功之后。
### 主从选择 ### 主从选择
Vnode 会保持一个数据版本号(version),对内存数据进行持久化存储时,对该版本号也进行持久化存储。每个数据更新操作,无论是采集的时序数据还是元数据,这个版本号将增加 1。 Vnode 会保持一个数据版本号(version),对内存数据进行持久化存储时,对该版本号也进行持久化存储。每个数据更新操作,无论是采集的时序数据还是元数据,这个版本号将增加 1。
......
...@@ -94,78 +94,3 @@ GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS=tdengine-datasource ...@@ -94,78 +94,3 @@ GF_PLUGINS_ALLOW_LOADING_UNSIGNED_PLUGINS=tdengine-datasource
在 2.3.3.0 及以上版本,您可以导入 TDinsight Dashboard (Grafana Dashboard ID: [15167](https://grafana.com/grafana/dashboards/15167)) 作为 TDengine 集群的监控可视化工具。安装和使用说明请见 [TDinsight 用户手册](https://www.taosdata.com/cn/documentation/tools/insight) 在 2.3.3.0 及以上版本,您可以导入 TDinsight Dashboard (Grafana Dashboard ID: [15167](https://grafana.com/grafana/dashboards/15167)) 作为 TDengine 集群的监控可视化工具。安装和使用说明请见 [TDinsight 用户手册](https://www.taosdata.com/cn/documentation/tools/insight)
## <a class="anchor" id="matlab"></a>MATLAB
MATLAB 可以通过安装包内提供的 JDBC Driver 直接连接到 TDengine 获取数据到本地工作空间。
### MATLAB 的 JDBC 接口适配
MATLAB 的适配有下面几个步骤,下面以 Windows 10 上适配 MATLAB2021a 为例:
- 将 TDengine 客户端安装路径下的 `\TDengine\connector\jdbc的驱动程序taos-jdbcdriver-2.0.25-dist.jar` 拷贝到 `${matlab_root}\MATLAB\R2021a\java\jar\toolbox`
- 将 TDengine 安装包内的 `taos.lib` 文件拷贝至 `${matlab_root_dir}\MATLAB\R2021\lib\win64`
- 将新添加的驱动 jar 包加入 MATLAB 的 classpath。在 `${matlab_root_dir}\MATLAB\R2021a\toolbox\local\classpath.txt` 文件中添加下面一行:
```
$matlabroot/java/jar/toolbox/taos-jdbcdriver-2.0.25-dist.jar
```
-`${user_home}\AppData\Roaming\MathWorks\MATLAB\R2021a\` 下添加一个文件 `javalibrarypath.txt`,并在该文件中添加 taos.dll 的路径,比如您的 taos.dll 是在安装时拷贝到了 `C:\Windows\System32` 下,那么就应该在 `javalibrarypath.txt` 中添加如下一行:
```
C:\Windows\System32
```
### 在 MATLAB 中连接 TDengine 获取数据
在成功进行了上述配置后,打开 MATLAB。
- 创建一个连接:
```matlab
conn = database(‘test’, ‘root’, ‘taosdata’, ‘com.taosdata.jdbc.TSDBDriver’, ‘jdbc:TSDB://192.168.1.94:6030/’)
```
- 执行一次查询:
```matlab
sql0 = [‘select * from tb’]
data = select(conn, sql0);
```
- 插入一条记录:
```matlab
sql1 = [‘insert into tb values (now, 1)’]
exec(conn, sql1)
```
更多例子细节请参考安装包内 `examples\Matlab\TDengineDemo.m` 文件。
## <a class="anchor" id="r"></a>R
R语言支持通过JDBC接口来连接TDengine数据库。首先需要安装R语言的JDBC包。启动R语言环境,然后执行以下命令安装R语言的JDBC支持库:
```R
install.packages('RJDBC', repos='http://cran.us.r-project.org')
```
安装完成以后,通过执行`library('RJDBC')`命令加载 _RJDBC_ 包:
然后加载TDengine的JDBC驱动:
```R
drv<-JDBC("com.taosdata.jdbc.TSDBDriver","JDBCDriver-2.0.0-dist.jar", identifier.quote="\"")
```
如果执行成功,不会出现任何错误信息。之后通过以下命令尝试连接数据库:
```R
conn<-dbConnect(drv,"jdbc:TSDB://192.168.0.1:0/?user=root&password=taosdata","root","taosdata")
```
注意将上述命令中的IP地址替换成正确的IP地址。如果没有任务错误的信息,则连接数据库成功,否则需要根据错误提示调整连接的命令。TDengine支持以下的 _RJDBC_ 包中函数:
- dbWriteTable(conn, "test", iris, overwrite=FALSE, append=TRUE):将数据框iris写入表test中,overwrite必须设置为false,append必须设为TRUE,且数据框iris要与表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。
TDengine客户端暂不支持如下函数:
- dbExistsTable(conn, "test"):是否存在表test。
- dbListTables(conn):显示连接中的所有表。
...@@ -223,7 +223,10 @@ taosd -C ...@@ -223,7 +223,10 @@ taosd -C
| 105 | compressColData | | **S** | bytes | 客户端与服务器之间进行消息通讯过程中,对服务器端查询结果进行列压缩的阈值。 | 0: 对所有查询结果均进行压缩 >0: 查询结果中任意列大小超过该值的消息才进行压缩 -1: 不压缩 | -1 | 2.3.0.0 版本新增。 | | 105 | compressColData | | **S** | bytes | 客户端与服务器之间进行消息通讯过程中,对服务器端查询结果进行列压缩的阈值。 | 0: 对所有查询结果均进行压缩 >0: 查询结果中任意列大小超过该值的消息才进行压缩 -1: 不压缩 | -1 | 2.3.0.0 版本新增。 |
| 106 | tsdbMetaCompactRatio | | **C** | | tsdb meta文件中冗余数据超过多少阈值,开启meta文件的压缩功能 | 0:不开启,[1-100]:冗余数据比例 | 0 | | | 106 | tsdbMetaCompactRatio | | **C** | | tsdb meta文件中冗余数据超过多少阈值,开启meta文件的压缩功能 | 0:不开启,[1-100]:冗余数据比例 | 0 | |
| 107 | rpcForceTcp | | **SC**| | 强制使用TCP传输 | 0: 不开启 1: 开启 | 0 | 在网络比较差的环境中,建议开启。2.0版本新增。| | 107 | rpcForceTcp | | **SC**| | 强制使用TCP传输 | 0: 不开启 1: 开启 | 0 | 在网络比较差的环境中,建议开启。2.0版本新增。|
| 108 | maxRegexStringLen | | **C**| | 正则表达式最大允许长度 | 默认值128,最大长度 16384 | 0 | 2.3版本新增。| | 108 | maxNumOfDistinctRes | | **S**| | 允许返回的distinct结果最大行数 |默认值为10万,最大值1亿 | 10万 | 2.3版本新增。|
| 109 | clientMerge | | **C**| | 是否允许客户端对写入数据去重 |0:不开启,1:开启| 0 | 2.3版本新增。|
| 110 | httpDBNameMandatory | | **S**| | 是否在URL中输入 数据库名称|0:不开启,1:开启| 0 | 2.3版本新增。|
| 111 | maxRegexStringLen | | **C**| | 正则表达式最大允许长度 | 默认值128,最大长度 16384 | 0 | 2.3版本新增。|
**注意:**对于端口,TDengine会使用从serverPort起13个连续的TCP和UDP端口号,请务必在防火墙打开。因此如果是缺省配置,需要打开从6030到6042共13个端口,而且必须TCP和UDP都打开。(详细的端口情况请参见 [TDengine 2.0 端口说明](https://www.taosdata.com/cn/documentation/faq#port) **注意:**对于端口,TDengine会使用从serverPort起13个连续的TCP和UDP端口号,请务必在防火墙打开。因此如果是缺省配置,需要打开从6030到6042共13个端口,而且必须TCP和UDP都打开。(详细的端口情况请参见 [TDengine 2.0 端口说明](https://www.taosdata.com/cn/documentation/faq#port)
......
...@@ -682,8 +682,9 @@ taos> SELECT SERVER_STATUS() AS status; ...@@ -682,8 +682,9 @@ taos> SELECT SERVER_STATUS() AS status;
1 | 1 |
Query OK, 1 row(s) in set (0.000081s) Query OK, 1 row(s) in set (0.000081s)
``` ```
函数_block_dist()使用说明 函数_block_dist()使用说明
语法 <br/>语法
SELECT _block_dist() FROM { tb_name | stb_name } SELECT _block_dist() FROM { tb_name | stb_name }
...@@ -709,7 +710,7 @@ summary: ...@@ -709,7 +710,7 @@ summary:
5th=[392], 10th=[392], 20th=[392], 30th=[392], 40th=[792], 50th=[792] 60th=[792], 70th=[792], 80th=[792], 90th=[792], 95th=[792], 99th=[792] Min=[392(Rows)] Max=[800(Rows)] Avg=[666(Rows)] Stddev=[2.17] Rows=[2000], Blocks=[3], Size=[5.440(Kb)] Comp=[0.23] RowsInMem=[0] SeekHeaderTime=[1(us)] 5th=[392], 10th=[392], 20th=[392], 30th=[392], 40th=[792], 50th=[792] 60th=[792], 70th=[792], 80th=[792], 90th=[792], 95th=[792], 99th=[792] Min=[392(Rows)] Max=[800(Rows)] Avg=[666(Rows)] Stddev=[2.17] Rows=[2000], Blocks=[3], Size=[5.440(Kb)] Comp=[0.23] RowsInMem=[0] SeekHeaderTime=[1(us)]
``` ```
上述信息的说明如下: 上述信息的说明如下:
1、查询的(超级)表所包含的存储在文件中的数据块(data block)中所包含的数据行的数量分布直方图信息:5%, 10%, 20%, 30%, 40%, 50%, 60%, 70%, 80%, 90%, 95%, 99% 的数值; <br/>1、查询的(超级)表所包含的存储在文件中的数据块(data block)中所包含的数据行的数量分布直方图信息:5%, 10%, 20%, 30%, 40%, 50%, 60%, 70%, 80%, 90%, 95%, 99% 的数值;
<br/>2、所有数据块中,包含行数最少的数据块所包含的行数量, 其中的 Min 指标 392 行。 <br/>2、所有数据块中,包含行数最少的数据块所包含的行数量, 其中的 Min 指标 392 行。
<br/>3、所有数据块中,包含行数最多的数据块所包含的行数量, 其中的 Max 指标 800 行。 <br/>3、所有数据块中,包含行数最多的数据块所包含的行数量, 其中的 Max 指标 800 行。
<br/>4、所有数据块行数的算数平均值 666行(其中的 Avg 项)。 <br/>4、所有数据块行数的算数平均值 666行(其中的 Avg 项)。
...@@ -723,6 +724,7 @@ summary: ...@@ -723,6 +724,7 @@ summary:
支持版本:指定计算算法的功能从2.1.0.x 版本开始,2.1.0.0之前的版本不支持指定使用算法的功能。 支持版本:指定计算算法的功能从2.1.0.x 版本开始,2.1.0.0之前的版本不支持指定使用算法的功能。
#### TAOS SQL中特殊关键词 #### TAOS SQL中特殊关键词
> TBNAME: 在超级表查询中可视为一个特殊的标签,代表查询涉及的子表名<br> > TBNAME: 在超级表查询中可视为一个特殊的标签,代表查询涉及的子表名<br>
...@@ -839,6 +841,7 @@ WHERE t1.ts = t2.ts AND t1.deviceid = t2.deviceid AND t1.status=0; ...@@ -839,6 +841,7 @@ WHERE t1.ts = t2.ts AND t1.deviceid = t2.deviceid AND t1.status=0;
3. 暂不支持参与 JOIN 操作的表之间聚合后的四则运算。 3. 暂不支持参与 JOIN 操作的表之间聚合后的四则运算。
4. 不支持只对其中一部分表做 GROUP BY。 4. 不支持只对其中一部分表做 GROUP BY。
5. JOIN 查询的不同表的过滤条件之间不能为 OR。 5. JOIN 查询的不同表的过滤条件之间不能为 OR。
6. JOIN 查询要求连接条件不能是普通列,只能针对标签和主时间字段列(第一列)。
<a class="anchor" id="nested"></a> <a class="anchor" id="nested"></a>
### 嵌套查询 ### 嵌套查询
...@@ -1569,7 +1572,54 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数 ...@@ -1569,7 +1572,54 @@ TDengine支持针对数据的聚合查询。提供支持的聚合和选择函数
## <a class="anchor" id="aggregation"></a>按窗口切分聚合 ## <a class="anchor" id="aggregation"></a>按窗口切分聚合
TDengine 支持按时间段等窗口切分方式进行聚合结果查询,比如温度传感器每秒采集一次数据,但需查询每隔 10 分钟的温度平均值。这类聚合适合于降维(down sample)操作,语法如下: TDengine 支持按时间段窗口切分方式进行聚合结果查询,比如温度传感器每秒采集一次数据,但需查询每隔 10 分钟的温度平均值。这种场景下可以使用窗口子句来获得需要的查询结果。
窗口子句用于针对查询的数据集合进行按照窗口切分成为查询子集并进行聚合,窗口包含时间窗口(time window)、状态窗口(status window)、会话窗口(session window)三种窗口。其中时间窗口又可划分为滑动时间窗口和翻转时间窗口。
时间窗口
INTERVAL子句用于产生相等时间周期的窗口,SLIDING用以指定窗口向前滑动的时间。每次执行的查询是一个时间窗口,时间窗口随着时间流动向前滑动。在定义连续查询的时候需要指定时间窗口(time window )大小和每次前向增量时间(forward sliding times)。如图,[t0s, t0e] ,[t1s , t1e], [t2s, t2e] 是分别是执行三次连续查询的时间窗口范围,窗口的前向滑动的时间范围sliding time标识 。查询过滤、聚合等操作按照每个时间窗口为独立的单位执行。当SLIDING与INTERVAL相等的时候,滑动窗口即为翻转窗口。
![时间窗口示意图](../images/sql/timewindow-1.png)
INTERVAL和SLIDING子句需要配合聚合和选择函数来使用。以下SQL语句非法:
```mysql
SELECT * FROM temp_table INTERVAL(1S)
```
SLIDING的向前滑动的时间不能超过一个窗口的时间范围。以下语句非法:
```mysql
SELECT COUNT(*) FROM temp_table INTERVAL(1D) SLIDING(2D)
```
当 SLIDING 与 INTERVAL 取值相等的时候,滑动窗口即为翻转窗口。
* 聚合时间段的窗口宽度由关键词 INTERVAL 指定,最短时间间隔 10 毫秒(10a);并且支持偏移 offset(偏移必须小于间隔),也即时间窗口划分与“UTC 时刻 0”相比的偏移量。SLIDING 语句用于指定聚合时间段的前向增量,也即每次窗口向前滑动的时长。
* 从 2.1.5.0 版本开始,INTERVAL 语句允许的最短时间间隔调整为 1 微秒(1u),当然如果所查询的 DATABASE 的时间精度设置为毫秒级,那么允许的最短时间间隔为 1 毫秒(1a)。
* **注意**:用到 INTERVAL 语句时,除非极特殊的情况,都要求把客户端和服务端的 taos.cfg 配置文件中的 timezone 参数配置为相同的取值,以避免时间处理函数频繁进行跨时区转换而导致的严重性能影响。
![时间窗口示意图](../images/sql/timewindow-2.png)
状态窗口
使用整数(布尔值)或字符串来标识产生记录时候设备的状态量。产生的记录如果具有相同的状态量数值则归属于同一个状态窗口,数值改变后该窗口关闭。如下图所示,根据状态量确定的状态窗口分别是[2019-04-28 14:22:07,2019-04-28 14:22:10]和[2019-04-28 14:22:11,2019-04-28 14:22:12]两个。(状态窗口暂不支持对超级表使用)
使用STATE_WINDOW来确定状态窗口划分的列。例如:
```mysql
SELECT COUNT(*), FIRST(ts), status FROM temp_tb_1 STATE_WINDOW(status)
```
会话窗口
会话窗口根据记录的时间戳主键的值来确定是否属于同一个会话。如下图所示,如果设置时间戳的连续的间隔小于等于12秒,则以下6条记录构成2个会话窗口,分别是:[2019-04-28 14:22:10,2019-04-28 14:22:30]和[2019-04-28 14:23:10,2019-04-28 14:23:30]。因为2019-04-28 14:22:30与2019-04-28 14:23:10之间的时间间隔是40秒,超过了连续时间间隔(12秒)。
![时间窗口示意图](../images/sql/timewindow-3.png)
在tol_value时间间隔范围内的结果都认为归属于同一个窗口,如果连续的两条记录的时间超过tol_val,则自动开启下一个窗口。(会话窗口暂不支持对超级表使用)
```mysql
SELECT COUNT(*), FIRST(ts) FROM temp_tb_1 SESSION_WINDOW(ts, tol_val)
```
这种类型的查询语法如下:
```mysql ```mysql
SELECT function_list FROM tb_name SELECT function_list FROM tb_name
...@@ -1587,12 +1637,8 @@ SELECT function_list FROM stb_name ...@@ -1587,12 +1637,8 @@ SELECT function_list FROM stb_name
``` ```
- 在聚合查询中,function_list 位置允许使用聚合和选择函数,并要求每个函数仅输出单个结果(例如:COUNT、AVG、SUM、STDDEV、LEASTSQUARES、PERCENTILE、MIN、MAX、FIRST、LAST),而不能使用具有多行输出结果的函数(例如:TOP、BOTTOM、DIFF 以及四则运算)。 - 在聚合查询中,function_list 位置允许使用聚合和选择函数,并要求每个函数仅输出单个结果(例如:COUNT、AVG、SUM、STDDEV、LEASTSQUARES、PERCENTILE、MIN、MAX、FIRST、LAST),而不能使用具有多行输出结果的函数(例如:TOP、BOTTOM、DIFF 以及四则运算)。
- 查询过滤、聚合等操作按照每个切分窗口为独立的单位执行。聚合查询目前支持三种窗口的划分方式:
1. 时间窗口:聚合时间段的窗口宽度由关键词 INTERVAL 指定,最短时间间隔 10 毫秒(10a);并且支持偏移 offset(偏移必须小于间隔),也即时间窗口划分与“UTC 时刻 0”相比的偏移量。SLIDING 语句用于指定聚合时间段的前向增量,也即每次窗口向前滑动的时长。当 SLIDING 与 INTERVAL 取值相等的时候,滑动窗口即为翻转窗口。
* 从 2.1.5.0 版本开始,INTERVAL 语句允许的最短时间间隔调整为 1 微秒(1u),当然如果所查询的 DATABASE 的时间精度设置为毫秒级,那么允许的最短时间间隔为 1 毫秒(1a)。
* **注意:**用到 INTERVAL 语句时,除非极特殊的情况,都要求把客户端和服务端的 taos.cfg 配置文件中的 timezone 参数配置为相同的取值,以避免时间处理函数频繁进行跨时区转换而导致的严重性能影响。
2. 状态窗口:使用整数或布尔值来标识产生记录时设备的状态量,产生的记录如果具有相同的状态量取值则归属于同一个状态窗口,数值改变后该窗口关闭。状态量所对应的列作为 STATE_WINDOW 语句的参数来指定。(状态窗口暂不支持对超级表使用)
3. 会话窗口:时间戳所在的列由 SESSION 语句的 ts_col 参数指定,会话窗口根据相邻两条记录的时间戳差值来确定是否属于同一个会话——如果时间戳差异在 tol_val 以内,则认为记录仍属于同一个窗口;如果时间变化超过 tol_val,则自动开启下一个窗口。(会话窗口暂不支持对超级表使用)
- WHERE 语句可以指定查询的起止时间和其他过滤条件。 - WHERE 语句可以指定查询的起止时间和其他过滤条件。
- FILL 语句指定某一窗口区间数据缺失的情况下的填充模式。填充模式包括以下几种: - FILL 语句指定某一窗口区间数据缺失的情况下的填充模式。填充模式包括以下几种:
1. 不进行填充:NONE(默认填充模式)。 1. 不进行填充:NONE(默认填充模式)。
...@@ -1630,7 +1676,7 @@ SELECT AVG(current), MAX(current), APERCENTILE(current, 50) FROM meters ...@@ -1630,7 +1676,7 @@ SELECT AVG(current), MAX(current), APERCENTILE(current, 50) FROM meters
- 表名最大长度为 192,每行数据最大长度 16k 个字符, 从 2.1.7.0 版本开始,每行数据最大长度 48k 个字符(注意:数据行内每个 BINARY/NCHAR 类型的列还会额外占用 2 个字节的存储位置)。 - 表名最大长度为 192,每行数据最大长度 16k 个字符, 从 2.1.7.0 版本开始,每行数据最大长度 48k 个字符(注意:数据行内每个 BINARY/NCHAR 类型的列还会额外占用 2 个字节的存储位置)。
- 列名最大长度为 64,最多允许 1024 列,最少需要 2 列,第一列必须是时间戳。(从 2.1.7.0 版本开始,改为最多允许 4096 列) - 列名最大长度为 64,最多允许 1024 列,最少需要 2 列,第一列必须是时间戳。(从 2.1.7.0 版本开始,改为最多允许 4096 列)
- 标签名最大长度为 64,最多允许 128 个,可以 1 个,一个表中标签值的总长度不超过 16k 个字符。 - 标签名最大长度为 64,最多允许 128 个,可以 1 个,一个表中标签值的总长度不超过 16k 个字符。
- SQL 语句最大长度 1048576 个字符,也可通过系统配置参数 maxSQLLength 修改,取值范围 65480 ~ 1048576。 - SQL 语句最大长度 1048576 个字符,也可通过客户端配置参数 maxSQLLength 修改,取值范围 65480 ~ 1048576。
- SELECT 语句的查询结果,最多允许返回 1024 列(语句中的函数调用可能也会占用一些列空间),超限时需要显式指定较少的返回数据列,以避免语句执行报错。(从 2.1.7.0 版本开始,改为最多允许 4096 列) - SELECT 语句的查询结果,最多允许返回 1024 列(语句中的函数调用可能也会占用一些列空间),超限时需要显式指定较少的返回数据列,以避免语句执行报错。(从 2.1.7.0 版本开始,改为最多允许 4096 列)
- 库的数目,超级表的数目、表的数目,系统不做限制,仅受系统资源限制。 - 库的数目,超级表的数目、表的数目,系统不做限制,仅受系统资源限制。
......
...@@ -601,6 +601,10 @@ static void monSaveSystemInfo() { ...@@ -601,6 +601,10 @@ static void monSaveSystemInfo() {
} }
static int32_t monGetRowElemCharLen(TAOS_FIELD field, char *rowElem) { static int32_t monGetRowElemCharLen(TAOS_FIELD field, char *rowElem) {
if (field.type != TSDB_DATA_TYPE_BINARY && field.type != TSDB_DATA_TYPE_NCHAR) {
return -1;
}
int32_t charLen = varDataLen(rowElem - VARSTR_HEADER_SIZE); int32_t charLen = varDataLen(rowElem - VARSTR_HEADER_SIZE);
if (field.type == TSDB_DATA_TYPE_BINARY) { if (field.type == TSDB_DATA_TYPE_BINARY) {
assert(charLen <= field.bytes && charLen >= 0); assert(charLen <= field.bytes && charLen >= 0);
...@@ -629,12 +633,14 @@ static int32_t monBuildMasterUptimeSql(char *sql) { ...@@ -629,12 +633,14 @@ static int32_t monBuildMasterUptimeSql(char *sql) {
while ((row = taos_fetch_row(result))) { while ((row = taos_fetch_row(result))) {
for (int i = 0; i < num_fields; ++i) { for (int i = 0; i < num_fields; ++i) {
int32_t charLen = monGetRowElemCharLen(fields[i], (char *)row[i]); if (strcmp(fields[i].name, "role") == 0) {
if (strcmp(fields[i].name, "role") == 0 && strncmp((char *)row[i], "master", charLen) == 0) { int32_t charLen = monGetRowElemCharLen(fields[i], (char *)row[i]);
if (strcmp(fields[i + 1].name, "role_time") == 0) { if (strncmp((char *)row[i], "master", charLen) == 0) {
int64_t now = taosGetTimestamp(TSDB_TIME_PRECISION_MILLI); if (strcmp(fields[i + 1].name, "role_time") == 0) {
//master uptime in seconds int64_t now = taosGetTimestamp(TSDB_TIME_PRECISION_MILLI);
masterUptime = (now - *(int64_t *)row[i + 1]) / 1000; //master uptime in seconds
masterUptime = (now - *(int64_t *)row[i + 1]) / 1000;
}
} }
} }
} }
...@@ -1139,12 +1145,16 @@ static uint32_t monBuildVgroupsInfoSql(char *sql, char *dbName) { ...@@ -1139,12 +1145,16 @@ static uint32_t monBuildVgroupsInfoSql(char *sql, char *dbName) {
pos += snprintf(sql, SQL_LENGTH, "insert into %s.vgroup_%d values(%" PRId64 ", "SQL_STR_FMT, pos += snprintf(sql, SQL_LENGTH, "insert into %s.vgroup_%d values(%" PRId64 ", "SQL_STR_FMT,
tsMonitorDbName, vgId, ts, dbName); tsMonitorDbName, vgId, ts, dbName);
} else { } else {
return TSDB_CODE_SUCCESS; goto DONE;
} }
} else if (strcmp(fields[i].name, "tables") == 0) { } else if (strcmp(fields[i].name, "tables") == 0) {
pos += snprintf(sql + pos, SQL_LENGTH, ", %d", *(int32_t *)row[i]); pos += snprintf(sql + pos, SQL_LENGTH, ", %d", *(int32_t *)row[i]);
} else if (strcmp(fields[i].name, "status") == 0) { } else if (strcmp(fields[i].name, "status") == 0) {
charLen = monGetRowElemCharLen(fields[i], (char *)row[i]); charLen = monGetRowElemCharLen(fields[i], (char *)row[i]);
if (charLen < 0) {
monError("failed to save vgroup_%d info, reason: invalid row %s len, sql:%s", vgId, (char *)row[i], tsMonitor.sql);
goto DONE;
}
pos += snprintf(sql + pos, strlen(SQL_STR_FMT) + charLen + 1, ", "SQL_STR_FMT, (char *)row[i]); pos += snprintf(sql + pos, strlen(SQL_STR_FMT) + charLen + 1, ", "SQL_STR_FMT, (char *)row[i]);
} else if (strcmp(fields[i].name, "onlines") == 0) { } else if (strcmp(fields[i].name, "onlines") == 0) {
pos += snprintf(sql + pos, SQL_LENGTH, ", %d", *(int32_t *)row[i]); pos += snprintf(sql + pos, SQL_LENGTH, ", %d", *(int32_t *)row[i]);
...@@ -1152,6 +1162,10 @@ static uint32_t monBuildVgroupsInfoSql(char *sql, char *dbName) { ...@@ -1152,6 +1162,10 @@ static uint32_t monBuildVgroupsInfoSql(char *sql, char *dbName) {
snprintf(v_dnode_ids, sizeof(v_dnode_ids), "%d;", *(int16_t *)row[i]); snprintf(v_dnode_ids, sizeof(v_dnode_ids), "%d;", *(int16_t *)row[i]);
} else if (v_dnode_str && strcmp(v_dnode_str, "_status") == 0) { } else if (v_dnode_str && strcmp(v_dnode_str, "_status") == 0) {
charLen = monGetRowElemCharLen(fields[i], (char *)row[i]); charLen = monGetRowElemCharLen(fields[i], (char *)row[i]);
if (charLen < 0) {
monError("failed to save vgroup_%d info, reason: invalid row %s len, sql:%s", vgId, (char *)row[i], tsMonitor.sql);
goto DONE;
}
snprintf(v_dnode_status, charLen + 1, "%s;", (char *)row[i]); snprintf(v_dnode_status, charLen + 1, "%s;", (char *)row[i]);
} else if (strcmp(fields[i].name, "compacting") == 0) { } else if (strcmp(fields[i].name, "compacting") == 0) {
//flush dnode_ids and dnode_role in to sql //flush dnode_ids and dnode_role in to sql
...@@ -1169,8 +1183,9 @@ static uint32_t monBuildVgroupsInfoSql(char *sql, char *dbName) { ...@@ -1169,8 +1183,9 @@ static uint32_t monBuildVgroupsInfoSql(char *sql, char *dbName) {
monDebug("successfully to save vgroup_%d info, sql:%s", vgId, tsMonitor.sql); monDebug("successfully to save vgroup_%d info, sql:%s", vgId, tsMonitor.sql);
} }
} }
taos_free_result(result);
DONE:
taos_free_result(result);
return TSDB_CODE_SUCCESS; return TSDB_CODE_SUCCESS;
} }
...@@ -1220,12 +1235,24 @@ static void monSaveSlowQueryInfo() { ...@@ -1220,12 +1235,24 @@ static void monSaveSlowQueryInfo() {
if (strcmp(fields[i].name, "query_id") == 0) { if (strcmp(fields[i].name, "query_id") == 0) {
has_slowquery = true; has_slowquery = true;
charLen = monGetRowElemCharLen(fields[i], (char *)row[i]); charLen = monGetRowElemCharLen(fields[i], (char *)row[i]);
if (charLen < 0) {
monError("failed to save slow_query info, reason: invalid row %s len, sql:%s", (char *)row[i], tsMonitor.sql);
goto DONE;
}
pos += snprintf(sql + pos, strlen(SQL_STR_FMT) + charLen + 1, ", "SQL_STR_FMT, (char *)row[i]); pos += snprintf(sql + pos, strlen(SQL_STR_FMT) + charLen + 1, ", "SQL_STR_FMT, (char *)row[i]);
} else if (strcmp(fields[i].name, "user") == 0) { } else if (strcmp(fields[i].name, "user") == 0) {
charLen = monGetRowElemCharLen(fields[i], (char *)row[i]); charLen = monGetRowElemCharLen(fields[i], (char *)row[i]);
if (charLen < 0) {
monError("failed to save slow_query info, reason: invalid row %s len, sql:%s", (char *)row[i], tsMonitor.sql);
goto DONE;
}
pos += snprintf(sql + pos, strlen(SQL_STR_FMT) + charLen + 1, ", "SQL_STR_FMT, (char *)row[i]); pos += snprintf(sql + pos, strlen(SQL_STR_FMT) + charLen + 1, ", "SQL_STR_FMT, (char *)row[i]);
} else if (strcmp(fields[i].name, "qid") == 0) { } else if (strcmp(fields[i].name, "qid") == 0) {
charLen = monGetRowElemCharLen(fields[i], (char *)row[i]); charLen = monGetRowElemCharLen(fields[i], (char *)row[i]);
if (charLen < 0) {
monError("failed to save slow_query info, reason: invalid row %s len, sql:%s", (char *)row[i], tsMonitor.sql);
goto DONE;
}
pos += snprintf(sql + pos, strlen(SQL_STR_FMT) + charLen + 1, ", "SQL_STR_FMT, (char *)row[i]); pos += snprintf(sql + pos, strlen(SQL_STR_FMT) + charLen + 1, ", "SQL_STR_FMT, (char *)row[i]);
} else if (strcmp(fields[i].name, "created_time") == 0) { } else if (strcmp(fields[i].name, "created_time") == 0) {
int64_t create_time = *(int64_t *)row[i]; int64_t create_time = *(int64_t *)row[i];
...@@ -1235,18 +1262,25 @@ static void monSaveSlowQueryInfo() { ...@@ -1235,18 +1262,25 @@ static void monSaveSlowQueryInfo() {
pos += snprintf(sql + pos, SQL_LENGTH, ", %" PRId64 "", *(int64_t *)row[i]); pos += snprintf(sql + pos, SQL_LENGTH, ", %" PRId64 "", *(int64_t *)row[i]);
} else if (strcmp(fields[i].name, "ep") == 0) { } else if (strcmp(fields[i].name, "ep") == 0) {
charLen = monGetRowElemCharLen(fields[i], (char *)row[i]); charLen = monGetRowElemCharLen(fields[i], (char *)row[i]);
if (charLen < 0) {
monError("failed to save slow_query info, reason: invalid row %s len, sql:%s", (char *)row[i], tsMonitor.sql);
goto DONE;
}
pos += snprintf(sql + pos, strlen(SQL_STR_FMT) + charLen + 1, ", "SQL_STR_FMT, (char *)row[i]); pos += snprintf(sql + pos, strlen(SQL_STR_FMT) + charLen + 1, ", "SQL_STR_FMT, (char *)row[i]);
} else if (strcmp(fields[i].name, "sql") == 0) { } else if (strcmp(fields[i].name, "sql") == 0) {
charLen = monGetRowElemCharLen(fields[i], (char *)row[i]); charLen = monGetRowElemCharLen(fields[i], (char *)row[i]);
if (charLen < 0) {
monError("failed to save slow_query info, reason: invalid row %s len, sql:%s", (char *)row[i], tsMonitor.sql);
goto DONE;
}
pos += snprintf(sql + pos, strlen(SQL_STR_FMT) + charLen + 2, ", "SQL_STR_FMT")", (char *)row[i]); pos += snprintf(sql + pos, strlen(SQL_STR_FMT) + charLen + 2, ", "SQL_STR_FMT")", (char *)row[i]);
} }
} }
} }
monDebug("save slow query, sql:%s", sql); monDebug("save slow query, sql:%s", sql);
taos_free_result(result);
if (!has_slowquery) { if (!has_slowquery) {
return; goto DONE;
} }
void *res = taos_query(tsMonitor.conn, tsMonitor.sql); void *res = taos_query(tsMonitor.conn, tsMonitor.sql);
code = taos_errno(res); code = taos_errno(res);
...@@ -1259,6 +1293,9 @@ static void monSaveSlowQueryInfo() { ...@@ -1259,6 +1293,9 @@ static void monSaveSlowQueryInfo() {
monDebug("successfully to save slowquery info, sql:%s", tsMonitor.sql); monDebug("successfully to save slowquery info, sql:%s", tsMonitor.sql);
} }
DONE:
taos_free_result(result);
return;
} }
static void monSaveDisksInfo() { static void monSaveDisksInfo() {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册