Merge branch '3.0' into fix/3_liaohj
|
@ -63,7 +63,7 @@ toc_max_heading_level: 4
|
|||
|
||||
1. 数据库(Database):数据库提供时序数据的高效存储和读取能力。在工业、物联网场景,由设备所产生的时序数据量是十分惊人的。从存储数据的角度来说,数据库需要把这些数据持久化到硬盘上并最大程度地压缩,从而降低存储成本。从读取数据的角度来说,数据库需要保证实时查询,以及历史数据的查询效率。比较传统的存储方案是使用 MySql、Oracle 等关系型数据库,也有 Hadoop 体系的 HBase,专用的时序数据库则有 InfluxDB、OpenTSDB、Prometheus 等。
|
||||
|
||||
2. 数据订阅(Data Subscription):很多时序数据应用都需要在第一时间订阅到业务所需的实时数据,从而及时了解被监测对对象的最新状态,用 AI 或其他工具做实时的数据分析。同时,由于数据的隐私以及安全,你只能容许应用订阅他有权限访问的数据。因此,一个时序数据处理平台一定需要具备数据订阅的能力,帮助应用实时获取最新数据。
|
||||
2. 数据订阅(Data Subscription):很多时序数据应用都需要在第一时间订阅到业务所需的实时数据,从而及时了解被监测对对象的最新状态,用 AI 或其他工具做实时的数据分析。同时,由于数据的隐私以及安全,你只能允许应用订阅他有权限访问的数据。因此,一个时序数据处理平台一定需要具备数据订阅的能力,帮助应用实时获取最新数据。
|
||||
|
||||
3. ETL(Extract, Transform, Load):在实际的物联网、工业场景中,时序数据的采集需要特定的 ETL 工具进行数据的提取、清洗和转换操作,才能把数据写入数据库中,以保证数据的质量。因为不同数据采集系统往往使用不同的标准,比如采集的温度的物理单位不一致,有的用摄氏度,有的用华氏度;系统之间所在的时区不一致,要进行转换;时间分辨率也可能不统一,因此这些从不同系统汇聚来的数据需要进行转换才能写入数据库。
|
||||
|
||||
|
@ -109,7 +109,7 @@ toc_max_heading_level: 4
|
|||
|
||||
5. 必须拥有高效的缓存功能:绝大部分场景,都需要能快速获取设备当前状态或其他信息,用以报警、大屏展示或其他。系统需要提供一高效机制,让用户可以获取全部、或符合过滤条件的部分设备的最新状态。
|
||||
|
||||
6. 必须拥有实时流式计算:各种实时预警或预测已经不是简单的基于某一个阈值进行,而是需要通过将一个或多个设备产生的数据流进行实时聚合计算,不只是基于一个时间点、而是基于一个时间窗口进行计算。不仅如此,计算的需求也相当复杂,因场景而异,应容许用户自定义函数进行计算。
|
||||
6. 必须拥有实时流式计算:各种实时预警或预测已经不是简单的基于某一个阈值进行,而是需要通过将一个或多个设备产生的数据流进行实时聚合计算,不只是基于一个时间点、而是基于一个时间窗口进行计算。不仅如此,计算的需求也相当复杂,因场景而异,应允许用户自定义函数进行计算。
|
||||
|
||||
7. 必须支持数据订阅:与通用大数据平台比较一致,同一组数据往往有很多应用都需要,因此系统应该提供订阅功能,只要有新的数据更新,就应该实时提醒应用。由于数据隐私和安全,而且这个订阅也应该是个性化的,只能订阅有权查看的数据,比如仅仅能订阅每小时的平均功率,而不能订阅原始的电流、电压值。
|
||||
|
||||
|
@ -119,7 +119,7 @@ toc_max_heading_level: 4
|
|||
|
||||
10. 必须支持灵活的多维度分析:对于联网设备产生的数据,需要进行各种维度的统计分析,比如从设备所处的地域进行分析,从设备的型号、供应商进行分析,从设备所使用的人员进行分析等等。而且这些维度的分析是无法事先想好的,是在实际运营过程中,根据业务发展的需求定下来的。因此时序大数据系统需要一个灵活的机制增加某个维度的分析。
|
||||
|
||||
11. 需要支持即席分析和查询。为提高大数据分析师的工作效率,系统应该提供一命令行工具或容许用户通过其他工具,执行 SQL 查询,而不是非要通过编程接口。查询分析的结果可以很方便的导出,再制作成各种图表。
|
||||
11. 需要支持即席分析和查询。为提高大数据分析师的工作效率,系统应该提供一命令行工具或允许用户通过其他工具,执行 SQL 查询,而不是非要通过编程接口。查询分析的结果可以很方便的导出,再制作成各种图表。
|
||||
|
||||
12. 必须支持数据降频、插值、特殊函数计算等操作。原始数据的采集频次可能很高,但具体分析往往不需要对原始数据执行,而是数据降频之后。系统需要提供高效的数据降频操作。设备是很难同步的,不同设备采集数据的时间点是很难对齐的,因此分析一个特定时间点的值,往往需要插值才能解决,系统需要提供线性插值、设置固定值等多种插值策略才行。工业互联网里,除通用的统计操作之外,往往还需要支持一些特殊函数,比如时间加权平均、累计求和、差值等。
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ toc_max_heading_level: 4
|
|||
|
||||
TDengine 是一个高性能、分布式的时序数据库。通过集成的缓存、数据订阅、流计算和数据清洗与转换等功能,TDengine 已经发展成为一个专为物联网、工业互联网、金融和 IT 运维等关键行业量身定制的时序大数据平台。该平台能够高效地汇聚、存储、分析、计算和分发来自海量数据采集点的大规模数据流,每日处理能力可达 TB 乃至 PB 级别。借助 TDengine,企业可以实现实时的业务监控和预警,进而发掘出有价值的商业洞察。
|
||||
|
||||
自 2019 年 7 月 以 来, 涛 思 数 据 陆 续 将 TDengine 的 不 同 版 本 开 源, 包 括 单 机版(2019 年 7 月)、集群版(2020 年 8 月)以及云原生版(2022 年 8 月)。开源之后,TDengine 迅速获得了全球开发者的关注,多次在 GitHub 网站全球趋势排行榜上位居榜首。截至编写本书时,TDengine 在 GitHub 网站上已积累近 2.3 万颗星,安装实例超过53 万个,覆盖 60 多个国家和地区,广泛应用于电力、石油、化工、新能源、智能制造、汽车、环境监测等行业或领域,赢得了全球开发者的广泛认可
|
||||
自 2019 年 7 月 以 来, 涛 思 数 据 陆 续 将 TDengine 的 不 同 版 本 开 源, 包 括 单 机版(2019 年 7 月)、集群版(2020 年 8 月)以及云原生版(2022 年 8 月)。开源之后,TDengine 迅速获得了全球开发者的关注,多次在 GitHub 网站全球趋势排行榜上位居榜首,最新的关注热度见[涛思数据首页](https://www.taosdata.com/)。
|
||||
|
||||
## TDengine 产品
|
||||
|
||||
|
@ -22,7 +22,7 @@ TDengine OSS 是一个开源的高性能时序数据库,与其他时序数据
|
|||
|
||||
TDengine 经过特别优化,以适应时间序列数据的独特需求,引入了“一个数据采集点一张表”和“超级表”的创新数据组织策略。这些策略背后的支撑是一个革命性的存储引擎,它极大地提升了数据处理的速度和效率,无论是在数据的写入、查询还是存储方面。接下来,逐一探索 TDengine 的众多功能,帮助您全面了解这个为高效处理时间序列数据而生的大数据平台。
|
||||
|
||||
1. 写入数据:TDengine 支持多种数据写入方式。首先,它完全兼容 SQL,允许用户使用标准的 SQL 语法进行数据写入。而且 TDengine 还支持无模式(Schemaless)写入,包括流行的 InfluxDB Line 协议、OpenTSDB 的 Telnet 和 JSON 协议,这些协议的加入使得数据的导入变得更加灵活和高效。更进一步,TDengine 与众多第三方工具实现了无缝集成,例如 Telegraf、Prometheus、EMQX、StatsD、collectd 和 HiveMQ 等。对于 TDengine Enterprise, TDengine 还提供了 MQTT、OPC-UA、OPC-DA、PI、Wonderware, Kafka 等连接器。这些工具通过简单的配置,无需一行代码,就可以将来自各种数据源的数据源源不断的写入数据库,极大地简化了数据收集和存储的过程。
|
||||
1. 写入数据:TDengine 支持多种数据写入方式。首先,它完全兼容 SQL,允许用户使用标准的 SQL 语法进行数据写入。而且 TDengine 还支持无模式(Schemaless)写入,包括流行的 InfluxDB Line 协议、OpenTSDB 的 Telnet 和 JSON 协议,这些协议的加入使得数据的导入变得更加灵活和高效。更进一步,TDengine 与众多第三方工具实现了无缝集成,例如 Telegraf、Prometheus、EMQX、StatsD、collectd 和 HiveMQ 等。在 TDengine Enterprise 中, 还提供了 MQTT、OPC-UA、OPC-DA、PI、Wonderware、Kafka、InfluxDB、OpenTSDB、MySQL、Oracle 和 SQL Server 等连接器。这些工具通过简单的配置,无需一行代码,就可以将来自各种数据源的数据源源不断的写入数据库,极大地简化了数据收集和存储的过程。
|
||||
|
||||
2. 查询数据:TDengine 提供标准的 SQL 查询语法,并针对时序数据和业务的特点优化和新增了许多语法和功能,例如降采样、插值、累计求和、时间加权平均、状态窗口、时间窗口、会话窗口、滑动窗口等。TDengine 还支持用户自定义函数(UDF)
|
||||
|
||||
|
@ -38,13 +38,11 @@ TDengine 经过特别优化,以适应时间序列数据的独特需求,引
|
|||
|
||||
8. 数据迁移:TDengine 提供了多种便捷的数据导入导出功能,包括脚本文件导入导出、数据文件导入导出、taosdump 工具导入导出等。企业版还支持边云协同、数据同步等场景,兼容多种数据源,如 AVEVA PI System 等。
|
||||
|
||||
9. 编程连接器:TDengine 提供不同语言的连接器,包括 C/C++、Java、Go、Node.js、Rust、Python、C#、R、PHP 等。而且 TDengine 支持 REST 接口,应用可以直接通过 HTTP POST 请求 BODY 中包含的 SQL 语句来操作数据库。
|
||||
9. 编程连接器:TDengine 提供不同语言的连接器,包括 C/C++、Java、Go、Node.js、Rust、Python、C#、R、PHP 等。这些连接器大多都支持原生连接和 WebSocket 两种连接方式。TDengine 也提供 REST 接口,任何语言的应用程序可以直接通过 HTTP 请求访问数据库。
|
||||
|
||||
10. 数据安全:TDengine 提供了丰富的用户管理和权限管理功能以控制不同用户对数据库和表的访问权限,提供了 IP 白名单功能以控制不同帐号只能从特定的服务器接入集群。TDengine 支持系统管理员对不同数据库按需加密,数据加密后对读写完全透明且对性能的影响很小。还提供了审计日志功能以记录系统中的敏感操作。
|
||||
|
||||
11. 编程连接器:TDengine 提供了丰富的编程语言连接器,包括 C/C++、Java、Go、Node.js、Rust、Python、C#、R、PHP 等,并支持 REST ful 接口,方便应用通过HTTP POST 请求操作数据库。
|
||||
|
||||
12. 常用工具:TDengine 还提供了交互式命令行程序(CLI),便于管理集群、检查系统状态、做即时查询。压力测试工具 taosBenchmark,用于测试 TDengine 的性能。TDengine 还提供了图形化管理界面,简化了操作和管理过程。
|
||||
11. 常用工具:TDengine 还提供了交互式命令行程序(CLI),便于管理集群、检查系统状态、做即时查询。压力测试工具 taosBenchmark,用于测试 TDengine 的性能。TDengine 还提供了图形化管理界面,简化了操作和管理过程。
|
||||
|
||||
## TDengine 与典型时序数据库的区别
|
||||
|
||||
|
|
|
@ -71,4 +71,54 @@ taos>
|
|||
|
||||
## 快速体验
|
||||
|
||||
想要快速体验 TDengine 的写入和查询能力,请参考[快速体验](../use)
|
||||
### 体验写入
|
||||
|
||||
taosBenchmark 是一个专为测试 TDengine 性能而设计的工具,它能够全面评估TDengine 在写入、查询和订阅等方面的功能表现。该工具能够模拟大量设备产生的数据,并允许用户灵活控制数据库、超级表、标签列的数量和类型、数据列的数量和类型、子表数量、每张子表的数据量、写入数据的时间间隔、工作线程数量以及是否写入乱序数据等策略。
|
||||
|
||||
启动 TDengine 的服务,在终端中执行如下命令
|
||||
|
||||
```shell
|
||||
taosBenchmark -y
|
||||
```
|
||||
|
||||
系统将自动在数据库 test 下创建一张名为 meters的超级表。这张超级表将包含 10 000 张子表,表名从 d0 到 d9999,每张表包含 10,000条记录。每条记录包含 ts(时间戳)、current(电流)、voltage(电压)和 phase(相位)4个字段。时间戳范围从“2017-07-14 10:40:00 000”到“2017-07-14 10:40:09 999”。每张表还带有 location 和 groupId 两个标签,其中,groupId 设置为 1 到 10,而 location 则设置为 California.Campbell、California.Cupertino 等城市信息。
|
||||
|
||||
执行该命令后,系统将迅速完成 1 亿条记录的写入过程。实际所需时间取决于硬件性能,但即便在普通 PC 服务器上,这个过程通常也只需要十几秒。
|
||||
|
||||
taosBenchmark 提供了丰富的选项,允许用户自定义测试参数,如表的数目、记录条数等。要查看详细的参数列表,请在终端中输入如下命令
|
||||
```shell
|
||||
taosBenchmark --help
|
||||
```
|
||||
|
||||
有关taosBenchmark 的详细使用方法,请参考[taosBenchmark 参考手册](../../reference/components/taosbenchmark)
|
||||
|
||||
### 体验查询
|
||||
|
||||
使用上述 taosBenchmark 插入数据后,可以在 TDengine CLI(taos)输入查询命令,体验查询速度。
|
||||
|
||||
1. 查询超级表 meters 下的记录总条数
|
||||
```shell
|
||||
SELECT COUNT(*) FROM test.meters;
|
||||
```
|
||||
|
||||
2. 查询 1 亿条记录的平均值、最大值、最小值
|
||||
```shell
|
||||
SELECT AVG(current), MAX(voltage), MIN(phase) FROM test.meters;
|
||||
```
|
||||
|
||||
3. 查询 location = "California.SanFrancisco" 的记录总条数
|
||||
```shell
|
||||
SELECT COUNT(*) FROM test.meters WHERE location = "California.SanFrancisco";
|
||||
```
|
||||
|
||||
4. 查询 groupId = 10 的所有记录的平均值、最大值、最小值
|
||||
```shell
|
||||
SELECT AVG(current), MAX(voltage), MIN(phase) FROM test.meters WHERE groupId = 10;
|
||||
```
|
||||
|
||||
5. 对表 d1001 按每 10 秒进行平均值、最大值和最小值聚合统计
|
||||
```shell
|
||||
SELECT _wstart, AVG(current), MAX(voltage), MIN(phase) FROM test.d1001 INTERVAL(10s);
|
||||
```
|
||||
|
||||
在上面的查询中,使用系统提供的伪列_wstart 来给出每个窗口的开始时间。
|
|
@ -267,4 +267,54 @@ Query OK, 2 row(s) in set (0.003128s)
|
|||
|
||||
## 快速体验
|
||||
|
||||
想要快速体验 TDengine 的写入和查询能力,请参考[快速体验](../use)
|
||||
### 体验写入
|
||||
|
||||
taosBenchmark 是一个专为测试 TDengine 性能而设计的工具,它能够全面评估TDengine 在写入、查询和订阅等方面的功能表现。该工具能够模拟大量设备产生的数据,并允许用户灵活控制数据库、超级表、标签列的数量和类型、数据列的数量和类型、子表数量、每张子表的数据量、写入数据的时间间隔、工作线程数量以及是否写入乱序数据等策略。
|
||||
|
||||
启动 TDengine 的服务,在终端中执行如下命令
|
||||
|
||||
```shell
|
||||
taosBenchmark -y
|
||||
```
|
||||
|
||||
系统将自动在数据库 test 下创建一张名为 meters的超级表。这张超级表将包含 10 000 张子表,表名从 d0 到 d9999,每张表包含 10,000条记录。每条记录包含 ts(时间戳)、current(电流)、voltage(电压)和 phase(相位)4个字段。时间戳范围从“2017-07-14 10:40:00 000”到“2017-07-14 10:40:09 999”。每张表还带有 location 和 groupId 两个标签,其中,groupId 设置为 1 到 10,而 location 则设置为 California.Campbell、California.Cupertino 等城市信息。
|
||||
|
||||
执行该命令后,系统将迅速完成 1 亿条记录的写入过程。实际所需时间取决于硬件性能,但即便在普通 PC 服务器上,这个过程通常也只需要十几秒。
|
||||
|
||||
taosBenchmark 提供了丰富的选项,允许用户自定义测试参数,如表的数目、记录条数等。要查看详细的参数列表,请在终端中输入如下命令
|
||||
```shell
|
||||
taosBenchmark --help
|
||||
```
|
||||
|
||||
有关taosBenchmark 的详细使用方法,请参考[taosBenchmark 参考手册](../../reference/components/taosbenchmark)
|
||||
|
||||
### 体验查询
|
||||
|
||||
使用上述 taosBenchmark 插入数据后,可以在 TDengine CLI(taos)输入查询命令,体验查询速度。
|
||||
|
||||
1. 查询超级表 meters 下的记录总条数
|
||||
```shell
|
||||
SELECT COUNT(*) FROM test.meters;
|
||||
```
|
||||
|
||||
2. 查询 1 亿条记录的平均值、最大值、最小值
|
||||
```shell
|
||||
SELECT AVG(current), MAX(voltage), MIN(phase) FROM test.meters;
|
||||
```
|
||||
|
||||
3. 查询 location = "California.SanFrancisco" 的记录总条数
|
||||
```shell
|
||||
SELECT COUNT(*) FROM test.meters WHERE location = "California.SanFrancisco";
|
||||
```
|
||||
|
||||
4. 查询 groupId = 10 的所有记录的平均值、最大值、最小值
|
||||
```shell
|
||||
SELECT AVG(current), MAX(voltage), MIN(phase) FROM test.meters WHERE groupId = 10;
|
||||
```
|
||||
|
||||
5. 对表 d1001 按每 10 秒进行平均值、最大值和最小值聚合统计
|
||||
```shell
|
||||
SELECT _wstart, AVG(current), MAX(voltage), MIN(phase) FROM test.d1001 INTERVAL(10s);
|
||||
```
|
||||
|
||||
在上面的查询中,使用系统提供的伪列_wstart 来给出每个窗口的开始时间。
|
|
@ -8,6 +8,10 @@ sidebar_label: 集群维护
|
|||
|
||||
本节介绍 TDengine Enterprise 中提供的高阶集群维护手段,能够使 TDengine 集群长期运行得更健壮和高效。
|
||||
|
||||
## 节点管理
|
||||
|
||||
如何管理集群节点请参考[节点管理](../../reference/taos-sql/node)
|
||||
|
||||
## 数据重整
|
||||
|
||||
TDengine 面向多种写入场景,而很多写入场景下,TDengine 的存储会导致数据存储的放大或数据文件的空洞等。这一方面影响数据的存储效率,另一方面也会影响查询效率。为了解决上述问题,TDengine 企业版提供了对数据的重整功能,即 DATA COMPACT 功能,将存储的数据文件重新整理,删除文件空洞和无效数据,提高数据的组织度,从而提高存储和查询的效率。数据重整功能在 3.0.3.0 版本第一次发布,此后又经过了多次迭代优化,建议使用最新版本。
|
||||
|
|
|
@ -6,22 +6,22 @@ toc_max_heading_level: 4
|
|||
|
||||
## UDF 简介
|
||||
|
||||
在某些应用场景中,应用逻辑需要的查询功能无法直接使用TDengine内置的函数来实现。TDengine允许编写用户自定义函数(UDF),以便解决特殊应用场景中的使用需求。UDF在集群中注册成功后,可以像系统内置函数一样在SQL中调用,就使用角度而言没有任何区别。UDF分为标量函数和聚合函数。标量函数对每行数据输出一个值,如求绝对值abs、正弦函数sin、字符串拼接函数concat等。聚合函数对多行数据输出一个值,如求平均数avg、取最大值max等。
|
||||
在某些应用场景中,应用逻辑需要的查询功能无法直接使用 TDengine 内置的函数来实现。TDengine 允许编写用户自定义函数(UDF),以便解决特殊应用场景中的使用需求。UDF 在集群中注册成功后,可以像系统内置函数一样在 SQ L中调用,就使用角度而言没有任何区别。UDF 分为标量函数和聚合函数。标量函数对每行数据输出一个值,如求绝对值(abs)、正弦函数(sin)、字符串拼接函数(concat)等。聚合函数对多行数据输出一个值,如求平均数(avg)、取最大值(max)等。
|
||||
|
||||
TDengine支持用C和Python两种编程语言编写UDF。C语言编写的UDF与内置函数的性能几乎相同,Python语言编写的UDF可以利用丰富的Python运算库。为了避免UDF执行中发生异常影响数据库服务,TDengine使用了进程分离技术,把UDF的执行放到另一个进程中完成,即使用户编写的UDF崩溃,也不会影响TDengine的正常运行。
|
||||
TDengine 支持用 C 和 Python 两种编程语言编写 UDF。C 语言编写的 UDF 与内置函数的性能几乎相同,Python 语言编写的 UDF 可以利用丰富的 Python 运算库。为了避免 UDF 执行中发生异常影响数据库服务,TDengine 使用了进程分离技术,把 UDF 的执行放到另一个进程中完成,即使用户编写的 UDF 崩溃,也不会影响 TDengine 的正常运行。
|
||||
|
||||
## 用 C 语言开发 UDF
|
||||
|
||||
使用 C 语言实现 UDF 时,需要实现规定的接口函数
|
||||
- 标量函数需要实现标量接口函数 scalarfn 。
|
||||
- 聚合函数需要实现聚合接口函数 aggfn_start , aggfn , aggfn_finish。
|
||||
- 如果需要初始化,实现 udf_init;如果需要清理工作,实现udf_destroy。
|
||||
- 聚合函数需要实现聚合接口函数 aggfn_start、aggfn、aggfn_finish。
|
||||
- 如果需要初始化,实现 udf_init;如果需要清理工作,实现 udf_destroy。
|
||||
|
||||
接口函数的名称是 UDF 名称,或者是 UDF 名称和特定后缀(`_start`, `_finish`, `_init`, `_destroy`)的连接。列表中的scalarfn,aggfn, udf需要替换成udf函数名。
|
||||
接口函数的名称是 UDF 名称,或者是 UDF 名称和特定后缀(`_start`、`_finish`、`_init`、`_destroy`)的连接。
|
||||
|
||||
### 接口定义
|
||||
|
||||
在TDengine中,UDF的接口函数名称可以是UDF名称,也可以是UDF名称和特定后缀(如_start、_finish、_init、_destroy)的连接。后面内容中描述的函数名称,例如scalarfn、aggfn,需要替换成UDF名称。。
|
||||
在 TDengine 中,UDF 的接口函数名称可以是 UDF 名称,也可以是 UDF 名称和特定后缀(如_start、_finish、_init、_destroy)的连接。后面内容中描述的函数名称,例如 scalarfn、aggfn,需要替换成 UDF 名称。
|
||||
|
||||
#### 标量函数接口
|
||||
|
||||
|
@ -37,11 +37,11 @@ int32_t scalarfn(SUdfDataBlock* inputDataBlock, SUdfColumn *resultColumn)
|
|||
#### 聚合函数接口
|
||||
|
||||
聚合函数是一种特殊的函数,用于对数据进行分组和计算,从而生成汇总信息。聚合函数的工作原理如下。
|
||||
- 初始化结果缓冲区:首先调用aggfn_start函数,生成一个结果缓冲区(result buffer),用于存储中间结果。
|
||||
- 初始化结果缓冲区:首先调用 aggfn_start 函数,生成一个结果缓冲区(result buffer),用于存储中间结果。
|
||||
- 分组数据:相关数据会被分为多个行数据块(row data block),每个行数据块包含一组具有相同分组键(grouping key)的数据。
|
||||
- 更新中间结果:对于每个数据块,调用aggfn函数更新中间结果。aggfn函数会根据聚合函数的类型(如sum、avg、count等)对数据进行相应的计算,并将计算结
|
||||
- 更新中间结果:对于每个数据块,调用 aggfn 函数更新中间结果。aggfn 函数会根据聚合函数的类型(如 sum、avg、count 等)对数据进行相应的计算,并将计算结
|
||||
果存储在结果缓冲区中。
|
||||
- 生成最终结果:在所有数据块的中间结果更新完成后,调用aggfn_finish函数从结果缓冲区中提取最终结果。最终结果通常只包含0条或1条数据,具体取决于聚
|
||||
- 生成最终结果:在所有数据块的中间结果更新完成后,调用 aggfn_finish 函数从结果缓冲区中提取最终结果。最终结果只包含 0 条或 1 条数据,具体取决于聚
|
||||
合函数的类型和输入数据。
|
||||
|
||||
聚合函数的接口函数原型如下。
|
||||
|
@ -52,8 +52,7 @@ int32_t aggfn(SUdfDataBlock* inputBlock, SUdfInterBuf *interBuf, SUdfInterBuf *n
|
|||
int32_t aggfn_finish(SUdfInterBuf* interBuf, SUdfInterBuf *result)
|
||||
```
|
||||
|
||||
|
||||
其中 aggfn 是函数名的占位符。首先调用aggfn_start生成结果buffer,然后相关的数据会被分为多个行数据块,对每个数据块调用 aggfn 用数据块更新中间结果,最后再调用 aggfn_finish 从中间结果产生最终结果,最终结果只能含 0 或 1 条结果数据。
|
||||
其中 aggfn 是函数名的占位符。首先调用 aggfn_start 生成结果 buffer,然后相关的数据会被分为多个行数据块,对每个数据块调用 aggfn 用数据块更新中间结果,最后再调用 aggfn_finish 从中间结果产生最终结果,最终结果只能含 0 或 1 条结果数据。
|
||||
|
||||
主要参数说明如下。
|
||||
- interBuf:中间结果缓存区。
|
||||
|
@ -61,29 +60,47 @@ int32_t aggfn_finish(SUdfInterBuf* interBuf, SUdfInterBuf *result)
|
|||
- newInterBuf:新的中间结果缓冲区。
|
||||
- result:最终结果。
|
||||
|
||||
|
||||
#### 初始化和销毁接口
|
||||
|
||||
初始化和销毁接口是标量函数和聚合函数共同使用的接口,相关API如下。
|
||||
初始化和销毁接口是标量函数和聚合函数共同使用的接口,相关 API 如下。
|
||||
|
||||
```c
|
||||
int32_t udf_init()
|
||||
int32_t udf_destroy()
|
||||
```
|
||||
|
||||
其中,udf_init函数完成初始化工作,udf_destroy函数完成清理工作。如果没有初始化工作,无须定义udf_init函数;如果没有清理工作,无须定义udf_destroy函数。
|
||||
其中,udf_init 函数完成初始化工作,udf_destroy 函数完成清理工作。如果没有初始化工作,无须定义 udf_init 函数;如果没有清理工作,无须定义 udf_destroy 函数。
|
||||
|
||||
### 标量函数模板
|
||||
|
||||
用C语言开发标量函数的模板如下。
|
||||
用 C 语言开发标量函数的模板如下。
|
||||
```c
|
||||
#include "taos.h"
|
||||
#include "taoserror.h"
|
||||
#include "taosudf.h"
|
||||
|
||||
// Initialization function. If no initialization, we can skip definition of it.
|
||||
// The initialization function shall be concatenation of the udf name and _init suffix
|
||||
// @return error number defined in taoserror.h
|
||||
int32_t scalarfn_init() {
|
||||
// initialization.
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
// Scalar function main computation function
|
||||
// @param inputDataBlock, input data block composed of multiple columns with each column defined by SUdfColumn
|
||||
// @param resultColumn, output column
|
||||
// @return error number defined in taoserror.h
|
||||
int32_t scalarfn(SUdfDataBlock* inputDataBlock, SUdfColumn* resultColumn) {
|
||||
// read data from inputDataBlock and process, then output to resultColumn.
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
// Cleanup function. If no cleanup related processing, we can skip definition of it.
|
||||
// The destroy function shall be concatenation of the udf name and _destroy suffix.
|
||||
// @return error number defined in taoserror.h
|
||||
int32_t scalarfn_destroy() {
|
||||
// clean up
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
```
|
||||
|
@ -91,53 +108,206 @@ int32_t scalarfn_destroy() {
|
|||
|
||||
用C语言开发聚合函数的模板如下。
|
||||
```c
|
||||
#include "taos.h"
|
||||
#include "taoserror.h"
|
||||
#include "taosudf.h"
|
||||
|
||||
// Initialization function. If no initialization, we can skip definition of it.
|
||||
// The initialization function shall be concatenation of the udf name and _init suffix
|
||||
// @return error number defined in taoserror.h
|
||||
int32_t aggfn_init() {
|
||||
// initialization.
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
// Aggregate start function. The intermediate value or the state(@interBuf) is initialized in this function.
|
||||
// The function name shall be concatenation of udf name and _start suffix
|
||||
// @param interbuf intermediate value to initialize
|
||||
// @return error number defined in taoserror.h
|
||||
int32_t aggfn_start(SUdfInterBuf* interBuf) {
|
||||
// initialize intermediate value in interBuf
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
// Aggregate reduce function. This function aggregate old state(@interbuf) and one data bock(inputBlock) and output a new state(@newInterBuf).
|
||||
// @param inputBlock input data block
|
||||
// @param interBuf old state
|
||||
// @param newInterBuf new state
|
||||
// @return error number defined in taoserror.h
|
||||
int32_t aggfn(SUdfDataBlock* inputBlock, SUdfInterBuf *interBuf, SUdfInterBuf *newInterBuf) {
|
||||
// read from inputBlock and interBuf and output to newInterBuf
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
// Aggregate function finish function. This function transforms the intermediate value(@interBuf) into the final output(@result).
|
||||
// The function name must be concatenation of aggfn and _finish suffix.
|
||||
// @interBuf : intermediate value
|
||||
// @result: final result
|
||||
// @return error number defined in taoserror.h
|
||||
int32_t int32_t aggfn_finish(SUdfInterBuf* interBuf, SUdfInterBuf *result) {
|
||||
// read data from inputDataBlock and process, then output to result
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
|
||||
// Cleanup function. If no cleanup related processing, we can skip definition of it.
|
||||
// The destroy function shall be concatenation of the udf name and _destroy suffix.
|
||||
// @return error number defined in taoserror.h
|
||||
int32_t aggfn_destroy() {
|
||||
// clean up
|
||||
return TSDB_CODE_SUCCESS;
|
||||
}
|
||||
```
|
||||
|
||||
### 编译
|
||||
|
||||
在TDengine中,为了实现UDF,需要编写C语言源代码,并按照TDengine的规范编译为动态链接库文件。
|
||||
按照前面描述的规则,准备UDF的源代码bit_and.c。以Linux操作系统为例,执行如下指令,编译得到动态链接库文件。
|
||||
在 TDengine 中,为了实现 UDF,需要编写 C 语言源代码,并按照 TDengine 的规范编译为动态链接库文件。
|
||||
按照前面描述的规则,准备 UDF 的源代码 bit_and.c。以 Linux 操作系统为例,执行如下指令,编译得到动态链接库文件。
|
||||
```shell
|
||||
gcc-g-O0-fPIC-sharedbit_and.c-olibbitand.so
|
||||
gcc -g -O0 -fPIC -shared bit_and.c -o libbitand.so
|
||||
```
|
||||
|
||||
为了保证可靠运行,推荐使用7.5及以上版本的GCC。
|
||||
为了保证可靠运行,推荐使用 7.5 及以上版本的 GCC。
|
||||
|
||||
### C UDF 数据结构
|
||||
```c
|
||||
typedef struct SUdfColumnMeta {
|
||||
int16_t type;
|
||||
int32_t bytes;
|
||||
uint8_t precision;
|
||||
uint8_t scale;
|
||||
} SUdfColumnMeta;
|
||||
|
||||
typedef struct SUdfColumnData {
|
||||
int32_t numOfRows;
|
||||
int32_t rowsAlloc;
|
||||
union {
|
||||
struct {
|
||||
int32_t nullBitmapLen;
|
||||
char *nullBitmap;
|
||||
int32_t dataLen;
|
||||
char *data;
|
||||
} fixLenCol;
|
||||
|
||||
struct {
|
||||
int32_t varOffsetsLen;
|
||||
int32_t *varOffsets;
|
||||
int32_t payloadLen;
|
||||
char *payload;
|
||||
int32_t payloadAllocLen;
|
||||
} varLenCol;
|
||||
};
|
||||
} SUdfColumnData;
|
||||
|
||||
typedef struct SUdfColumn {
|
||||
SUdfColumnMeta colMeta;
|
||||
bool hasNull;
|
||||
SUdfColumnData colData;
|
||||
} SUdfColumn;
|
||||
|
||||
typedef struct SUdfDataBlock {
|
||||
int32_t numOfRows;
|
||||
int32_t numOfCols;
|
||||
SUdfColumn **udfCols;
|
||||
} SUdfDataBlock;
|
||||
|
||||
typedef struct SUdfInterBuf {
|
||||
int32_t bufLen;
|
||||
char *buf;
|
||||
int8_t numOfResult; //zero or one
|
||||
} SUdfInterBuf;
|
||||
```
|
||||
数据结构说明如下:
|
||||
|
||||
- SUdfDataBlock 数据块包含行数 numOfRows 和列数 numCols。udfCols[i] (0 \<= i \<= numCols-1)表示每一列数据,类型为SUdfColumn*。
|
||||
- SUdfColumn 包含列的数据类型定义 colMeta 和列的数据 colData。
|
||||
- SUdfColumnMeta 成员定义同 taos.h 数据类型定义。
|
||||
- SUdfColumnData 数据可以变长,varLenCol 定义变长数据,fixLenCol 定义定长数据。
|
||||
- SUdfInterBuf 定义中间结构 buffer,以及 buffer 中结果个数 numOfResult
|
||||
|
||||
为了更好的操作以上数据结构,提供了一些便利函数,定义在 taosudf.h。
|
||||
|
||||
|
||||
### C UDF 示例代码
|
||||
|
||||
#### 标量函数示例 [bit_and](https://github.com/taosdata/TDengine/blob/3.0/tests/script/sh/bit_and.c)
|
||||
|
||||
bit_add 实现多列的按位与功能。如果只有一列,返回这一列。bit_add 忽略空值。
|
||||
|
||||
<details>
|
||||
<summary>bit_and.c</summary>
|
||||
|
||||
```c
|
||||
{{#include tests/script/sh/bit_and.c}}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
#### 聚合函数示例1 返回值为数值类型 [l2norm](https://github.com/taosdata/TDengine/blob/3.0/tests/script/sh/l2norm.c)
|
||||
|
||||
l2norm 实现了输入列的所有数据的二阶范数,即对每个数据先平方,再累加求和,最后开方。
|
||||
|
||||
<details>
|
||||
<summary>l2norm.c</summary>
|
||||
|
||||
```c
|
||||
{{#include tests/script/sh/l2norm.c}}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
#### 聚合函数示例2 返回值为字符串类型 [max_vol](https://github.com/taosdata/TDengine/blob/3.0/tests/script/sh/max_vol.c)
|
||||
|
||||
max_vol 实现了从多个输入的电压列中找到最大电压,返回由设备 ID + 最大电压所在(行,列)+ 最大电压值 组成的组合字符串值
|
||||
|
||||
创建表:
|
||||
```bash
|
||||
create table battery(ts timestamp, vol1 float, vol2 float, vol3 float, deviceId varchar(16));
|
||||
```
|
||||
创建自定义函数:
|
||||
```bash
|
||||
create aggregate function max_vol as '/root/udf/libmaxvol.so' outputtype binary(64) bufsize 10240 language 'C';
|
||||
```
|
||||
使用自定义函数:
|
||||
```bash
|
||||
select max_vol(vol1, vol2, vol3, deviceid) from battery;
|
||||
```
|
||||
|
||||
<details>
|
||||
<summary>max_vol.c</summary>
|
||||
|
||||
```c
|
||||
{{#include tests/script/sh/max_vol.c}}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## 用 Python 语言开发 UDF
|
||||
|
||||
### 准备环境
|
||||
|
||||
准备环境的具体步骤如下:
|
||||
- 第1步,准备好Python运行环境。
|
||||
- 第2步,安装Python包taospyudf。命令如下。
|
||||
- 第1步,准备好 Python 运行环境。
|
||||
- 第2步,安装 Python 包 taospyudf。命令如下。
|
||||
```shell
|
||||
pip3 install taospyudf
|
||||
```
|
||||
- 第3步,执行命令ldconfig。
|
||||
- 第4步,启动taosd服务。
|
||||
- 第3步,执行命令 ldconfig。
|
||||
- 第4步,启动 taosd 服务。
|
||||
|
||||
安装过程中会编译 C++ 源码,因此系统上要有 cmake 和 gcc。编译生成的 libtaospyudf.so 文件自动会被复制到 /usr/local/lib/ 目录,因此如果是非 root 用户,安装时需加 sudo。安装完可以检查这个目录是否有了这个文件:
|
||||
|
||||
```shell
|
||||
root@slave11 ~/udf $ ls -l /usr/local/lib/libtaos*
|
||||
-rw-r--r-- 1 root root 671344 May 24 22:54 /usr/local/lib/libtaospyudf.so
|
||||
```
|
||||
|
||||
### 接口定义
|
||||
|
||||
当使用Python语言开发UDF时,需要实现规定的接口函数。具体要求如下。
|
||||
- 标量函数需要实现标量接口函数process。
|
||||
- 聚合函数需要实现聚合接口函数start、reduce、finish。
|
||||
- 如果需要初始化,则应实现函数init。
|
||||
- 如果需要清理工作,则实现函数destroy。
|
||||
当使用 Python 语言开发 UDF 时,需要实现规定的接口函数。具体要求如下。
|
||||
- 标量函数需要实现标量接口函数 process。
|
||||
- 聚合函数需要实现聚合接口函数 start、reduce、finish。
|
||||
- 如果需要初始化,则应实现函数 init。
|
||||
- 如果需要清理工作,则实现函数 destroy。
|
||||
|
||||
#### 标量函数接口
|
||||
|
||||
|
@ -147,7 +317,7 @@ def process(input: datablock) -> tuple[output_type]:
|
|||
```
|
||||
|
||||
主要参数说明如下:
|
||||
- input:datablock 类似二维矩阵,通过成员方法 data(row,col)返回位于 row 行,col 列的 python 对象
|
||||
- input:datablock 类似二维矩阵,通过成员方法 data(row, col) 读取位于 row 行、col 列的 python 对象
|
||||
- 返回值是一个 Python 对象元组,每个元素类型为输出类型。
|
||||
|
||||
#### 聚合函数接口
|
||||
|
@ -159,13 +329,13 @@ def reduce(inputs: datablock, buf: bytes) -> bytes
|
|||
def finish(buf: bytes) -> output_type:
|
||||
```
|
||||
|
||||
上述代码定义了3个函数,分别用于实现一个自定义的聚合函数。具体过程如下。
|
||||
上述代码定义了 3 个函数,分别用于实现一个自定义的聚合函数。具体过程如下。
|
||||
|
||||
首先,调用start函数生成最初的结果缓冲区。这个结果缓冲区用于存储聚合函数的内部状态,随着输入数据的处理而不断更新。
|
||||
首先,调用 start 函数生成最初的结果缓冲区。这个结果缓冲区用于存储聚合函数的内部状态,随着输入数据的处理而不断更新。
|
||||
|
||||
然后,输入数据会被分为多个行数据块。对于每个行数据块,调用reduce函数,并将当前行数据块(inputs)和当前的中间结果(buf)作为参数传递。reduce函数会根据输入数据和当前状态来更新聚合函数的内部状态,并返回新的中间结果
|
||||
然后,输入数据会被分为多个行数据块。对于每个行数据块,调用 reduce 函数,并将当前行数据块(inputs)和当前的中间结果(buf)作为参数传递。reduce 函数会根据输入数据和当前状态来更新聚合函数的内部状态,并返回新的中间结果。
|
||||
|
||||
最后,当所有行数据块都处理完毕后,调用finish函数。这个函数接收最终的中间结果(buf)作为参数,并从中生成最终的输出。由于聚合函数的特性,最终输出只能包含0条或1条数据。这个输出结果将作为聚合函数的计算结果返回给调用者。
|
||||
最后,当所有行数据块都处理完毕后,调用 finish 函数。这个函数接收最终的中间结果(buf)作为参数,并从中生成最终的输出。由于聚合函数的特性,最终输出只能包含 0 条或 1 条数据。这个输出结果将作为聚合函数的计算结果返回给调用者。
|
||||
|
||||
#### 初始化和销毁接口
|
||||
|
||||
|
@ -179,7 +349,7 @@ def destroy()
|
|||
- init 完成初始化工作
|
||||
- destroy 完成清理工作
|
||||
|
||||
**注意** 用Python开发UDF时必须定义init函数和destroy函数
|
||||
**注意** 用 Python 开发 UDF 时必须定义 init 函数和 destroy 函数
|
||||
|
||||
### 标量函数模板
|
||||
|
||||
|
@ -204,7 +374,7 @@ def start() -> bytes:
|
|||
def reduce(inputs: datablock, buf: bytes) -> bytes
|
||||
# deserialize buf to state
|
||||
# reduce the inputs and state into new_state.
|
||||
# use inputs.data(i,j) to access python object of location(i,j)
|
||||
# use inputs.data(i, j) to access python object of location(i, j)
|
||||
# serialize new_state into new_state_bytes
|
||||
return new_state_bytes
|
||||
def finish(buf: bytes) -> output_type:
|
||||
|
@ -217,13 +387,13 @@ def finish(buf: bytes) -> output_type:
|
|||
|
||||
| **TDengine SQL数据类型** | **Python数据类型** |
|
||||
| :-----------------------: | ------------ |
|
||||
|TINYINT / SMALLINT / INT / BIGINT | int |
|
||||
|TINYINT UNSIGNED / SMALLINT UNSIGNED / INT UNSIGNED / BIGINT UNSIGNED | int |
|
||||
|FLOAT / DOUBLE | float |
|
||||
|BOOL | bool |
|
||||
|BINARY / VARCHAR / NCHAR | bytes|
|
||||
|TIMESTAMP | int |
|
||||
|JSON and other types | 不支持 |
|
||||
| TINYINT / SMALLINT / INT / BIGINT | int |
|
||||
| TINYINT UNSIGNED / SMALLINT UNSIGNED / INT UNSIGNED / BIGINT UNSIGNED | int |
|
||||
| FLOAT / DOUBLE | float |
|
||||
| BOOL | bool |
|
||||
| BINARY / VARCHAR / NCHAR | bytes|
|
||||
| TIMESTAMP | int |
|
||||
| JSON and other types | 不支持 |
|
||||
|
||||
### 开发示例
|
||||
|
||||
|
@ -460,7 +630,7 @@ def process(block):
|
|||
for i in range(rows)]
|
||||
```
|
||||
|
||||
UDF 框架会将 TDengine 的 timestamp 类型映射为 Python 的 int 类型,所以这个函数只接受一个表示毫秒数的整数。process 方法先做参数检查,然后用 moment 包替换时间的星期为星期日,最后格式化输出。输出的字符串长度是固定的10个字符长,因此可以这样创建 UDF 函数:
|
||||
UDF 框架会将 TDengine 的 timestamp 类型映射为 Python 的 int 类型,所以这个函数只接受一个表示毫秒数的整数。process 方法先做参数检查,然后用 moment 包替换时间的星期为星期日,最后格式化输出。输出的字符串长度是固定的 10 个字符长,因此可以这样创建 UDF 函数:
|
||||
|
||||
```sql
|
||||
create function nextsunday as '/root/udf/nextsunday.py' outputtype binary(10) language 'Python';
|
||||
|
@ -627,39 +797,77 @@ close log file: spread.log
|
|||
|
||||
通过这个示例,我们学会了如何定义聚合函数,并打印自定义的日志信息。
|
||||
|
||||
### 更多 Python UDF 示例代码
|
||||
#### 标量函数示例 [pybitand](https://github.com/taosdata/TDengine/blob/3.0/tests/script/sh/pybitand.py)
|
||||
|
||||
pybitand 实现多列的按位与功能。如果只有一列,返回这一列。pybitand 忽略空值。
|
||||
|
||||
<details>
|
||||
<summary>pybitand.py</summary>
|
||||
|
||||
```Python
|
||||
{{#include tests/script/sh/pybitand.py}}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
#### 聚合函数示例 [pyl2norm](https://github.com/taosdata/TDengine/blob/3.0/tests/script/sh/pyl2norm.py)
|
||||
|
||||
pyl2norm 实现了输入列的所有数据的二阶范数,即对每个数据先平方,再累加求和,最后开方。
|
||||
|
||||
<details>
|
||||
<summary>pyl2norm.py</summary>
|
||||
|
||||
```c
|
||||
{{#include tests/script/sh/pyl2norm.py}}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
#### 聚合函数示例 [pycumsum](https://github.com/taosdata/TDengine/blob/3.0/tests/script/sh/pycumsum.py)
|
||||
|
||||
pycumsum 使用 numpy 计算输入列所有数据的累积和。
|
||||
<details>
|
||||
<summary>pycumsum.py</summary>
|
||||
|
||||
```c
|
||||
{{#include tests/script/sh/pycumsum.py}}
|
||||
```
|
||||
|
||||
</details>
|
||||
|
||||
## 管理 UDF
|
||||
|
||||
在集群中管理UDF的过程涉及创建、使用和维护这些函数。用户可以通过SQL在集群中创建和管理UDF,一旦创建成功,集群的所有用户都可以在SQL中使用这些函数。由于UDF存储在集群的mnode上,因此即使重启集群,已经创建的UDF也仍然可用。
|
||||
在集群中管理 UDF 的过程涉及创建、使用和维护这些函数。用户可以通过 SQL 在集群中创建和管理 UDF,一旦创建成功,集群的所有用户都可以在 SQL 中使用这些函数。由于 UDF 存储在集群的 mnode 上,因此即使重启集群,已经创建的 UDF 也仍然可用。
|
||||
|
||||
在创建UDF时,需要区分标量函数和聚合函数。标量函数接受零个或多个输入参数,并返回一个单一的值。聚合函数接受一组输入值,并通过对这些值进行某种计算(如求和、计数等)来返回一个单一的值。如果创建时声明了错误的函数类别,则通过SQL调用函数时会报错。
|
||||
在创建 UDF 时,需要区分标量函数和聚合函数。标量函数接受零个或多个输入参数,并返回一个单一的值。聚合函数接受一组输入值,并通过对这些值进行某种计算(如求和、计数等)来返回一个单一的值。如果创建时声明了错误的函数类别,则通过 SQL 调用函数时会报错。
|
||||
|
||||
此外,用户需要确保输入数据类型与UDF程序匹配,UDF输出的数据类型与outputtype匹配。这意味着在创建UDF时,需要为输入参数和输出值指定正确的数据类型。这有助于确保在调用UDF时,输入数据能够正确地传递给UDF,并且UDF的输出值与预期的数据类型相匹配。
|
||||
此外,用户需要确保输入数据类型与 UDF 程序匹配,UDF 输出的数据类型与 outputtype 匹配。这意味着在创建 UDF 时,需要为输入参数和输出值指定正确的数据类型。这有助于确保在调用 UDF 时,输入数据能够正确地传递给 UDF,并且 UDF 的输出值与预期的数据类型相匹配。
|
||||
|
||||
### 创建标量函数
|
||||
|
||||
创建标量函数的SQL语法如下。
|
||||
创建标量函数的 SQL 语法如下。
|
||||
```sql
|
||||
CREATE FUNCTION function_name AS library_path OUTPUTTYPE output_type LANGUAGE 'Python';
|
||||
CREATE OR REPLACE FUNCTION function_name AS library_path OUTPUTTYPE output_type LANGUAGE 'Python';
|
||||
```
|
||||
各参数说明如下。
|
||||
- or replace:如果函数已经存在,则会修改已有的函数属性。
|
||||
- function_name:标量函数在SQL中被调用时的函数名。
|
||||
- language:支持C语言和Python语言(3.7及以上版本),默认为C。
|
||||
- library_path:如果编程语言是C,则路径是包含UDF实现的动态链接库的库文件绝对路径,通常指向一个so文件。如果编程语言是Python,则路径是包含UDF
|
||||
实现的Python文件路径。路径需要用英文单引号或英文双引号括起来。
|
||||
- language:支持 C 语言和 Python 语言(3.7 及以上版本),默认为 C。
|
||||
- library_path:如果编程语言是 C,则路径是包含 UDF 实现的动态链接库的库文件绝对路径,通常指向一个 so 文件。如果编程语言是 Python,则路径是包含 UDF
|
||||
实现的 Python 文件路径。路径需要用英文单引号或英文双引号括起来。
|
||||
- output_type:函数计算结果的数据类型名称。
|
||||
|
||||
|
||||
### 创建聚合函数
|
||||
|
||||
创建聚合函数的SQL语法如下。
|
||||
创建聚合函数的 SQL 语法如下。
|
||||
```sql
|
||||
CREATE AGGREGATE FUNCTION function_name library_path OUTPUTTYPE output_type LANGUAGE 'Python';
|
||||
CREATE OR REPLACE AGGREGATE FUNCTION function_name library_path OUTPUTTYPE output_type LANGUAGE 'Python';
|
||||
```
|
||||
|
||||
其中,buffer_size 表示中间计算结果的缓冲区大小,单位是字节。其他参数的含义与标量函数相同。
|
||||
|
||||
如下SQL创建一个名为 l2norm 的UDF。
|
||||
如下 SQL 创建一个名为 l2norm 的 UDF。
|
||||
```sql
|
||||
CREATE AGGREGATE FUNCTION l2norm AS "/home/taos/udf_example/libl2norm.so" OUTPUTTYPE DOUBLE bufsize 8;
|
||||
```
|
||||
|
@ -673,8 +881,15 @@ DROP FUNCTION function_name;
|
|||
|
||||
### 查看 UDF
|
||||
|
||||
显示集群中当前可用的所有UDF的SQL如下。
|
||||
显示集群中当前可用的所有 UDF 的 SQL 如下。
|
||||
```sql
|
||||
show functions;
|
||||
```
|
||||
|
||||
### 查看函数信息
|
||||
|
||||
同名的 UDF 每更新一次,版本号会增加 1。
|
||||
```sql
|
||||
select * from ins_functions \G;
|
||||
```
|
||||
|
||||
|
|
|
@ -4,27 +4,27 @@ sidebar_label: taosExplorer
|
|||
toc_max_heading_level: 4
|
||||
---
|
||||
|
||||
taos-explorer 是一个为用户提供 TDengine 实例的可视化管理交互工具的 web 服务。本节主要讲述其安装和部署。它的各项功能都是基于简单易上手的图形界面,可以直接尝试,如果有需要也可以考高级功能和运维指南中的相关内容。
|
||||
taosExplorer 是一个为用户提供 TDengine 实例的可视化管理交互工具的 web 服务。本节主要讲述其安装和部署。它的各项功能都是基于简单易上手的图形界面,可以直接尝试,如果有需要也可以考高级功能和运维指南中的相关内容。
|
||||
|
||||
## 安装
|
||||
|
||||
taos-explorer 无需单独安装,从 TDengine 3.3.0.0 版本开始,它随着 TDengine Enterprise Server 安装包一起发布,安装完成后,就可以看到 `taos-explorer` 服务。
|
||||
taosEexplorer 无需单独安装,从 TDengine 3.3.0.0 版本开始,它随着 TDengine Enterprise Server 安装包一起发布,安装完成后,就可以看到 `taos-explorer` 服务。
|
||||
|
||||
## 配置
|
||||
|
||||
在启动 Explorer 之前,请确保配置文件中的内容正确。
|
||||
在启动 taosExplorer 之前,请确保配置文件中的内容正确。
|
||||
|
||||
```TOML
|
||||
# Explorer listen port
|
||||
# listen port
|
||||
port = 6060
|
||||
|
||||
# Explorer listen address for IPv4
|
||||
# listen address for IPv4
|
||||
addr = "0.0.0.0"
|
||||
|
||||
# Explorer listen address for IPv4
|
||||
# listen address for IPv4
|
||||
#ipv6 = "::1"
|
||||
|
||||
# Explorer log level. Possible: error,warn,info,debug,trace
|
||||
# log level. Possible: error,warn,info,debug,trace
|
||||
log_level = "info"
|
||||
|
||||
# taosAdapter address.
|
||||
|
@ -49,9 +49,9 @@ cors = false
|
|||
|
||||
说明:
|
||||
|
||||
- `port`:Explorer 服务绑定的端口。
|
||||
- `addr`:Explorer 服务绑定的 IPv4 地址,默认为 `0.0.0.0`。如需修改,请配置为 `localhost` 之外的地址以对外提供服务。
|
||||
- `ipv6`:Explorer 服务绑定的 IPv6 地址,默认不绑定 IPv6 地址。
|
||||
- `port`:taosExplorer 服务绑定的端口。
|
||||
- `addr`:taosExplorer 服务绑定的 IPv4 地址,默认为 `0.0.0.0`。如需修改,请配置为 `localhost` 之外的地址以对外提供服务。
|
||||
- `ipv6`:taosExplorer 服务绑定的 IPv6 地址,默认不绑定 IPv6 地址。
|
||||
- `log_level`:日志级别,可选值为 "error", "warn", "info", "debug", "trace"。
|
||||
- `cluster`:TDengine 集群的 taosAdapter 地址。
|
||||
- `x_api`:taosX 的 gRPC 地址。
|
||||
|
@ -62,7 +62,7 @@ cors = false
|
|||
|
||||
## 启动停止
|
||||
|
||||
然后启动 Explorer,可以直接在命令行执行 taos-explorer 或者使用 systemctl 命令:
|
||||
然后启动 taosExplorer,可以直接在命令行执行 taos-explorer 或者使用 systemctl 命令:
|
||||
|
||||
```bash
|
||||
systemctl start taos-explorer # Linux
|
||||
|
@ -78,7 +78,7 @@ sc.exe stop taos-explorer # Windows
|
|||
## 问题排查
|
||||
|
||||
1. 当通过浏览器打开 Explorer 站点遇到“无法访问此网站”的错误信息时,请通过命令行登录 taosExplorer 所在机器,并使用命令 `systemctl status taos-explorer` 检查服务的状态,如果返回的状态是 `inactive`,请使用命令`systemctl start taos-explorer` 启动服务。
|
||||
2. 如果需要获取 Explorer 的详细日志,可通过命令 `journalctl -u taos-explorer`。
|
||||
2. 如果需要获取 taosExplorer 的详细日志,可通过命令 `journalctl -u taos-explorer`。
|
||||
3. 当使用 Nginx 或其他工具进行转发时,注意进行 CORS 设置或在配置文件中使用 `cors = true`。
|
||||
|
||||
这是一个 Nginx 配置文件 CORS 设置的例子:
|
||||
|
|
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 104 KiB |
Before Width: | Height: | Size: 5.5 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 6.9 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 81 KiB |
Before Width: | Height: | Size: 7.1 KiB After Width: | Height: | Size: 32 KiB |
Before Width: | Height: | Size: 86 KiB After Width: | Height: | Size: 118 KiB |
Before Width: | Height: | Size: 78 KiB After Width: | Height: | Size: 70 KiB |
|
@ -7,80 +7,47 @@ toc_max_heading_level: 4
|
|||
import Tabs from '@theme/Tabs'
|
||||
import TabItem from '@theme/TabItem'
|
||||
|
||||
TDinsight 是使用监控数据库和 [Grafana] 对 TDengine 进行监控的解决方案。
|
||||
TDinsight 是使用 [Grafana] 对 TDengine 进行监控的解决方案。
|
||||
|
||||
TDengine 通过 taosKeeper 将服务器的 CPU、内存、硬盘空间、带宽、请求数、磁盘读写速度、慢查询等信息定时写入指定数据库,并对重要的系统操作(比如登录、创建、删除数据库等)以及各种错误报警信息进行记录。通过 [Grafana] 和 [TDengine 数据源插件](https://github.com/taosdata/grafanaplugin/releases),TDinsight 将集群状态、节点信息、插入及查询请求、资源使用情况等进行可视化展示,同时还支持 vnode、dnode、mnode 节点状态异常告警,为开发者实时监控 TDengine 集群运行状态提供了便利。本文将指导用户安装 Grafana 服务器并通过 `TDinsight.sh` 安装脚本自动安装 TDengine 数据源插件及部署 TDinsight 可视化面板。
|
||||
TDengine 通过 taosKeeper 将服务器的 CPU、内存、硬盘空间、带宽、请求数、磁盘读写速度、慢查询等信息定时写入指定数据库。通过 Grafana 和 TDengine 数据源插件,TDinsight 将集群状态、节点信息、插入及查询请求、资源使用情况等进行可视化展示,为开发者实时监控 TDengine 集群运行状态提供了便利。本文将指导用户安装 TDengine 数据源插件及部署 TDinsight 可视化面板。
|
||||
|
||||
## 系统要求
|
||||
## 前置条件
|
||||
|
||||
- 单节点的 TDengine 服务器或多节点的 [TDengine] 集群,以及一个[Grafana]服务器。此仪表盘需要 TDengine 3.0.0.0 及以上,并开启监控服务,具体配置请参考:[TDengine 监控配置](../../../operation/monitor)。
|
||||
首先检查下面服务:
|
||||
- TDengine 已经安装并正常运行,此仪表盘需要 TDengine 3.0.0.0 及以上,并开启监控上报配置,具体配置请参考:[TDengine 监控配置](../taosd/#监控相关)。
|
||||
- taosAdapter 已经安装并正常运行。具体细节请参考:[taosAdapter 使用手册](../taosadapter)
|
||||
- taosKeeper 已安装并正常运行。注意需要 taos.cfg 文件中打开 monitor 相关配置项,具体细节请参考:[taosKeeper 使用手册](../taoskeeper)
|
||||
- taosKeeper 已安装并正常运行。具体细节请参考:[taosKeeper 使用手册](../taoskeeper)
|
||||
|
||||
记录以下信息:
|
||||
然后记录以下信息:
|
||||
|
||||
- taosAdapter 集群 REST API 地址,如:`http://tdengine.local:6041`。
|
||||
- taosAdapter 集群 REST API 地址,如:`http://localhost:6041`。
|
||||
- taosAdapter 集群认证信息,可使用用户名及密码。
|
||||
- taosKeeper 记录监控指标的数据库名称。
|
||||
|
||||
## 安装 Grafana
|
||||
## 安装和启动 Grafana
|
||||
|
||||
我们建议在此处使用最新的[Grafana] 8 或 9 版本。您可以在任何[支持的操作系统](https://grafana.com/docs/grafana/latest/installation/requirements/#supported-operating-systems)中,按照 [Grafana 官方文档安装说明](https://grafana.com/docs/grafana/latest/installation/) 安装 [Grafana]。
|
||||
我们建议您使用最新的 Grafana 版本,TDInsight 支持 Grafana 7.5 及以上版本。您可以在任何[支持的操作系统](https://grafana.com/docs/grafana/latest/installation/requirements/#supported-operating-systems)中,按照 [Grafana 官方文档安装说明](https://grafana.com/docs/grafana/latest/installation/) 安装 Grafana。
|
||||
安装后请参考 [启动 Grafana](https://grafana.com/docs/grafana/latest/setup-grafana/start-restart-grafana/) 启动 Grafana 服务。
|
||||
|
||||
<Tabs defaultValue="debian" groupId="install">
|
||||
<TabItem value="debian" label="基于 Debian 或 Ubuntu 系统">
|
||||
安装完成后就可以在 Web 浏览器中打开 Grafana 网址,默认是:`http://localhost:3000`。 默认用户名/密码都是 `admin`。Grafana 会要求在首次登录后更改密码。
|
||||
|
||||
对于 Debian 或 Ubuntu 操作系统,建议使用 Grafana 镜像仓库。使用如下命令从零开始安装:
|
||||
:::info
|
||||
|
||||
```bash
|
||||
sudo apt-get install -y apt-transport-https
|
||||
sudo apt-get install -y software-properties-common wget
|
||||
wget -q -O - https://packages.grafana.com/gpg.key |\
|
||||
sudo apt-key add -
|
||||
echo "deb https://packages.grafana.com/oss/deb stable main" |\
|
||||
sudo tee -a /etc/apt/sources.list.d/grafana.list
|
||||
sudo apt-get update
|
||||
sudo apt-get install grafana
|
||||
```
|
||||
下文介绍中,都以 Grafana v11.0.0 版本为例,其他版本功能可能有差异,请参考 [Grafana 官网](https://grafana.com/docs/grafana/latest/)。
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="redhat" label="基于 CentOS / RHEL 系统">
|
||||
:::
|
||||
|
||||
您可以从官方 YUM 镜像仓库安装。
|
||||
## 安装 TDengine 数据源插件
|
||||
|
||||
```bash
|
||||
sudo tee /etc/yum.repos.d/grafana.repo << EOF
|
||||
[grafana]
|
||||
name=grafana
|
||||
baseurl=https://packages.grafana.com/oss/rpm
|
||||
repo_gpgcheck=1
|
||||
enabled=1
|
||||
gpgcheck=1
|
||||
gpgkey=https://packages.grafana.com/gpg.key
|
||||
sslverify=1
|
||||
sslcacert=/etc/pki/tls/certs/ca-bundle.crt
|
||||
EOF
|
||||
sudo yum install grafana
|
||||
```
|
||||
|
||||
或者用 RPM 安装:
|
||||
|
||||
```bash
|
||||
wget https://dl.grafana.com/oss/release/grafana-7.5.11-1.x86_64.rpm
|
||||
sudo yum install grafana-7.5.11-1.x86_64.rpm
|
||||
# or
|
||||
sudo yum install \
|
||||
https://dl.grafana.com/oss/release/grafana-7.5.11-1.x86_64.rpm
|
||||
```
|
||||
|
||||
</TabItem>
|
||||
|
||||
</Tabs>
|
||||
|
||||
### 安装 TDengine 数据源插件
|
||||
TDInsight 支持图形界面安装、手动安装和脚本安装三种安装方式,一般建议图形界面安装。对于 Grafana 8.5 以下版本可以使用手动安装和脚本安装方式。
|
||||
|
||||
<Tabs defaultValue="manual" groupId="deploy">
|
||||
<TabItem value="manual" label="手动设置 TDinsight">
|
||||
<TabItem value="gui" label="图形界面安装">
|
||||
|
||||
使用 Grafana 最新版本(8.5+),您可以在 Grafana 中[浏览和管理插件](https://grafana.com/docs/grafana/next/administration/plugin-management/#plugin-catalog)。在 Grafana 管理界面中的 **Configurations > Plugins** 页面直接搜索 `TDengine` 并按照提示安装。
|
||||
|
||||
</TabItem>
|
||||
<TabItem value="manual" label="手动安装">
|
||||
|
||||
从 GitHub 安装 TDengine 最新版数据源插件。
|
||||
|
||||
|
@ -108,9 +75,9 @@ allow_loading_unsigned_plugins = tdengine-datasource
|
|||
|
||||
</TabItem>
|
||||
|
||||
<TabItem value="auto" label="自动部署 TDinsight">
|
||||
<TabItem value="auto" label="脚本安装">
|
||||
|
||||
我们提供了一个自动化安装脚本 [`TDinsight.sh`](https://github.com/taosdata/grafanaplugin/releases/latest/download/TDinsight.sh) 脚本以便用户快速进行安装配置。
|
||||
我们提供了一个自动化安装脚本 [TDinsight.sh](https://github.com/taosdata/grafanaplugin/releases/latest/download/TDinsight.sh) 脚本以便用户快速进行安装配置。
|
||||
|
||||
您可以通过 `wget` 或其他工具下载该脚本:
|
||||
|
||||
|
@ -122,9 +89,154 @@ chmod +x TDinsight.sh
|
|||
|
||||
这个脚本会自动下载最新的[Grafana TDengine 数据源插件](https://github.com/taosdata/grafanaplugin/releases/latest) 和 [TDinsight 仪表盘](https://github.com/taosdata/grafanaplugin/blob/master/dashboards/TDinsightV3.json) ,将命令行选项中的可配置参数转为 [Grafana Provisioning](https://grafana.com/docs/grafana/latest/administration/provisioning/) 配置文件,以进行自动化部署及更新等操作。
|
||||
|
||||
假设您在同一台主机上使用 TDengine 和 Grafana 的默认服务。运行 `./TDinsight.sh` 并打开 Grafana 浏览器窗口就可以看到 TDinsight 仪表盘了。
|
||||
1. 假设您在同一台主机上使用 TDengine 和 Grafana 服务。 运行 `./TDinsight.sh` 并打开 Grafana 页面就可以看到 TDinsight 仪表盘了。
|
||||
2. 假设您在主机 `tdengine` 上启动 TDengine 数据库,taosAdapter 的 HTTP 监听端口为 `6041`,用户为 `root1`,密码为 `pass5ord`。执行脚本:`./TDinsight.sh -a http://tdengine:6041 -u root1 -p pass5ord`
|
||||
|
||||
下面是 TDinsight.sh 的用法说明:
|
||||
详细的使用方法请参考 [TDinsight.sh 详细说明](./#附录)
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
|
||||
## 添加 TDengine 数据源
|
||||
|
||||
安装完毕后, 点击 “Connections” -> “Data sources“, 然后选择 ”tdengine-datasource“,输入 TDengine 相关配置:
|
||||
- Host: TDengine 集群中提供 REST 服务的 IP 地址与端口号,默认 `http://localhost:6041`
|
||||
- User:TDengine 用户名。
|
||||
- Password:TDengine 用户密码。
|
||||
|
||||
点击 `Save & Test` 进行测试,成功会提示:`TDengine Data source is working`。
|
||||
|
||||
|
||||
## 导入 TDengine V3 仪表盘
|
||||
|
||||
在配置 TDengine 数据源界面,点击 “Dashboards” tab,再点击 ”import” 导入 ”TDengine for 3.x” 仪表盘。
|
||||
导入成功后可以进入这个 dashboard,在左上角 ”Log from“ 选项中选择 taosKeeper 中设置的记录监控指标的数据库就可以看到监控结果。
|
||||
|
||||
|
||||
## TDengine V3 仪表盘详情
|
||||
|
||||
TDinsight 仪表盘旨在提供 TDengine 相关资源的使用情况和状态,比如 dnodes、 mnodes、 vnodes 和数据库等。
|
||||
主要分为集群状态、DNodes 概述、MNode 概述、请求、数据库、DNode 资源使用情况和 taosAdapter 监控信息。下面我们分别详细介绍。
|
||||
|
||||
### 集群状态
|
||||
这部分指标包括集群当前信息和状态。
|
||||
|
||||

|
||||
|
||||
指标详情(从上到下,从左到右):
|
||||
|
||||
- **First EP**:当前 TDengine 集群中的`firstEp`设置。
|
||||
- **Version**:TDengine 服务器版本(master mnode)。
|
||||
- **Expire Time** - 企业版过期时间。
|
||||
- **Used Measuring Points** - 企业版已使用的测点数。
|
||||
- **Databases** - 数据库个数。
|
||||
- **Connections** - 当前连接个数。
|
||||
- **DNodes/MNodes/VGroups/VNodes**:每种资源的总数和存活数。
|
||||
- **DNodes/MNodes/VGroups/VNodes Alive Percent**:每种资源的存活数/总数的比例,启用告警规则,并在资源存活率(1 分钟内平均健康资源比例)不足 100%时触发。
|
||||
- **Measuring Points Used**:启用告警规则的测点数用量(社区版无数据,默认情况下是健康的)。
|
||||
|
||||
### DNodes 概述
|
||||
这部分指标包括集群 dnode 基本信息。
|
||||
|
||||

|
||||
|
||||
指标详情:
|
||||
- **DNodes Status**:`show dnodes` 的简单表格视图。
|
||||
- **DNodes Number**:DNodes 数量变化。
|
||||
|
||||
### MNode 概述
|
||||
这部分指标包括集群 mnode 基本信息。
|
||||
|
||||

|
||||
|
||||
指标详情:
|
||||
1. **MNodes Status**:`show mnodes` 的简单表格视图。
|
||||
2. **MNodes Number**:类似于`DNodes Number`,MNodes 数量变化。
|
||||
|
||||
### 请求统计
|
||||
这部分指标包括集群执行 sql 的统计指标。
|
||||
|
||||

|
||||
|
||||
指标详情:
|
||||
1. **Select Request**:select 请求数。
|
||||
2. **Delete Request**:delete 请求数。
|
||||
3. **Insert Request**:insert 请求数。
|
||||
4. **Inserted Rows**:实际插入行数。
|
||||
5. **Slow Sql**:慢查询数,可以在顶部分时长段过滤。
|
||||
|
||||
### 表统计
|
||||
|
||||
这部分指标包括集群中表的统计指标。
|
||||
|
||||

|
||||
|
||||
指标详情:
|
||||
1. **STables**:超级表数量。
|
||||
2. **Total Tables**:所有表数量。
|
||||
3. **Tables**:所有普通表数量随时间变化图。
|
||||
4. **Tables Number Foreach VGroups**:每个 VGroups 包含的表数量。
|
||||
|
||||
### DNode 资源使用情况
|
||||
|
||||
这部分指标包括集群所有数据节点资源使用情况展示,每个数据节点为一个 Row 进行展示。。
|
||||
|
||||

|
||||
|
||||
指标详情(从上到下,从左到右):
|
||||
|
||||
1. **Uptime**:从创建 dnode 开始经过的时间。
|
||||
2. **Has MNodes?**:当前 dnode 是否为 mnode。
|
||||
3. **CPU Cores**:CPU 核数。
|
||||
4. **VNodes Number**:当前 dnode 的 VNodes 数量。
|
||||
5. **VNodes Masters**:处于 master 角色的 vnode 数量。
|
||||
6. **Current CPU Usage of taosd**:taosd 进程的 CPU 使用率。
|
||||
7. **Current Memory Usage of taosd**:taosd 进程的内存使用情况。
|
||||
8. **Max Disk Used**:taosd 所有数据目录对应的最大磁盘使用率。
|
||||
9. **CPU Usage**:进程和系统 CPU 使用率。
|
||||
10. **RAM Usage**:RAM 使用指标时间序列视图。
|
||||
11. **Disk Used**:多级存储下每个级别使用的磁盘(默认为 level0 级)。
|
||||
12. **Disk IO**:磁盘 IO 速率。
|
||||
13. **Net IO**:网络 IO,除本机网络之外的总合网络 IO 速率。
|
||||
|
||||
|
||||
### taosAdapter 监控
|
||||
|
||||
这部分指标包括 taosAdapter rest 和 websocket 请求统计详情。
|
||||
|
||||

|
||||
|
||||
指标详情:
|
||||
|
||||
1. **Total**:总请求数
|
||||
2. **Successful**:总成功数
|
||||
3. **Failed**:总失败数
|
||||
4. **Queries**:总查询数
|
||||
5. **Writes**:总写入数
|
||||
6. **Other**:总其他请求数
|
||||
|
||||
还有上述分类的细分维度折线图。
|
||||
|
||||
## 升级
|
||||
下面三种方式都可以进行升级:
|
||||
- 用图形界面,若有新版本,可以在 ”TDengine Datasource“ 插件页面点击 update 升级。
|
||||
- 按照手动安装步骤自行安装新的 Grafana 插件和 Dashboard。
|
||||
- 通过重新运行 `TDinsight.sh` 脚本升级到最新的 Grafana 插件和 TDinsight Dashboard。
|
||||
|
||||
## 卸载
|
||||
针对不同的安装方式,卸载时:
|
||||
- 用图形界面,在 ”TDengine Datasource“ 插件页面点击 ”Uninstall“ 卸载。
|
||||
- 通过 `TDinsight.sh` 脚本安装的 TDinsight,可以使用命令行 `TDinsight.sh -R` 清理相关资源。
|
||||
- 手动安装的 TDinsight,要完全卸载,需要清理以下内容:
|
||||
1. Grafana 中的 TDinsight Dashboard。
|
||||
2. Grafana 中的 Data Source 数据源。
|
||||
3. 从插件安装目录删除 `tdengine-datasource` 插件。
|
||||
|
||||
## 附录
|
||||
|
||||
### TDinsight.sh 详细说明
|
||||
下面是 TDinsight.sh 的用法详细说明:
|
||||
|
||||
```text
|
||||
Usage:
|
||||
|
@ -189,211 +301,3 @@ sudo ./TDengine.sh -n TDengine-Env1 -a http://another:6041 -u root -p taosdata -
|
|||
请注意,配置数据源、通知 Channel 和仪表盘在前端是不可更改的。您应该再次通过此脚本更新配置或手动更改 `/etc/grafana/provisioning` 目录(这是 Grafana 的默认目录,根据需要使用`-P`选项更改)中的配置文件。
|
||||
|
||||
特别地,当您使用 Grafana Cloud 或其他组织时,`-O` 可用于设置组织 ID。 `-G` 可指定 Grafana 插件安装目录。 `-e` 参数将仪表盘设置为可编辑。
|
||||
|
||||
</TabItem>
|
||||
</Tabs>
|
||||
|
||||
### 启动 Grafana 服务
|
||||
|
||||
```bash
|
||||
sudo systemctl start grafana-server
|
||||
sudo systemctl enable grafana-server
|
||||
```
|
||||
|
||||
### 登录到 Grafana
|
||||
|
||||
在 Web 浏览器中打开默认的 Grafana 网址:`http://localhost:3000`。
|
||||
默认用户名/密码都是 `admin`。Grafana 会要求在首次登录后更改密码。
|
||||
|
||||
### 添加 TDengine 数据源
|
||||
|
||||
指向 **Configurations** -> **Data Sources** 菜单,然后点击 **Add data source** 按钮。
|
||||
|
||||

|
||||
|
||||
搜索并选择**TDengine**。
|
||||
|
||||

|
||||
|
||||
配置 TDengine 数据源。
|
||||
|
||||

|
||||
|
||||
保存并测试,正常情况下会报告 'TDengine Data source is working'。
|
||||
|
||||

|
||||
|
||||
|
||||
|
||||
### 导入仪表盘
|
||||
|
||||
在配置 TDengine 数据源界面,点击 **Dashboards** tab。
|
||||
|
||||

|
||||
|
||||
选择 `TDengine for 3.x`,并点击 `import`。
|
||||
|
||||
导入完成后,在搜索界面已经出现了 **TDinsight for 3.x** dashboard。
|
||||
|
||||

|
||||
|
||||
进入 TDinsight for 3.x dashboard 后,选择 taosKeeper 中设置的记录监控指标的数据库。
|
||||
|
||||

|
||||
|
||||
然后可以看到监控结果。
|
||||
|
||||
## TDinsight 仪表盘详细信息
|
||||
|
||||
TDinsight 仪表盘旨在提供 TDengine 相关资源的使用情况和状态,比如 dnodes、 mnodes、 vnodes 和数据库等。
|
||||
|
||||
指标详情如下:
|
||||
|
||||
### 集群状态
|
||||
|
||||

|
||||
|
||||
这部分包括集群当前信息和状态,告警信息也在此处(从左到右,从上到下)。
|
||||
|
||||
- **First EP**:当前 TDengine 集群中的`firstEp`设置。
|
||||
- **Version**:TDengine 服务器版本(master mnode)。
|
||||
- **Master Uptime**: 当前 Master MNode 被选举为 Master 后经过的时间。
|
||||
- **Expire Time** - 企业版过期时间。
|
||||
- **Used Measuring Points** - 企业版已使用的测点数。
|
||||
- **Databases** - 数据库个数。
|
||||
- **Connections** - 当前连接个数。
|
||||
- **DNodes/MNodes/VGroups/VNodes**:每种资源的总数和存活数。
|
||||
- **DNodes/MNodes/VGroups/VNodes Alive Percent**:每种资源的存活数/总数的比例,启用告警规则,并在资源存活率(1 分钟内平均健康资源比例)不足 100%时触发。
|
||||
- **Measuring Points Used**:启用告警规则的测点数用量(社区版无数据,默认情况下是健康的)。
|
||||
- **Grants Expire Time**:启用告警规则的企业版过期时间(社区版无数据,默认情况是健康的)。
|
||||
- **Error Rate**:启用警报的集群总合错误率(每秒平均错误数)。
|
||||
|
||||
### DNodes 状态
|
||||
|
||||

|
||||
|
||||
- **DNodes Status**:`show dnodes` 的简单表格视图。
|
||||
- **DNodes Lifetime**:从创建 dnode 开始经过的时间。
|
||||
- **DNodes Number**:DNodes 数量变化。
|
||||
|
||||
### MNode 概述
|
||||
|
||||

|
||||
|
||||
1. **MNodes Status**:`show mnodes` 的简单表格视图。
|
||||
2. **MNodes Number**:类似于`DNodes Number`,MNodes 数量变化。
|
||||
|
||||
### 请求
|
||||
|
||||

|
||||
|
||||
1. **Requests Rate(Inserts per Second)**:平均每秒插入次数。
|
||||
2. **Requests (Selects)**:查询请求数及变化率(count of second)。
|
||||
|
||||
### 数据库
|
||||
|
||||

|
||||
|
||||
数据库使用情况,对变量 `$database` 的每个值即每个数据库进行重复多行展示。
|
||||
|
||||
1. **STables**:超级表数量。
|
||||
2. **Total Tables**:所有表数量。
|
||||
3. **Tables**:所有普通表数量随时间变化图。
|
||||
4. **Tables Number Foreach VGroups**:每个 VGroups 包含的表数量。
|
||||
|
||||
### DNode 资源使用情况
|
||||
|
||||

|
||||
|
||||
数据节点资源使用情况展示,对变量 `$fqdn` 即每个数据节点进行重复多行展示。包括:
|
||||
|
||||
1. **Uptime**:从创建 dnode 开始经过的时间。
|
||||
2. **Has MNodes?**:当前 dnode 是否为 mnode。
|
||||
3. **CPU Cores**:CPU 核数。
|
||||
4. **VNodes Number**:当前 dnode 的 VNodes 数量。
|
||||
5. **VNodes Masters**:处于 master 角色的 vnode 数量。
|
||||
6. **Current CPU Usage of taosd**:taosd 进程的 CPU 使用率。
|
||||
7. **Current Memory Usage of taosd**:taosd 进程的内存使用情况。
|
||||
8. **Disk Used**:taosd 数据目录的总磁盘使用百分比。
|
||||
9. **CPU Usage**:进程和系统 CPU 使用率。
|
||||
10. **RAM Usage**:RAM 使用指标时间序列视图。
|
||||
11. **Disk Used**:多级存储下每个级别使用的磁盘(默认为 level0 级)。
|
||||
12. **Disk Increasing Rate per Minute**:每分钟磁盘用量增加或减少的百分比。
|
||||
13. **Disk IO**:磁盘 IO 速率。
|
||||
14. **Net IO**:网络 IO,除本机网络之外的总合网络 IO 速率。
|
||||
|
||||
### 登录历史
|
||||
|
||||

|
||||
|
||||
目前只报告每分钟登录次数。
|
||||
|
||||
### 监控 taosAdapter
|
||||
|
||||

|
||||
|
||||
支持监控 taosAdapter 请求统计和状态详情。包括:
|
||||
|
||||
1. **Http Request Total**: 请求总数。
|
||||
2. **Http Request Fail**: 请求总数。
|
||||
3. **CPU Used**: taosAdapter CPU 使用情况。
|
||||
4. **Memory Used**: taosAdapter 内存使用情况。
|
||||
5. **Http Request Inflight**: 即时处理请求数。
|
||||
6. **Http Status Code**: taosAdapter http 状态码。
|
||||
|
||||
## 升级
|
||||
|
||||
通过 `TDinsight.sh` 脚本安装的 TDinsight,可以通过重新运行该脚本就可以升级到最新的 Grafana 插件和 TDinsight Dashboard。
|
||||
|
||||
手动安装的情况下,可按照上述步骤自行安装新的 Grafana 插件和 Dashboard。
|
||||
|
||||
## 卸载
|
||||
|
||||
通过 `TDinsight.sh` 脚本安装的 TDinsight,可以使用命令行 `TDinsight.sh -R` 清理相关资源。
|
||||
|
||||
手动安装时,要完全卸载 TDinsight,需要清理以下内容:
|
||||
|
||||
1. Grafana 中的 TDinsight Dashboard。
|
||||
2. Grafana 中的 Data Source 数据源。
|
||||
3. 从插件安装目录删除 `tdengine-datasource` 插件。
|
||||
|
||||
## 整合的 Docker 示例
|
||||
|
||||
```bash
|
||||
git clone --depth 1 https://github.com/taosdata/grafanaplugin.git
|
||||
cd grafanaplugin
|
||||
```
|
||||
|
||||
根据需要在 `docker-compose.yml` 文件中修改:
|
||||
|
||||
```yaml
|
||||
version: '3.7'
|
||||
|
||||
services:
|
||||
grafana:
|
||||
image: grafana/grafana:7.5.10
|
||||
volumes:
|
||||
- ./dist:/var/lib/grafana/plugins/tdengine-datasource
|
||||
- ./grafana/grafana.ini:/etc/grafana/grafana.ini
|
||||
- ./grafana/provisioning/:/etc/grafana/provisioning/
|
||||
- grafana-data:/var/lib/grafana
|
||||
environment:
|
||||
TDENGINE_API: ${TDENGINE_API}
|
||||
TDENGINE_USER: ${TDENGINE_USER}
|
||||
TDENGINE_PASS: ${TDENGINE_PASS}
|
||||
ports:
|
||||
- 3000:3000
|
||||
volumes:
|
||||
grafana-data:
|
||||
```
|
||||
|
||||
替换`docker-compose.yml`中的环境变量或保存环境变量到`.env`文件,然后用`docker-compose up`启动 Grafana。`docker-compose` 工具的具体用法参见 [Docker Compose Reference](https://docs.docker.com/compose/)
|
||||
|
||||
```bash
|
||||
docker-compose up -d
|
||||
```
|
||||
|
||||
TDinsight 已经通过 Provisioning 部署完毕,请到 http://localhost:3000/d/tdinsight/ 查看仪表盘。
|
||||
|
||||
[grafana]: https://grafana.com
|
||||
[tdengine]: https://www.taosdata.com
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
---
|
||||
sidebar_label: 集群管理
|
||||
title: 集群管理
|
||||
description: 管理集群的 SQL 命令的详细解析
|
||||
sidebar_label: 节点管理
|
||||
title: 节点管理
|
||||
description: 管理集群节点的 SQL 命令的详细解析
|
||||
---
|
||||
|
||||
组成 TDengine 集群的物理实体是 dnode (data node 的缩写),它是一个运行在操作系统之上的进程。在 dnode 中可以建立负责时序数据存储的 vnode (virtual node),在多节点集群环境下当某个数据库的 replica 为 3 时,该数据库中的每个 vgroup 由 3 个 vnode 组成;当数据库的 replica 为 1 时,该数据库中的每个 vgroup 由 1 个 vnode 组成。如果要想配置某个数据库为多副本,则集群中的 dnode 数量至少为 3。在 dnode 还可以创建 mnode (management node),单个集群中最多可以创建三个 mnode。在 TDengine 3.0.0.0 中为了支持存算分离,引入了一种新的逻辑节点 qnode (query node),qnode 和 vnode 既可以共存在一个 dnode 中,也可以完全分离在不同的 dnode 上。
|
||||
|
|
|
@ -35,6 +35,7 @@ Websocket 连接支持所有能运行 Rust 的平台。
|
|||
|
||||
| Rust 连接器版本 | TDengine 版本 | 主要功能 |
|
||||
| :----------------: | :--------------: | :--------------------------------------------------: |
|
||||
| v0.12.3 | 3.3.0.0 or later | 优化了 Websocket 查询和插入性能,支持了 VARBINARY 和 GEOMETRY 类型 |
|
||||
| v0.12.0 | 3.2.3.0 or later | WS 支持压缩。 |
|
||||
| v0.11.0 | 3.2.0.0 | TMQ 功能优化。 |
|
||||
| v0.10.0 | 3.1.0.0 | WS endpoint 变更。 |
|
||||
|
@ -44,7 +45,6 @@ Websocket 连接支持所有能运行 Rust 的平台。
|
|||
| v0.7.6 | 3.0.3.0 | 支持在请求中使用 req_id。 |
|
||||
| v0.6.0 | 3.0.0.0 | 基础功能。 |
|
||||
|
||||
Rust 连接器仍然在快速开发中,1.0 之前无法保证其向后兼容。建议使用 3.0 版本以上的 TDengine,以避免已知问题。
|
||||
|
||||
## 处理错误
|
||||
|
||||
|
|
|
@ -41,12 +41,16 @@ Python 连接器的源码托管在 [GitHub](https://github.com/taosdata/taos-con
|
|||
|
||||
|Python Connector 版本|主要变化|
|
||||
|:-------------------:|:----:|
|
||||
|2.7.15|新增 VARBINARY 和 GEOMETRY 类型支持|
|
||||
|2.7.14|修复已知问题|
|
||||
|2.7.13|新增 tmq 同步提交 offset 接口|
|
||||
|2.7.12|1. 新增 varbinary 类型支持(STMT暂不支持 varbinary )<br/> 2. query 性能提升(感谢贡献者[hadrianl](https://github.com/taosdata/taos-connector-python/pull/209))|
|
||||
|2.7.9|数据订阅支持获取消费进度和重置消费进度|
|
||||
|2.7.8|新增 `execute_many`|
|
||||
|
||||
|Python Websocket Connector 版本|主要变化|
|
||||
|:----------------------------:|:-----:|
|
||||
|0.3.2|优化 Websocket sql 查询和插入性能,修改 readme 和 文档,修复已知问题|
|
||||
|0.2.9|已知问题修复|
|
||||
|0.2.5|1. 数据订阅支持获取消费进度和重置消费进度 <br/> 2. 支持 schemaless <br/> 3. 支持 STMT|
|
||||
|0.2.4|数据订阅新增取消订阅方法|
|
||||
|
|
|
@ -178,7 +178,7 @@ TDengine 集群可以容纳单个、多个甚至几千个数据节点。应用
|
|||
|
||||
TDengine 存储的数据包括采集的时序数据以及库、表相关的元数据、标签数据等,这些数据具体分为三部分:
|
||||
|
||||
- 时序数据:TDengine 的核心存储对象,存放于 vnode 里,由 data、head 和 last 三个文件组成,数据量大,查询量取决于应用场景。容许乱序写入,但暂时不支持删除操作,并且仅在 update 参数设置为 1 时允许更新操作。通过采用一个采集点一张表的模型,一个时间段的数据是连续存储,对单张表的写入是简单的追加操作,一次读,可以读到多条记录,这样保证对单个采集点的插入和查询操作,性能达到最优。
|
||||
- 时序数据:TDengine 的核心存储对象,存放于 vnode 里,由 data、head 和 last 三个文件组成,数据量大,查询量取决于应用场景。允许乱序写入,但暂时不支持删除操作,并且仅在 update 参数设置为 1 时允许更新操作。通过采用一个采集点一张表的模型,一个时间段的数据是连续存储,对单张表的写入是简单的追加操作,一次读,可以读到多条记录,这样保证对单个采集点的插入和查询操作,性能达到最优。
|
||||
- 数据表元数据:包含标签信息和 Table Schema 信息,存放于 vnode 里的 meta 文件,支持增删改查四个标准操作。数据量很大,有 N 张表,就有 N 条记录,因此采用 LRU 存储,支持标签数据的索引。TDengine 支持多核多线程并发查询。只要计算内存足够,元数据全内存存储,千万级别规模的标签数据过滤结果能毫秒级返回。在内存资源不足的情况下,仍然可以支持数千万张表的快速查询。
|
||||
- 数据库元数据:存放于 mnode 里,包含系统节点、用户、DB、STable Schema 等信息,支持增删改查四个标准操作。这部分数据的量不大,可以全内存保存,而且由于客户端有缓存,查询量也不大。因此目前的设计虽是集中式存储管理,但不会构成性能瓶颈。
|
||||
|
Before Width: | Height: | Size: 319 KiB After Width: | Height: | Size: 319 KiB |
Before Width: | Height: | Size: 179 KiB After Width: | Height: | Size: 179 KiB |
Before Width: | Height: | Size: 117 KiB After Width: | Height: | Size: 117 KiB |
Before Width: | Height: | Size: 133 KiB After Width: | Height: | Size: 133 KiB |
Before Width: | Height: | Size: 476 KiB After Width: | Height: | Size: 476 KiB |
Before Width: | Height: | Size: 105 KiB After Width: | Height: | Size: 105 KiB |
Before Width: | Height: | Size: 359 KiB After Width: | Height: | Size: 359 KiB |
Before Width: | Height: | Size: 118 KiB After Width: | Height: | Size: 118 KiB |
Before Width: | Height: | Size: 52 KiB After Width: | Height: | Size: 52 KiB |
Before Width: | Height: | Size: 30 KiB After Width: | Height: | Size: 30 KiB |
Before Width: | Height: | Size: 96 KiB After Width: | Height: | Size: 96 KiB |
Before Width: | Height: | Size: 133 KiB After Width: | Height: | Size: 133 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 16 KiB |
Before Width: | Height: | Size: 163 KiB After Width: | Height: | Size: 163 KiB |
Before Width: | Height: | Size: 25 KiB After Width: | Height: | Size: 25 KiB |
Before Width: | Height: | Size: 192 KiB After Width: | Height: | Size: 192 KiB |
Before Width: | Height: | Size: 46 KiB After Width: | Height: | Size: 46 KiB |
Before Width: | Height: | Size: 232 KiB After Width: | Height: | Size: 232 KiB |
Before Width: | Height: | Size: 5.6 KiB After Width: | Height: | Size: 5.6 KiB |
Before Width: | Height: | Size: 19 KiB After Width: | Height: | Size: 19 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 75 KiB After Width: | Height: | Size: 75 KiB |
Before Width: | Height: | Size: 72 KiB After Width: | Height: | Size: 72 KiB |
Before Width: | Height: | Size: 231 KiB After Width: | Height: | Size: 231 KiB |
Before Width: | Height: | Size: 40 KiB After Width: | Height: | Size: 40 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 61 KiB After Width: | Height: | Size: 61 KiB |
Before Width: | Height: | Size: 56 KiB After Width: | Height: | Size: 56 KiB |
Before Width: | Height: | Size: 215 KiB After Width: | Height: | Size: 215 KiB |
Before Width: | Height: | Size: 194 KiB After Width: | Height: | Size: 194 KiB |
Before Width: | Height: | Size: 106 KiB After Width: | Height: | Size: 106 KiB |
Before Width: | Height: | Size: 155 KiB After Width: | Height: | Size: 155 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 27 KiB After Width: | Height: | Size: 27 KiB |
|
@ -25,9 +25,9 @@ extern "C" {
|
|||
#include "tarray.h"
|
||||
#include "thash.h"
|
||||
#include "tlog.h"
|
||||
#include "tsimplehash.h"
|
||||
#include "tmsg.h"
|
||||
#include "tmsgcb.h"
|
||||
#include "tsimplehash.h"
|
||||
|
||||
typedef enum {
|
||||
JOB_TASK_STATUS_NULL = 0,
|
||||
|
@ -69,16 +69,16 @@ typedef enum {
|
|||
#define QUERY_MSG_MASK_SHOW_REWRITE() (1 << 0)
|
||||
#define QUERY_MSG_MASK_AUDIT() (1 << 1)
|
||||
#define QUERY_MSG_MASK_VIEW() (1 << 2)
|
||||
#define TEST_SHOW_REWRITE_MASK(m) (((m) & QUERY_MSG_MASK_SHOW_REWRITE()) != 0)
|
||||
#define TEST_AUDIT_MASK(m) (((m) & QUERY_MSG_MASK_AUDIT()) != 0)
|
||||
#define TEST_VIEW_MASK(m) (((m) & QUERY_MSG_MASK_VIEW()) != 0)
|
||||
#define TEST_SHOW_REWRITE_MASK(m) (((m)&QUERY_MSG_MASK_SHOW_REWRITE()) != 0)
|
||||
#define TEST_AUDIT_MASK(m) (((m)&QUERY_MSG_MASK_AUDIT()) != 0)
|
||||
#define TEST_VIEW_MASK(m) (((m)&QUERY_MSG_MASK_VIEW()) != 0)
|
||||
|
||||
typedef struct STableComInfo {
|
||||
uint8_t numOfTags; // the number of tags in schema
|
||||
uint8_t precision; // the number of precision
|
||||
col_id_t numOfColumns; // the number of columns
|
||||
int16_t numOfPKs;
|
||||
int32_t rowSize; // row size of the schema
|
||||
int32_t rowSize; // row size of the schema
|
||||
} STableComInfo;
|
||||
|
||||
typedef struct SIndexMeta {
|
||||
|
@ -119,8 +119,9 @@ typedef struct STableMeta {
|
|||
int32_t sversion;
|
||||
int32_t tversion;
|
||||
STableComInfo tableInfo;
|
||||
SSchemaExt* schemaExt; // There is no additional memory allocation, and the pointer is fixed to the next address of the schema content.
|
||||
SSchema schema[];
|
||||
SSchemaExt* schemaExt; // There is no additional memory allocation, and the pointer is fixed to the next address of
|
||||
// the schema content.
|
||||
SSchema schema[];
|
||||
} STableMeta;
|
||||
#pragma pack(pop)
|
||||
|
||||
|
@ -196,9 +197,9 @@ typedef struct SBoundColInfo {
|
|||
} SBoundColInfo;
|
||||
|
||||
typedef struct STableColsData {
|
||||
char tbName[TSDB_TABLE_NAME_LEN];
|
||||
SArray* aCol;
|
||||
bool getFromHash;
|
||||
char tbName[TSDB_TABLE_NAME_LEN];
|
||||
SArray* aCol;
|
||||
bool getFromHash;
|
||||
} STableColsData;
|
||||
|
||||
typedef struct STableVgUid {
|
||||
|
@ -207,15 +208,14 @@ typedef struct STableVgUid {
|
|||
} STableVgUid;
|
||||
|
||||
typedef struct STableBufInfo {
|
||||
void* pCurBuff;
|
||||
SArray* pBufList;
|
||||
int64_t buffUnit;
|
||||
int64_t buffSize;
|
||||
int64_t buffIdx;
|
||||
int64_t buffOffset;
|
||||
void* pCurBuff;
|
||||
SArray* pBufList;
|
||||
int64_t buffUnit;
|
||||
int64_t buffSize;
|
||||
int64_t buffIdx;
|
||||
int64_t buffOffset;
|
||||
} STableBufInfo;
|
||||
|
||||
|
||||
typedef struct STableDataCxt {
|
||||
STableMeta* pMeta;
|
||||
STSchema* pSchema;
|
||||
|
@ -237,23 +237,22 @@ typedef struct SStbInterlaceInfo {
|
|||
void* pRequest;
|
||||
uint64_t requestId;
|
||||
int64_t requestSelf;
|
||||
bool tbFromHash;
|
||||
bool tbFromHash;
|
||||
SHashObj* pVgroupHash;
|
||||
SArray* pVgroupList;
|
||||
SSHashObj* pTableHash;
|
||||
int64_t tbRemainNum;
|
||||
STableBufInfo tbBuf;
|
||||
char firstName[TSDB_TABLE_NAME_LEN];
|
||||
STSchema *pTSchema;
|
||||
STableDataCxt *pDataCtx;
|
||||
void *boundTags;
|
||||
STSchema* pTSchema;
|
||||
STableDataCxt* pDataCtx;
|
||||
void* boundTags;
|
||||
|
||||
bool tableColsReady;
|
||||
SArray *pTableCols;
|
||||
int32_t pTableColsIdx;
|
||||
bool tableColsReady;
|
||||
SArray* pTableCols;
|
||||
int32_t pTableColsIdx;
|
||||
} SStbInterlaceInfo;
|
||||
|
||||
|
||||
typedef int32_t (*__async_send_cb_fn_t)(void* param, SDataBuf* pMsg, int32_t code);
|
||||
typedef int32_t (*__async_exec_fn_t)(void* param);
|
||||
|
||||
|
@ -308,6 +307,8 @@ void destroyAhandle(void* ahandle);
|
|||
int32_t asyncSendMsgToServerExt(void* pTransporter, SEpSet* epSet, int64_t* pTransporterId, SMsgSendInfo* pInfo,
|
||||
bool persistHandle, void* ctx);
|
||||
|
||||
int32_t asyncFreeConnById(void* pTransporter, int64_t pid);
|
||||
;
|
||||
/**
|
||||
* Asynchronously send message to server, after the response received, the callback will be incured.
|
||||
*
|
||||
|
@ -325,7 +326,7 @@ void initQueryModuleMsgHandle();
|
|||
|
||||
const SSchema* tGetTbnameColumnSchema();
|
||||
bool tIsValidSchema(struct SSchema* pSchema, int32_t numOfCols, int32_t numOfTags);
|
||||
int32_t getAsofJoinReverseOp(EOperatorType op);
|
||||
int32_t getAsofJoinReverseOp(EOperatorType op);
|
||||
|
||||
int32_t queryCreateCTableMetaFromMsg(STableMetaRsp* msg, SCTableMeta* pMeta);
|
||||
int32_t queryCreateTableMetaFromMsg(STableMetaRsp* msg, bool isSuperTable, STableMeta** pMeta);
|
||||
|
@ -384,7 +385,7 @@ extern int32_t (*queryProcessMsgRsp[TDMT_MAX])(void* output, char* msg, int32_t
|
|||
|
||||
#define NEED_CLIENT_RM_TBLMETA_REQ(_type) \
|
||||
((_type) == TDMT_VND_CREATE_TABLE || (_type) == TDMT_MND_CREATE_STB || (_type) == TDMT_VND_DROP_TABLE || \
|
||||
(_type) == TDMT_MND_DROP_STB || (_type) == TDMT_MND_CREATE_VIEW || (_type) == TDMT_MND_DROP_VIEW || \
|
||||
(_type) == TDMT_MND_DROP_STB || (_type) == TDMT_MND_CREATE_VIEW || (_type) == TDMT_MND_DROP_VIEW || \
|
||||
(_type) == TDMT_MND_CREATE_TSMA || (_type) == TDMT_MND_DROP_TSMA || (_type) == TDMT_MND_DROP_TB_WITH_TSMA)
|
||||
|
||||
#define NEED_SCHEDULER_REDIRECT_ERROR(_code) \
|
||||
|
|
|
@ -125,6 +125,7 @@ typedef struct SRpcInit {
|
|||
int32_t timeToGetConn;
|
||||
int8_t supportBatch; // 0: no batch, 1. batch
|
||||
int32_t batchSize;
|
||||
int8_t notWaitAvaliableConn; // 1: wait to get, 0: no wait
|
||||
void *parent;
|
||||
} SRpcInit;
|
||||
|
||||
|
@ -158,18 +159,21 @@ void *rpcReallocCont(void *ptr, int64_t contLen);
|
|||
// Because taosd supports multi-process mode
|
||||
// These functions should not be used on the server side
|
||||
// Please use tmsg<xx> functions, which are defined in tmsgcb.h
|
||||
int rpcSendRequest(void *thandle, const SEpSet *pEpSet, SRpcMsg *pMsg, int64_t *rid);
|
||||
int rpcSendResponse(const SRpcMsg *pMsg);
|
||||
int rpcRegisterBrokenLinkArg(SRpcMsg *msg);
|
||||
int rpcReleaseHandle(void *handle, int8_t type); // just release conn to rpc instance, no close sock
|
||||
int32_t rpcSendRequest(void *thandle, const SEpSet *pEpSet, SRpcMsg *pMsg, int64_t *rid);
|
||||
int32_t rpcSendResponse(const SRpcMsg *pMsg);
|
||||
int32_t rpcRegisterBrokenLinkArg(SRpcMsg *msg);
|
||||
int32_t rpcReleaseHandle(void *handle, int8_t type); // just release conn to rpc instance, no close sock
|
||||
|
||||
// These functions will not be called in the child process
|
||||
int rpcSendRequestWithCtx(void *thandle, const SEpSet *pEpSet, SRpcMsg *pMsg, int64_t *rid, SRpcCtx *ctx);
|
||||
int rpcSendRecv(void *shandle, SEpSet *pEpSet, SRpcMsg *pReq, SRpcMsg *pRsp);
|
||||
int rpcSendRecvWithTimeout(void *shandle, SEpSet *pEpSet, SRpcMsg *pMsg, SRpcMsg *pRsp, int8_t *epUpdated,
|
||||
int32_t rpcSendRequestWithCtx(void *thandle, const SEpSet *pEpSet, SRpcMsg *pMsg, int64_t *rid, SRpcCtx *ctx);
|
||||
int32_t rpcSendRecv(void *shandle, SEpSet *pEpSet, SRpcMsg *pReq, SRpcMsg *pRsp);
|
||||
int32_t rpcSendRecvWithTimeout(void *shandle, SEpSet *pEpSet, SRpcMsg *pMsg, SRpcMsg *pRsp, int8_t *epUpdated,
|
||||
int32_t timeoutMs);
|
||||
int rpcSetDefaultAddr(void *thandle, const char *ip, const char *fqdn);
|
||||
void *rpcAllocHandle();
|
||||
|
||||
int32_t rpcFreeConnById(void *shandle, int64_t connId);
|
||||
|
||||
int32_t rpcSetDefaultAddr(void *thandle, const char *ip, const char *fqdn);
|
||||
int32_t rpcAllocHandle(int64_t *refId);
|
||||
int32_t rpcSetIpWhite(void *thandl, void *arg);
|
||||
|
||||
int32_t rpcUtilSIpRangeToStr(SIpV4Range *pRange, char *buf);
|
||||
|
|
|
@ -526,19 +526,17 @@ int32_t createRequest(uint64_t connId, int32_t type, int64_t reqid, SRequestObj
|
|||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
*pRequest = (SRequestObj *)taosMemoryCalloc(1, sizeof(SRequestObj));
|
||||
if (NULL == *pRequest) {
|
||||
return TSDB_CODE_OUT_OF_MEMORY;
|
||||
return terrno;
|
||||
}
|
||||
|
||||
STscObj *pTscObj = acquireTscObj(connId);
|
||||
if (pTscObj == NULL) {
|
||||
code = TSDB_CODE_TSC_DISCONNECTED;
|
||||
goto _return;
|
||||
TSC_ERR_JRET(terrno);
|
||||
}
|
||||
SSyncQueryParam *interParam = taosMemoryCalloc(1, sizeof(SSyncQueryParam));
|
||||
if (interParam == NULL) {
|
||||
releaseTscObj(connId);
|
||||
code = TSDB_CODE_OUT_OF_MEMORY;
|
||||
goto _return;
|
||||
TSC_ERR_JRET(terrno);
|
||||
}
|
||||
TSC_ERR_JRET(tsem_init(&interParam->sem, 0, 0));
|
||||
interParam->pRequest = *pRequest;
|
||||
|
@ -566,7 +564,11 @@ int32_t createRequest(uint64_t connId, int32_t type, int64_t reqid, SRequestObj
|
|||
|
||||
return TSDB_CODE_SUCCESS;
|
||||
_return:
|
||||
doDestroyRequest(*pRequest);
|
||||
if ((*pRequest)->pTscObj) {
|
||||
doDestroyRequest(*pRequest);
|
||||
} else {
|
||||
taosMemoryFree(*pRequest);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
|
|
|
@ -387,6 +387,7 @@ int32_t dmInitClient(SDnode *pDnode) {
|
|||
rpcInit.supportBatch = 1;
|
||||
rpcInit.batchSize = 8 * 1024;
|
||||
rpcInit.timeToGetConn = tsTimeToGetAvailableConn;
|
||||
rpcInit.notWaitAvaliableConn = 1;
|
||||
|
||||
(void)taosVersionStrToInt(version, &(rpcInit.compatibilityVer));
|
||||
|
||||
|
|
|
@ -533,7 +533,7 @@ int32_t mndPersistTaskDeployReq(STrans *pTrans, SStreamTask *pTask) {
|
|||
return code;
|
||||
}
|
||||
|
||||
code = setTransAction(pTrans, buf, tlen, TDMT_STREAM_TASK_DEPLOY, &pTask->info.epSet, 0, 0);
|
||||
code = setTransAction(pTrans, buf, tlen, TDMT_STREAM_TASK_DEPLOY, &pTask->info.epSet, 0, TSDB_CODE_VND_INVALID_VGROUP_ID);
|
||||
if (code) {
|
||||
taosMemoryFree(buf);
|
||||
}
|
||||
|
|
|
@ -322,7 +322,7 @@ static int32_t doSetResumeAction(STrans *pTrans, SMnode *pMnode, SStreamTask *pT
|
|||
return terrno;
|
||||
}
|
||||
|
||||
code = setTransAction(pTrans, pReq, sizeof(SVResumeStreamTaskReq), TDMT_STREAM_TASK_RESUME, &epset, 0, 0);
|
||||
code = setTransAction(pTrans, pReq, sizeof(SVResumeStreamTaskReq), TDMT_STREAM_TASK_RESUME, &epset, 0, TSDB_CODE_VND_INVALID_VGROUP_ID);
|
||||
if (code != 0) {
|
||||
taosMemoryFree(pReq);
|
||||
return terrno;
|
||||
|
@ -426,7 +426,7 @@ static int32_t doSetPauseAction(SMnode *pMnode, STrans *pTrans, SStreamTask *pTa
|
|||
(void) epsetToStr(&epset, buf, tListLen(buf));
|
||||
mDebug("pause stream task in node:%d, epset:%s", pTask->info.nodeId, buf);
|
||||
|
||||
code = setTransAction(pTrans, pReq, sizeof(SVPauseStreamTaskReq), TDMT_STREAM_TASK_PAUSE, &epset, 0, 0);
|
||||
code = setTransAction(pTrans, pReq, sizeof(SVPauseStreamTaskReq), TDMT_STREAM_TASK_PAUSE, &epset, 0, TSDB_CODE_VND_INVALID_VGROUP_ID);
|
||||
if (code != 0) {
|
||||
taosMemoryFree(pReq);
|
||||
return code;
|
||||
|
@ -486,7 +486,7 @@ static int32_t doSetDropAction(SMnode *pMnode, STrans *pTrans, SStreamTask *pTas
|
|||
}
|
||||
|
||||
// The epset of nodeId of this task may have been expired now, let's use the newest epset from mnode.
|
||||
code = setTransAction(pTrans, pReq, sizeof(SVDropStreamTaskReq), TDMT_STREAM_TASK_DROP, &epset, 0, 0);
|
||||
code = setTransAction(pTrans, pReq, sizeof(SVDropStreamTaskReq), TDMT_STREAM_TASK_DROP, &epset, 0, TSDB_CODE_VND_INVALID_VGROUP_ID);
|
||||
if (code != 0) {
|
||||
taosMemoryFree(pReq);
|
||||
return code;
|
||||
|
@ -715,7 +715,7 @@ static int32_t doSetResetAction(SMnode *pMnode, STrans *pTrans, SStreamTask *pTa
|
|||
return code;
|
||||
}
|
||||
|
||||
code = setTransAction(pTrans, pReq, sizeof(SVResetStreamTaskReq), TDMT_VND_STREAM_TASK_RESET, &epset, 0, 0);
|
||||
code = setTransAction(pTrans, pReq, sizeof(SVResetStreamTaskReq), TDMT_VND_STREAM_TASK_RESET, &epset, 0, TSDB_CODE_VND_INVALID_VGROUP_ID);
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
taosMemoryFree(pReq);
|
||||
}
|
||||
|
|
|
@ -1372,7 +1372,7 @@ static int32_t buildResult(SSDataBlock *pBlock, int32_t *numOfRows, int64_t cons
|
|||
OffsetRows *tmp = taosArrayGet(offsetRows, i);
|
||||
MND_TMQ_NULL_CHECK(tmp);
|
||||
if (tmp->vgId != pVgEp->vgId) {
|
||||
mError("mnd show subscriptions: do not find vgId:%d, %d in offsetRows", tmp->vgId, pVgEp->vgId);
|
||||
mInfo("mnd show subscriptions: do not find vgId:%d, %d in offsetRows", tmp->vgId, pVgEp->vgId);
|
||||
continue;
|
||||
}
|
||||
data = tmp;
|
||||
|
@ -1396,7 +1396,7 @@ static int32_t buildResult(SSDataBlock *pBlock, int32_t *numOfRows, int64_t cons
|
|||
pColInfo = taosArrayGet(pBlock->pDataBlock, cols++);
|
||||
MND_TMQ_NULL_CHECK(pColInfo);
|
||||
colDataSetNULL(pColInfo, *numOfRows);
|
||||
mError("mnd show subscriptions: do not find vgId:%d in offsetRows", pVgEp->vgId);
|
||||
mInfo("mnd show subscriptions: do not find vgId:%d in offsetRows", pVgEp->vgId);
|
||||
}
|
||||
(*numOfRows)++;
|
||||
}
|
||||
|
|
|
@ -1677,7 +1677,7 @@ int32_t mndAcquireUser(SMnode *pMnode, const char *userName, SUserObj **ppUser)
|
|||
|
||||
*ppUser = sdbAcquire(pSdb, SDB_USER, userName);
|
||||
if (*ppUser == NULL) {
|
||||
if (code == TSDB_CODE_SDB_OBJ_NOT_THERE) {
|
||||
if (terrno == TSDB_CODE_SDB_OBJ_NOT_THERE) {
|
||||
code = TSDB_CODE_MND_USER_NOT_EXIST;
|
||||
} else {
|
||||
code = TSDB_CODE_MND_USER_NOT_AVAILABLE;
|
||||
|
@ -3149,7 +3149,8 @@ int32_t mndValidateUserAuthInfo(SMnode *pMnode, SUserAuthVersion *pUsers, int32_
|
|||
(void)memcpy(rsp.user, pUsers[i].user, TSDB_USER_LEN);
|
||||
(void)taosArrayPush(batchRsp.pArray, &rsp);
|
||||
}
|
||||
mError("user:%s, failed to auth user since %s", pUsers[i].user, terrstr());
|
||||
mError("user:%s, failed to auth user since %s", pUsers[i].user, tstrerror(code));
|
||||
code = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
|
|
|
@ -1440,6 +1440,11 @@ int32_t metaGetTableTags(void *pVnode, uint64_t suid, SArray *pUidTagInfo) {
|
|||
|
||||
STUidTagInfo info = {.uid = uid, .pTagVal = pCur->pVal};
|
||||
info.pTagVal = taosMemoryMalloc(pCur->vLen);
|
||||
if (!info.pTagVal) {
|
||||
metaCloseCtbCursor(pCur);
|
||||
taosHashCleanup(pSepecifiedUidMap);
|
||||
return TSDB_CODE_OUT_OF_MEMORY;
|
||||
}
|
||||
memcpy(info.pTagVal, pCur->pVal, pCur->vLen);
|
||||
if (taosArrayPush(pUidTagInfo, &info) == NULL) {
|
||||
metaCloseCtbCursor(pCur);
|
||||
|
@ -1462,6 +1467,11 @@ int32_t metaGetTableTags(void *pVnode, uint64_t suid, SArray *pUidTagInfo) {
|
|||
STUidTagInfo *pTagInfo = taosArrayGet(pUidTagInfo, *index);
|
||||
if (pTagInfo->pTagVal == NULL) {
|
||||
pTagInfo->pTagVal = taosMemoryMalloc(pCur->vLen);
|
||||
if (!pTagInfo->pTagVal) {
|
||||
metaCloseCtbCursor(pCur);
|
||||
taosHashCleanup(pSepecifiedUidMap);
|
||||
return TSDB_CODE_OUT_OF_MEMORY;
|
||||
}
|
||||
memcpy(pTagInfo->pTagVal, pCur->pVal, pCur->vLen);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -347,6 +347,7 @@ static int32_t extractDataAndRspForDbStbSubscribe(STQ* pTq, STqHandle* pHandle,
|
|||
code = TAOS_GET_TERRNO(TSDB_CODE_OUT_OF_MEMORY);
|
||||
goto END;
|
||||
}
|
||||
totalMetaRows++;
|
||||
if ((taosArrayGetSize(btMetaRsp.batchMetaReq) >= tmqRowSize) || (taosGetTimestampMs() - st > 1000)) {
|
||||
tqOffsetResetToLog(&btMetaRsp.rspOffset, fetchVer);
|
||||
code = tqSendBatchMetaPollRsp(pHandle, pMsg, pRequest, &btMetaRsp, vgId);
|
||||
|
|
|
@ -28,7 +28,7 @@ int32_t tCreateSttBlockLoadInfo(STSchema *pSchema, int16_t *colList, int32_t num
|
|||
|
||||
SSttBlockLoadInfo *pLoadInfo = taosMemoryCalloc(1, sizeof(SSttBlockLoadInfo));
|
||||
if (pLoadInfo == NULL) {
|
||||
return TSDB_CODE_OUT_OF_MEMORY;
|
||||
return terrno;
|
||||
}
|
||||
|
||||
pLoadInfo->blockData[0].sttBlockIndex = -1;
|
||||
|
@ -50,9 +50,8 @@ int32_t tCreateSttBlockLoadInfo(STSchema *pSchema, int16_t *colList, int32_t num
|
|||
|
||||
pLoadInfo->aSttBlk = taosArrayInit(4, sizeof(SSttBlk));
|
||||
if (pLoadInfo->aSttBlk == NULL) {
|
||||
code = TSDB_CODE_OUT_OF_MEMORY;
|
||||
taosMemoryFreeClear(pLoadInfo);
|
||||
return code;
|
||||
return terrno;
|
||||
}
|
||||
|
||||
pLoadInfo->pSchema = pSchema;
|
||||
|
@ -358,7 +357,7 @@ static int32_t tValueDupPayload(SValue *pVal) {
|
|||
char *p = (char *)pVal->pData;
|
||||
char *pBuf = taosMemoryMalloc(pVal->nData);
|
||||
if (pBuf == NULL) {
|
||||
return TSDB_CODE_OUT_OF_MEMORY;
|
||||
return terrno;
|
||||
}
|
||||
|
||||
memcpy(pBuf, p, pVal->nData);
|
||||
|
@ -371,13 +370,15 @@ static int32_t tValueDupPayload(SValue *pVal) {
|
|||
static int32_t loadSttStatisticsBlockData(SSttFileReader *pSttFileReader, SSttBlockLoadInfo *pBlockLoadInfo,
|
||||
TStatisBlkArray *pStatisBlkArray, uint64_t suid, const char *id) {
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
int32_t lino = 0;
|
||||
void* px = NULL;
|
||||
int32_t startIndex = 0;
|
||||
|
||||
int32_t numOfBlocks = TARRAY2_SIZE(pStatisBlkArray);
|
||||
if (numOfBlocks <= 0) {
|
||||
return code;
|
||||
}
|
||||
|
||||
int32_t startIndex = 0;
|
||||
while ((startIndex < numOfBlocks) && (pStatisBlkArray->data[startIndex].maxTbid.suid < suid)) {
|
||||
++startIndex;
|
||||
}
|
||||
|
@ -413,150 +414,113 @@ static int32_t loadSttStatisticsBlockData(SSttFileReader *pSttFileReader, SSttBl
|
|||
|
||||
// existed
|
||||
if (i < rows) {
|
||||
if (pBlockLoadInfo->info.pUid == NULL) {
|
||||
pBlockLoadInfo->info.pUid = taosArrayInit(rows, sizeof(int64_t));
|
||||
pBlockLoadInfo->info.pFirstTs = taosArrayInit(rows, sizeof(int64_t));
|
||||
pBlockLoadInfo->info.pLastTs = taosArrayInit(rows, sizeof(int64_t));
|
||||
pBlockLoadInfo->info.pCount = taosArrayInit(rows, sizeof(int64_t));
|
||||
SSttTableRowsInfo* pInfo = &pBlockLoadInfo->info;
|
||||
|
||||
pBlockLoadInfo->info.pFirstKey = taosArrayInit(rows, sizeof(SValue));
|
||||
pBlockLoadInfo->info.pLastKey = taosArrayInit(rows, sizeof(SValue));
|
||||
if (pInfo->pUid == NULL) {
|
||||
pInfo->pUid = taosArrayInit(rows, sizeof(int64_t));
|
||||
pInfo->pFirstTs = taosArrayInit(rows, sizeof(int64_t));
|
||||
pInfo->pLastTs = taosArrayInit(rows, sizeof(int64_t));
|
||||
pInfo->pCount = taosArrayInit(rows, sizeof(int64_t));
|
||||
|
||||
pInfo->pFirstKey = taosArrayInit(rows, sizeof(SValue));
|
||||
pInfo->pLastKey = taosArrayInit(rows, sizeof(SValue));
|
||||
|
||||
if (pInfo->pUid == NULL || pInfo->pFirstTs == NULL || pInfo->pLastTs == NULL || pInfo->pCount == NULL ||
|
||||
pInfo->pFirstKey == NULL || pInfo->pLastKey == NULL) {
|
||||
code = terrno;
|
||||
goto _end;
|
||||
}
|
||||
}
|
||||
|
||||
if (pStatisBlkArray->data[k].maxTbid.suid == suid) {
|
||||
int32_t size = rows - i;
|
||||
int32_t offset = i * sizeof(int64_t);
|
||||
|
||||
px = taosArrayAddBatch(pBlockLoadInfo->info.pUid, tBufferGetDataAt(&block.uids, offset), size);
|
||||
if (px == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
px = taosArrayAddBatch(pInfo->pUid, tBufferGetDataAt(&block.uids, offset), size);
|
||||
TSDB_CHECK_NULL(px, code, lino, _end, terrno);
|
||||
|
||||
px = taosArrayAddBatch(pBlockLoadInfo->info.pFirstTs, tBufferGetDataAt(&block.firstKeyTimestamps, offset), size);
|
||||
if (px == NULL){
|
||||
return terrno;
|
||||
}
|
||||
px = taosArrayAddBatch(pInfo->pFirstTs, tBufferGetDataAt(&block.firstKeyTimestamps, offset), size);
|
||||
TSDB_CHECK_NULL(px, code, lino, _end, terrno);
|
||||
|
||||
px = taosArrayAddBatch(pBlockLoadInfo->info.pLastTs, tBufferGetDataAt(&block.lastKeyTimestamps, offset), size);
|
||||
if (px == NULL){
|
||||
return terrno;
|
||||
}
|
||||
px = taosArrayAddBatch(pInfo->pLastTs, tBufferGetDataAt(&block.lastKeyTimestamps, offset), size);
|
||||
TSDB_CHECK_NULL(px, code, lino, _end, terrno);
|
||||
|
||||
px = taosArrayAddBatch(pBlockLoadInfo->info.pCount, tBufferGetDataAt(&block.counts, offset), size);
|
||||
if (px == NULL){
|
||||
return terrno;
|
||||
}
|
||||
px = taosArrayAddBatch(pInfo->pCount, tBufferGetDataAt(&block.counts, offset), size);
|
||||
TSDB_CHECK_NULL(px, code, lino, _end, terrno);
|
||||
|
||||
if (block.numOfPKs > 0) {
|
||||
SValue vFirst = {0}, vLast = {0};
|
||||
for (int32_t f = i; f < rows; ++f) {
|
||||
code = tValueColumnGet(&block.firstKeyPKs[0], f, &vFirst);
|
||||
if (code) {
|
||||
break;
|
||||
}
|
||||
TSDB_CHECK_CODE(code, lino, _end);
|
||||
|
||||
code = tValueDupPayload(&vFirst);
|
||||
if (code) {
|
||||
break;
|
||||
}
|
||||
TSDB_CHECK_CODE(code, lino, _end);
|
||||
|
||||
px = taosArrayPush(pBlockLoadInfo->info.pFirstKey, &vFirst);
|
||||
if (px == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
px = taosArrayPush(pInfo->pFirstKey, &vFirst);
|
||||
TSDB_CHECK_NULL(px, code, lino, _end, terrno);
|
||||
|
||||
// todo add api to clone the original data
|
||||
code = tValueColumnGet(&block.lastKeyPKs[0], f, &vLast);
|
||||
if (code) {
|
||||
break;
|
||||
}
|
||||
TSDB_CHECK_CODE(code, lino, _end);
|
||||
|
||||
code = tValueDupPayload(&vLast);
|
||||
if (code) {
|
||||
break;
|
||||
}
|
||||
TSDB_CHECK_CODE(code, lino, _end);
|
||||
|
||||
px = taosArrayPush(pBlockLoadInfo->info.pLastKey, &vLast);
|
||||
if (px == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
px = taosArrayPush(pInfo->pLastKey, &vLast);
|
||||
TSDB_CHECK_NULL(px, code, lino, _end, terrno);
|
||||
}
|
||||
} else {
|
||||
SValue vFirst = {0};
|
||||
for (int32_t j = 0; j < size; ++j) {
|
||||
px = taosArrayPush(pBlockLoadInfo->info.pFirstKey, &vFirst);
|
||||
if (px == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
px = taosArrayPush(pInfo->pFirstKey, &vFirst);
|
||||
TSDB_CHECK_NULL(px, code, lino, _end, terrno);
|
||||
|
||||
px = taosArrayPush(pBlockLoadInfo->info.pLastKey, &vFirst);
|
||||
if (px == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
px = taosArrayPush(pInfo->pLastKey, &vFirst);
|
||||
TSDB_CHECK_NULL(px, code, lino, _end, terrno);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
STbStatisRecord record = {0};
|
||||
|
||||
while (i < rows) {
|
||||
(void)tStatisBlockGet(&block, i, &record);
|
||||
if (record.suid != suid) {
|
||||
break;
|
||||
}
|
||||
|
||||
px = taosArrayPush(pBlockLoadInfo->info.pUid, &record.uid);
|
||||
if (px == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
px = taosArrayPush(pInfo->pUid, &record.uid);
|
||||
TSDB_CHECK_NULL(px, code, lino, _end, terrno);
|
||||
|
||||
px = taosArrayPush(pBlockLoadInfo->info.pCount, &record.count);
|
||||
if (px == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
px = taosArrayPush(pInfo->pCount, &record.count);
|
||||
TSDB_CHECK_NULL(px, code, lino, _end, terrno);
|
||||
|
||||
px = taosArrayPush(pBlockLoadInfo->info.pFirstTs, &record.firstKey.ts);
|
||||
if (px == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
px = taosArrayPush(pInfo->pFirstTs, &record.firstKey.ts);
|
||||
TSDB_CHECK_NULL(px, code, lino, _end, terrno);
|
||||
|
||||
px = taosArrayPush(pBlockLoadInfo->info.pLastTs, &record.lastKey.ts);
|
||||
if (px == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
px = taosArrayPush(pInfo->pLastTs, &record.lastKey.ts);
|
||||
TSDB_CHECK_NULL(px, code, lino, _end, terrno);
|
||||
|
||||
if (record.firstKey.numOfPKs > 0) {
|
||||
SValue s = record.firstKey.pks[0];
|
||||
code = tValueDupPayload(&s);
|
||||
if (code) {
|
||||
return code;
|
||||
}
|
||||
TSDB_CHECK_CODE(code, lino, _end);
|
||||
|
||||
px = taosArrayPush(pBlockLoadInfo->info.pFirstKey, &s);
|
||||
if (px == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
px = taosArrayPush(pInfo->pFirstKey, &s);
|
||||
TSDB_CHECK_NULL(px, code, lino, _end, terrno);
|
||||
|
||||
s = record.lastKey.pks[0];
|
||||
code = tValueDupPayload(&s);
|
||||
if (code) {
|
||||
return code;
|
||||
}
|
||||
TSDB_CHECK_CODE(code, lino, _end);
|
||||
|
||||
px = taosArrayPush(pBlockLoadInfo->info.pLastKey, &s);
|
||||
if (px == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
px = taosArrayPush(pInfo->pLastKey, &s);
|
||||
TSDB_CHECK_NULL(px, code, lino, _end, terrno);
|
||||
} else {
|
||||
SValue v = {0};
|
||||
px = taosArrayPush(pBlockLoadInfo->info.pFirstKey, &v);
|
||||
if (px == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
px = taosArrayPush(pInfo->pFirstKey, &v);
|
||||
TSDB_CHECK_NULL(px, code, lino, _end, terrno);
|
||||
|
||||
px = taosArrayPush(pBlockLoadInfo->info.pLastKey, &v);
|
||||
if (px == NULL) {
|
||||
return terrno;
|
||||
}
|
||||
px = taosArrayPush(pInfo->pLastKey, &v);
|
||||
TSDB_CHECK_NULL(px, code, lino, _end, terrno);
|
||||
}
|
||||
|
||||
i += 1;
|
||||
|
@ -565,6 +529,7 @@ static int32_t loadSttStatisticsBlockData(SSttFileReader *pSttFileReader, SSttBl
|
|||
}
|
||||
}
|
||||
|
||||
_end:
|
||||
(void)tStatisBlockDestroy(&block);
|
||||
|
||||
double el = (taosGetTimestampUs() - st) / 1000.0;
|
||||
|
|
|
@ -202,6 +202,7 @@ typedef struct SExchangeInfo {
|
|||
SLimitInfo limitInfo;
|
||||
int64_t openedTs; // start exec time stamp, todo: move to SLoadRemoteDataInfo
|
||||
char* pTaskId;
|
||||
SArray* pFetchRpcHandles;
|
||||
} SExchangeInfo;
|
||||
|
||||
typedef struct SScanInfo {
|
||||
|
|
|
@ -147,7 +147,10 @@ _error:
|
|||
if (pInfo != NULL) {
|
||||
destroyAggOperatorInfo(pInfo);
|
||||
}
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
pTaskInfo->code = code;
|
||||
return code;
|
||||
}
|
||||
|
|
|
@ -247,7 +247,10 @@ _error:
|
|||
}
|
||||
pInfo->pTableList = NULL;
|
||||
destroyCacheScanOperator(pInfo);
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
|
@ -448,7 +451,7 @@ void destroyCacheScanOperator(void* param) {
|
|||
taosArrayDestroy(pInfo->matchInfo.pList);
|
||||
tableListDestroy(pInfo->pTableList);
|
||||
|
||||
if (pInfo->pLastrowReader != NULL) {
|
||||
if (pInfo->pLastrowReader != NULL && pInfo->readHandle.api.cacheFn.closeReader != NULL) {
|
||||
pInfo->readHandle.api.cacheFn.closeReader(pInfo->pLastrowReader);
|
||||
pInfo->pLastrowReader = NULL;
|
||||
}
|
||||
|
|
|
@ -341,7 +341,10 @@ _error:
|
|||
destroyCountWindowOperatorInfo(pInfo);
|
||||
}
|
||||
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
pTaskInfo->code = code;
|
||||
return code;
|
||||
}
|
||||
|
|
|
@ -145,7 +145,10 @@ _error:
|
|||
destroyEWindowOperatorInfo(pInfo);
|
||||
}
|
||||
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
pTaskInfo->code = code;
|
||||
return code;
|
||||
}
|
||||
|
|
|
@ -298,13 +298,13 @@ _end:
|
|||
pTaskInfo->code = code;
|
||||
T_LONG_JMP(pTaskInfo->env, code);
|
||||
}
|
||||
(*ppRes) = NULL;
|
||||
(*ppRes) = NULL;
|
||||
return code;
|
||||
}
|
||||
|
||||
static SSDataBlock* loadRemoteData(SOperatorInfo* pOperator) {
|
||||
SSDataBlock* pRes = NULL;
|
||||
int32_t code = loadRemoteDataNext(pOperator, &pRes);
|
||||
int32_t code = loadRemoteDataNext(pOperator, &pRes);
|
||||
return pRes;
|
||||
}
|
||||
|
||||
|
@ -346,6 +346,14 @@ static int32_t initExchangeOperator(SExchangePhysiNode* pExNode, SExchangeInfo*
|
|||
qError("%s invalid number: %d of sources in exchange operator", id, (int32_t)numOfSources);
|
||||
return TSDB_CODE_INVALID_PARA;
|
||||
}
|
||||
pInfo->pFetchRpcHandles = taosArrayInit(numOfSources, sizeof(int64_t));
|
||||
if (!pInfo->pFetchRpcHandles) {
|
||||
return terrno;
|
||||
}
|
||||
void* ret = taosArrayReserve(pInfo->pFetchRpcHandles, numOfSources);
|
||||
if (!ret) {
|
||||
return terrno;
|
||||
}
|
||||
|
||||
pInfo->pSources = taosArrayInit(numOfSources, sizeof(SDownstreamSourceNode));
|
||||
if (pInfo->pSources == NULL) {
|
||||
|
@ -384,6 +392,7 @@ static int32_t initExchangeOperator(SExchangePhysiNode* pExNode, SExchangeInfo*
|
|||
initLimitInfo(pExNode->node.pLimit, pExNode->node.pSlimit, &pInfo->limitInfo);
|
||||
pInfo->self = taosAddRef(exchangeObjRefPool, pInfo);
|
||||
|
||||
|
||||
return initDataSource(numOfSources, pInfo, id);
|
||||
}
|
||||
|
||||
|
@ -391,7 +400,7 @@ int32_t createExchangeOperatorInfo(void* pTransporter, SExchangePhysiNode* pExNo
|
|||
SOperatorInfo** pOptrInfo) {
|
||||
QRY_OPTR_CHECK(pOptrInfo);
|
||||
|
||||
int32_t code = 0;
|
||||
int32_t code = 0;
|
||||
int32_t lino = 0;
|
||||
SExchangeInfo* pInfo = taosMemoryCalloc(1, sizeof(SExchangeInfo));
|
||||
SOperatorInfo* pOperator = taosMemoryCalloc(1, sizeof(SOperatorInfo));
|
||||
|
@ -443,7 +452,10 @@ _error:
|
|||
doDestroyExchangeOperatorInfo(pInfo);
|
||||
}
|
||||
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
pTaskInfo->code = code;
|
||||
return code;
|
||||
}
|
||||
|
@ -468,6 +480,14 @@ void freeSourceDataInfo(void* p) {
|
|||
|
||||
void doDestroyExchangeOperatorInfo(void* param) {
|
||||
SExchangeInfo* pExInfo = (SExchangeInfo*)param;
|
||||
for (int32_t i = 0; i < pExInfo->pFetchRpcHandles->size; ++i) {
|
||||
int64_t* pRpcHandle = taosArrayGet(pExInfo->pFetchRpcHandles, i);
|
||||
if (*pRpcHandle > 0) {
|
||||
SDownstreamSourceNode* pSource = taosArrayGet(pExInfo->pSources, i);
|
||||
(void)asyncFreeConnById(pExInfo->pTransporter, *pRpcHandle);
|
||||
}
|
||||
}
|
||||
taosArrayDestroy(pExInfo->pFetchRpcHandles);
|
||||
|
||||
taosArrayDestroy(pExInfo->pSources);
|
||||
taosArrayDestroyEx(pExInfo->pSourceDataInfo, freeSourceDataInfo);
|
||||
|
@ -495,6 +515,8 @@ int32_t loadRemoteDataCallback(void* param, SDataBuf* pMsg, int32_t code) {
|
|||
}
|
||||
|
||||
int32_t index = pWrapper->sourceIndex;
|
||||
int64_t* pRpcHandle = taosArrayGet(pExchangeInfo->pFetchRpcHandles, index);
|
||||
*pRpcHandle = -1;
|
||||
SSourceDataInfo* pSourceDataInfo = taosArrayGet(pExchangeInfo->pSourceDataInfo, index);
|
||||
if (!pSourceDataInfo) {
|
||||
return terrno;
|
||||
|
@ -668,6 +690,8 @@ int32_t doSendFetchDataRequest(SExchangeInfo* pExchangeInfo, SExecTaskInfo* pTas
|
|||
int64_t transporterId = 0;
|
||||
code = asyncSendMsgToServer(pExchangeInfo->pTransporter, &pSource->addr.epSet, &transporterId, pMsgSendInfo);
|
||||
QUERY_CHECK_CODE(code, lino, _end);
|
||||
int64_t* pRpcHandle = taosArrayGet(pExchangeInfo->pFetchRpcHandles, sourceIndex);
|
||||
*pRpcHandle = transporterId;
|
||||
}
|
||||
|
||||
_end:
|
||||
|
@ -686,11 +710,12 @@ void updateLoadRemoteInfo(SLoadRemoteDataInfo* pInfo, int64_t numOfRows, int32_t
|
|||
}
|
||||
|
||||
int32_t extractDataBlockFromFetchRsp(SSDataBlock* pRes, char* pData, SArray* pColList, char** pNextStart) {
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
int32_t lino = 0;
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
int32_t lino = 0;
|
||||
SSDataBlock* pBlock = NULL;
|
||||
if (pColList == NULL) { // data from other sources
|
||||
blockDataCleanup(pRes);
|
||||
code = blockDecode(pRes, pData, (const char**) pNextStart);
|
||||
code = blockDecode(pRes, pData, (const char**)pNextStart);
|
||||
if (code) {
|
||||
return code;
|
||||
}
|
||||
|
@ -710,7 +735,6 @@ int32_t extractDataBlockFromFetchRsp(SSDataBlock* pRes, char* pData, SArray* pCo
|
|||
pStart += sizeof(SSysTableSchema);
|
||||
}
|
||||
|
||||
SSDataBlock* pBlock = NULL;
|
||||
code = createDataBlock(&pBlock);
|
||||
QUERY_CHECK_CODE(code, lino, _end);
|
||||
|
||||
|
@ -735,10 +759,12 @@ int32_t extractDataBlockFromFetchRsp(SSDataBlock* pRes, char* pData, SArray* pCo
|
|||
QUERY_CHECK_CODE(code, lino, _end);
|
||||
|
||||
blockDataDestroy(pBlock);
|
||||
pBlock = NULL;
|
||||
}
|
||||
|
||||
_end:
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
blockDataDestroy(pBlock);
|
||||
qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
|
||||
}
|
||||
return code;
|
||||
|
|
|
@ -567,7 +567,10 @@ _error:
|
|||
}
|
||||
|
||||
pTaskInfo->code = code;
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
|
|
|
@ -1504,7 +1504,10 @@ _error:
|
|||
destroyGroupCacheOperator(pInfo);
|
||||
}
|
||||
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
pTaskInfo->code = code;
|
||||
return code;
|
||||
}
|
||||
|
|
|
@ -1246,7 +1246,10 @@ _error:
|
|||
destroyPartitionOperatorInfo(pInfo);
|
||||
}
|
||||
pTaskInfo->code = code;
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
TAOS_RETURN(code);
|
||||
}
|
||||
|
||||
|
@ -1792,7 +1795,10 @@ int32_t createStreamPartitionOperatorInfo(SOperatorInfo* downstream, SStreamPart
|
|||
_error:
|
||||
pTaskInfo->code = code;
|
||||
if (pInfo != NULL) destroyStreamPartitionOperatorInfo(pInfo);
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
|
||||
return code;
|
||||
}
|
||||
|
|
|
@ -650,7 +650,7 @@ void destroyOperator(SOperatorInfo* pOperator) {
|
|||
freeResetOperatorParams(pOperator, OP_GET_PARAM, true);
|
||||
freeResetOperatorParams(pOperator, OP_NOTIFY_PARAM, true);
|
||||
|
||||
if (pOperator->fpSet.closeFn != NULL) {
|
||||
if (pOperator->fpSet.closeFn != NULL && pOperator->info != NULL) {
|
||||
pOperator->fpSet.closeFn(pOperator->info);
|
||||
}
|
||||
|
||||
|
|
|
@ -180,7 +180,10 @@ int32_t createProjectOperatorInfo(SOperatorInfo* downstream, SProjectPhysiNode*
|
|||
|
||||
_error:
|
||||
destroyProjectOperatorInfo(pInfo);
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
pTaskInfo->code = code;
|
||||
return code;
|
||||
}
|
||||
|
@ -529,7 +532,10 @@ int32_t createIndefinitOutputOperatorInfo(SOperatorInfo* downstream, SPhysiNode*
|
|||
|
||||
_error:
|
||||
destroyIndefinitOperatorInfo(pInfo);
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
pTaskInfo->code = code;
|
||||
return code;
|
||||
}
|
||||
|
|
|
@ -1466,7 +1466,10 @@ _error:
|
|||
destroyTableScanOperatorInfo(pInfo);
|
||||
}
|
||||
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
pTaskInfo->code = code;
|
||||
return code;
|
||||
}
|
||||
|
@ -3777,7 +3780,7 @@ static void destroyStreamScanOperatorInfo(void* param) {
|
|||
destroyOperator(pStreamScan->pTableScanOp);
|
||||
}
|
||||
|
||||
if (pStreamScan->tqReader) {
|
||||
if (pStreamScan->tqReader != NULL && pStreamScan->readerFn.tqReaderClose != NULL) {
|
||||
pStreamScan->readerFn.tqReaderClose(pStreamScan->tqReader);
|
||||
}
|
||||
if (pStreamScan->matchInfo.pList) {
|
||||
|
@ -4147,7 +4150,10 @@ _error:
|
|||
destroyStreamScanOperatorInfo(pInfo);
|
||||
}
|
||||
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
pTaskInfo->code = code;
|
||||
return code;
|
||||
}
|
||||
|
@ -4607,7 +4613,7 @@ static SSDataBlock* doTagScanFromMetaEntry(SOperatorInfo* pOperator) {
|
|||
|
||||
static void destroyTagScanOperatorInfo(void* param) {
|
||||
STagScanInfo* pInfo = (STagScanInfo*)param;
|
||||
if (pInfo->pCtbCursor != NULL) {
|
||||
if (pInfo->pCtbCursor != NULL && pInfo->pStorageAPI != NULL) {
|
||||
pInfo->pStorageAPI->metaFn.closeCtbCursor(pInfo->pCtbCursor);
|
||||
}
|
||||
taosHashCleanup(pInfo->filterCtx.colHash);
|
||||
|
@ -4704,7 +4710,10 @@ _error:
|
|||
}
|
||||
|
||||
if (pInfo != NULL) destroyTagScanOperatorInfo(pInfo);
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
|
@ -5769,8 +5778,10 @@ void destroyTableMergeScanOperatorInfo(void* param) {
|
|||
STableMergeScanInfo* pTableScanInfo = (STableMergeScanInfo*)param;
|
||||
|
||||
// start one reader variable
|
||||
pTableScanInfo->base.readerAPI.tsdReaderClose(pTableScanInfo->base.dataReader);
|
||||
pTableScanInfo->base.dataReader = NULL;
|
||||
if (pTableScanInfo->base.readerAPI.tsdReaderClose != NULL) {
|
||||
pTableScanInfo->base.readerAPI.tsdReaderClose(pTableScanInfo->base.dataReader);
|
||||
pTableScanInfo->base.dataReader = NULL;
|
||||
}
|
||||
|
||||
for (int32_t i = 0; i < pTableScanInfo->numNextDurationBlocks; ++i) {
|
||||
if (pTableScanInfo->nextDurationBlocks[i] != NULL) {
|
||||
|
@ -5949,7 +5960,10 @@ _error:
|
|||
pTaskInfo->code = code;
|
||||
pInfo->base.pTableListInfo = NULL;
|
||||
if (pInfo != NULL) destroyTableMergeScanOperatorInfo(pInfo);
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
||||
|
@ -6106,7 +6120,10 @@ _error:
|
|||
if (pInfo != NULL) {
|
||||
destoryTableCountScanOperator(pInfo);
|
||||
}
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
pTaskInfo->code = code;
|
||||
return code;
|
||||
}
|
||||
|
|
|
@ -164,7 +164,10 @@ _error:
|
|||
destroySortOperatorInfo(pInfo);
|
||||
}
|
||||
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
pTaskInfo->code = code;
|
||||
return code;
|
||||
}
|
||||
|
@ -836,6 +839,9 @@ _error:
|
|||
if (pInfo != NULL) {
|
||||
destroyGroupSortOperatorInfo(pInfo);
|
||||
}
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
|
|
@ -926,7 +926,10 @@ _error:
|
|||
destroyStreamCountAggOperatorInfo(pInfo);
|
||||
}
|
||||
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
pTaskInfo->code = code;
|
||||
qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
|
||||
return code;
|
||||
|
|
|
@ -981,7 +981,10 @@ int32_t createStreamEventAggOperatorInfo(SOperatorInfo* downstream, SPhysiNode*
|
|||
|
||||
_error:
|
||||
if (pInfo != NULL) destroyStreamEventOperatorInfo(pInfo);
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
pTaskInfo->code = code;
|
||||
qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
|
||||
return code;
|
||||
|
|
|
@ -1459,7 +1459,10 @@ _error:
|
|||
qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
|
||||
}
|
||||
if (pInfo != NULL) destroyStreamFillOperatorInfo(pInfo);
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
pTaskInfo->code = code;
|
||||
return code;
|
||||
}
|
||||
|
|
|
@ -2013,7 +2013,10 @@ int32_t createStreamFinalIntervalOperatorInfo(SOperatorInfo* downstream, SPhysiN
|
|||
|
||||
_error:
|
||||
if (pInfo != NULL) destroyStreamFinalIntervalOperatorInfo(pInfo);
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
pTaskInfo->code = code;
|
||||
return code;
|
||||
}
|
||||
|
@ -3832,7 +3835,10 @@ _error:
|
|||
destroyStreamSessionAggOperatorInfo(pInfo);
|
||||
}
|
||||
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
pTaskInfo->code = code;
|
||||
qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
|
||||
return code;
|
||||
|
@ -4088,7 +4094,10 @@ _error:
|
|||
if (pInfo != NULL) {
|
||||
destroyStreamSessionAggOperatorInfo(pInfo);
|
||||
}
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
pTaskInfo->code = code;
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
qError("%s failed at line %d since %s. task:%s", __func__, lino, tstrerror(code), GET_TASKID(pTaskInfo));
|
||||
|
@ -4978,7 +4987,10 @@ int32_t createStreamStateAggOperatorInfo(SOperatorInfo* downstream, SPhysiNode*
|
|||
|
||||
_error:
|
||||
if (pInfo != NULL) destroyStreamStateOperatorInfo(pInfo);
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
pTaskInfo->code = code;
|
||||
qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
|
||||
return code;
|
||||
|
@ -5313,7 +5325,10 @@ int32_t createStreamIntervalOperatorInfo(SOperatorInfo* downstream, SPhysiNode*
|
|||
|
||||
_error:
|
||||
if (pInfo != NULL) destroyStreamFinalIntervalOperatorInfo(pInfo);
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
pTaskInfo->code = code;
|
||||
return code;
|
||||
}
|
||||
|
|
|
@ -672,6 +672,7 @@ static SSDataBlock* sysTableScanUserCols(SOperatorInfo* pOperator) {
|
|||
}
|
||||
|
||||
blockDataDestroy(pDataBlock);
|
||||
pDataBlock = NULL;
|
||||
if (ret != 0) {
|
||||
pAPI->metaFn.closeTableMetaCursor(pInfo->pCur);
|
||||
pInfo->pCur = NULL;
|
||||
|
@ -683,6 +684,7 @@ static SSDataBlock* sysTableScanUserCols(SOperatorInfo* pOperator) {
|
|||
|
||||
_end:
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
blockDataDestroy(pDataBlock);
|
||||
qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
|
||||
pTaskInfo->code = code;
|
||||
T_LONG_JMP(pTaskInfo->env, code);
|
||||
|
@ -695,6 +697,7 @@ static SSDataBlock* sysTableScanUserTags(SOperatorInfo* pOperator) {
|
|||
int32_t lino = 0;
|
||||
SExecTaskInfo* pTaskInfo = pOperator->pTaskInfo;
|
||||
SStorageAPI* pAPI = &pTaskInfo->storageAPI;
|
||||
SSDataBlock* dataBlock = NULL;
|
||||
|
||||
SSysTableScanInfo* pInfo = pOperator->info;
|
||||
if (pOperator->status == OP_EXEC_DONE) {
|
||||
|
@ -704,7 +707,7 @@ static SSDataBlock* sysTableScanUserTags(SOperatorInfo* pOperator) {
|
|||
blockDataCleanup(pInfo->pRes);
|
||||
int32_t numOfRows = 0;
|
||||
|
||||
SSDataBlock* dataBlock = buildInfoSchemaTableMetaBlock(TSDB_INS_TABLE_TAGS);
|
||||
dataBlock = buildInfoSchemaTableMetaBlock(TSDB_INS_TABLE_TAGS);
|
||||
code = blockDataEnsureCapacity(dataBlock, pOperator->resultInfo.capacity);
|
||||
QUERY_CHECK_CODE(code, lino, _end);
|
||||
|
||||
|
@ -826,6 +829,7 @@ static SSDataBlock* sysTableScanUserTags(SOperatorInfo* pOperator) {
|
|||
}
|
||||
|
||||
blockDataDestroy(dataBlock);
|
||||
dataBlock = NULL;
|
||||
if (ret != 0) {
|
||||
pAPI->metaFn.closeTableMetaCursor(pInfo->pCur);
|
||||
pInfo->pCur = NULL;
|
||||
|
@ -837,6 +841,7 @@ static SSDataBlock* sysTableScanUserTags(SOperatorInfo* pOperator) {
|
|||
_end:
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
|
||||
blockDataDestroy(dataBlock);
|
||||
pAPI->metaFn.closeTableMetaCursor(pInfo->pCur);
|
||||
pInfo->pCur = NULL;
|
||||
pTaskInfo->code = code;
|
||||
|
@ -1310,9 +1315,11 @@ int32_t buildSysDbTableInfo(const SSysTableScanInfo* pInfo, int32_t capacity) {
|
|||
QUERY_CHECK_CODE(code, lino, _end);
|
||||
|
||||
blockDataDestroy(p);
|
||||
p = NULL;
|
||||
|
||||
_end:
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
blockDataDestroy(p);
|
||||
qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
|
||||
}
|
||||
return code;
|
||||
|
@ -1325,6 +1332,7 @@ static SSDataBlock* sysTableBuildUserTablesByUids(SOperatorInfo* pOperator) {
|
|||
SStorageAPI* pAPI = &pTaskInfo->storageAPI;
|
||||
SSysTableScanInfo* pInfo = pOperator->info;
|
||||
SSysTableIndex* pIdx = pInfo->pIdx;
|
||||
SSDataBlock* p = NULL;
|
||||
blockDataCleanup(pInfo->pRes);
|
||||
int32_t numOfRows = 0;
|
||||
|
||||
|
@ -1344,7 +1352,7 @@ static SSDataBlock* sysTableBuildUserTablesByUids(SOperatorInfo* pOperator) {
|
|||
|
||||
varDataSetLen(dbname, strlen(varDataVal(dbname)));
|
||||
|
||||
SSDataBlock* p = buildInfoSchemaTableMetaBlock(TSDB_INS_TABLE_TABLES);
|
||||
p = buildInfoSchemaTableMetaBlock(TSDB_INS_TABLE_TABLES);
|
||||
code = blockDataEnsureCapacity(p, pOperator->resultInfo.capacity);
|
||||
QUERY_CHECK_CODE(code, lino, _end);
|
||||
|
||||
|
@ -1545,12 +1553,14 @@ static SSDataBlock* sysTableBuildUserTablesByUids(SOperatorInfo* pOperator) {
|
|||
}
|
||||
|
||||
blockDataDestroy(p);
|
||||
p = NULL;
|
||||
|
||||
pInfo->loadInfo.totalRows += pInfo->pRes->info.rows;
|
||||
|
||||
_end:
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
|
||||
blockDataDestroy(p);
|
||||
pTaskInfo->code = code;
|
||||
T_LONG_JMP(pTaskInfo->env, code);
|
||||
}
|
||||
|
@ -1563,6 +1573,7 @@ static SSDataBlock* sysTableBuildUserTables(SOperatorInfo* pOperator) {
|
|||
SExecTaskInfo* pTaskInfo = pOperator->pTaskInfo;
|
||||
SStorageAPI* pAPI = &pTaskInfo->storageAPI;
|
||||
int8_t firstMetaCursor = 0;
|
||||
SSDataBlock* p = NULL;
|
||||
|
||||
SSysTableScanInfo* pInfo = pOperator->info;
|
||||
if (pInfo->pCur == NULL) {
|
||||
|
@ -1590,7 +1601,7 @@ static SSDataBlock* sysTableBuildUserTables(SOperatorInfo* pOperator) {
|
|||
|
||||
varDataSetLen(dbname, strlen(varDataVal(dbname)));
|
||||
|
||||
SSDataBlock* p = buildInfoSchemaTableMetaBlock(TSDB_INS_TABLE_TABLES);
|
||||
p = buildInfoSchemaTableMetaBlock(TSDB_INS_TABLE_TABLES);
|
||||
QUERY_CHECK_NULL(p, code, lino, _end, terrno);
|
||||
|
||||
code = blockDataEnsureCapacity(p, pOperator->resultInfo.capacity);
|
||||
|
@ -1783,6 +1794,7 @@ static SSDataBlock* sysTableBuildUserTables(SOperatorInfo* pOperator) {
|
|||
}
|
||||
|
||||
blockDataDestroy(p);
|
||||
p = NULL;
|
||||
|
||||
// todo temporarily free the cursor here, the true reason why the free is not valid needs to be found
|
||||
if (ret != 0) {
|
||||
|
@ -1796,6 +1808,7 @@ static SSDataBlock* sysTableBuildUserTables(SOperatorInfo* pOperator) {
|
|||
_end:
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
|
||||
blockDataDestroy(p);
|
||||
pTaskInfo->code = code;
|
||||
T_LONG_JMP(pTaskInfo->env, code);
|
||||
}
|
||||
|
@ -2209,7 +2222,10 @@ _error:
|
|||
if (code != TSDB_CODE_SUCCESS) {
|
||||
qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
|
||||
}
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
pTaskInfo->code = code;
|
||||
return code;
|
||||
}
|
||||
|
@ -2244,7 +2260,7 @@ void destroySysScanOperator(void* param) {
|
|||
if (strncasecmp(name, TSDB_INS_TABLE_TABLES, TSDB_TABLE_FNAME_LEN) == 0 ||
|
||||
strncasecmp(name, TSDB_INS_TABLE_TAGS, TSDB_TABLE_FNAME_LEN) == 0 ||
|
||||
strncasecmp(name, TSDB_INS_TABLE_COLS, TSDB_TABLE_FNAME_LEN) == 0 || pInfo->pCur != NULL) {
|
||||
if (pInfo->pAPI->metaFn.closeTableMetaCursor != NULL) {
|
||||
if (pInfo->pAPI != NULL && pInfo->pAPI->metaFn.closeTableMetaCursor != NULL) {
|
||||
pInfo->pAPI->metaFn.closeTableMetaCursor(pInfo->pCur);
|
||||
}
|
||||
|
||||
|
@ -2726,7 +2742,9 @@ static SSDataBlock* doBlockInfoScan(SOperatorInfo* pOperator) {
|
|||
static void destroyBlockDistScanOperatorInfo(void* param) {
|
||||
SBlockDistInfo* pDistInfo = (SBlockDistInfo*)param;
|
||||
blockDataDestroy(pDistInfo->pResBlock);
|
||||
pDistInfo->readHandle.api.tsdReader.tsdReaderClose(pDistInfo->pHandle);
|
||||
if (pDistInfo->readHandle.api.tsdReader.tsdReaderClose != NULL) {
|
||||
pDistInfo->readHandle.api.tsdReader.tsdReaderClose(pDistInfo->pHandle);
|
||||
}
|
||||
tableListDestroy(pDistInfo->pTableListInfo);
|
||||
taosMemoryFreeClear(param);
|
||||
}
|
||||
|
@ -2815,6 +2833,9 @@ _error:
|
|||
pInfo->pTableListInfo = NULL;
|
||||
destroyBlockDistScanOperatorInfo(pInfo);
|
||||
}
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
return code;
|
||||
}
|
||||
|
|
|
@ -1208,7 +1208,10 @@ _error:
|
|||
qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
|
||||
}
|
||||
if (pInfo != NULL) destroyTimeSliceOperatorInfo(pInfo);
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
pTaskInfo->code = code;
|
||||
return code;
|
||||
}
|
||||
|
|
|
@ -1414,7 +1414,10 @@ _error:
|
|||
if (pInfo != NULL) {
|
||||
destroyIntervalOperatorInfo(pInfo);
|
||||
}
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
pTaskInfo->code = code;
|
||||
return code;
|
||||
}
|
||||
|
@ -1690,7 +1693,10 @@ _error:
|
|||
destroyStateWindowOperatorInfo(pInfo);
|
||||
}
|
||||
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
pTaskInfo->code = code;
|
||||
return code;
|
||||
}
|
||||
|
@ -1783,7 +1789,10 @@ int32_t createSessionAggOperatorInfo(SOperatorInfo* downstream, SSessionWinodwPh
|
|||
|
||||
_error:
|
||||
if (pInfo != NULL) destroySWindowOperatorInfo(pInfo);
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
pTaskInfo->code = code;
|
||||
return code;
|
||||
}
|
||||
|
@ -2094,8 +2103,11 @@ int32_t createMergeAlignedIntervalOperatorInfo(SOperatorInfo* downstream, SMerge
|
|||
return code;
|
||||
|
||||
_error:
|
||||
destroyMAIOperatorInfo(miaInfo);
|
||||
destroyOperator(pOperator);
|
||||
if (miaInfo != NULL) destroyMAIOperatorInfo(miaInfo);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
pTaskInfo->code = code;
|
||||
return code;
|
||||
}
|
||||
|
@ -2427,7 +2439,10 @@ _error:
|
|||
destroyMergeIntervalOperatorInfo(pMergeIntervalInfo);
|
||||
}
|
||||
|
||||
destroyOperator(pOperator);
|
||||
if (pOperator != NULL) {
|
||||
pOperator->info = NULL;
|
||||
destroyOperator(pOperator);
|
||||
}
|
||||
pTaskInfo->code = code;
|
||||
return code;
|
||||
}
|
||||
|
|
|
@ -225,6 +225,7 @@ int32_t asyncSendMsgToServerExt(void* pTransporter, SEpSet* epSet, int64_t* pTra
|
|||
.code = 0
|
||||
};
|
||||
TRACE_SET_ROOTID(&rpcMsg.info.traceId, pInfo->requestId);
|
||||
|
||||
int code = rpcSendRequestWithCtx(pTransporter, epSet, &rpcMsg, pTransporterId, rpcCtx);
|
||||
if (code) {
|
||||
destroySendMsgInfo(pInfo);
|
||||
|
@ -235,6 +236,9 @@ int32_t asyncSendMsgToServerExt(void* pTransporter, SEpSet* epSet, int64_t* pTra
|
|||
int32_t asyncSendMsgToServer(void* pTransporter, SEpSet* epSet, int64_t* pTransporterId, SMsgSendInfo* pInfo) {
|
||||
return asyncSendMsgToServerExt(pTransporter, epSet, pTransporterId, pInfo, false, NULL);
|
||||
}
|
||||
int32_t asyncFreeConnById(void* pTransporter, int64_t pid) {
|
||||
return rpcFreeConnById(pTransporter, pid);
|
||||
}
|
||||
|
||||
char* jobTaskStatusStr(int32_t status) {
|
||||
switch (status) {
|
||||
|
@ -448,13 +452,13 @@ void parseTagDatatoJson(void* p, char** jsonStr) {
|
|||
if (value == NULL) {
|
||||
goto end;
|
||||
}
|
||||
if(!cJSON_AddItemToObject(json, tagJsonKey, value)){
|
||||
if (!cJSON_AddItemToObject(json, tagJsonKey, value)) {
|
||||
goto end;
|
||||
}
|
||||
} else if (type == TSDB_DATA_TYPE_NCHAR) {
|
||||
cJSON* value = NULL;
|
||||
if (pTagVal->nData > 0) {
|
||||
char* tagJsonValue = taosMemoryCalloc(pTagVal->nData, 1);
|
||||
char* tagJsonValue = taosMemoryCalloc(pTagVal->nData, 1);
|
||||
if (tagJsonValue == NULL) {
|
||||
goto end;
|
||||
}
|
||||
|
@ -479,7 +483,7 @@ void parseTagDatatoJson(void* p, char** jsonStr) {
|
|||
goto end;
|
||||
}
|
||||
|
||||
if(!cJSON_AddItemToObject(json, tagJsonKey, value)){
|
||||
if (!cJSON_AddItemToObject(json, tagJsonKey, value)) {
|
||||
goto end;
|
||||
}
|
||||
} else if (type == TSDB_DATA_TYPE_DOUBLE) {
|
||||
|
@ -488,7 +492,7 @@ void parseTagDatatoJson(void* p, char** jsonStr) {
|
|||
if (value == NULL) {
|
||||
goto end;
|
||||
}
|
||||
if(!cJSON_AddItemToObject(json, tagJsonKey, value)){
|
||||
if (!cJSON_AddItemToObject(json, tagJsonKey, value)) {
|
||||
goto end;
|
||||
}
|
||||
} else if (type == TSDB_DATA_TYPE_BOOL) {
|
||||
|
@ -497,7 +501,7 @@ void parseTagDatatoJson(void* p, char** jsonStr) {
|
|||
if (value == NULL) {
|
||||
goto end;
|
||||
}
|
||||
if(!cJSON_AddItemToObject(json, tagJsonKey, value)){
|
||||
if (!cJSON_AddItemToObject(json, tagJsonKey, value)) {
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
|
|
|
@ -3660,15 +3660,25 @@ int32_t fltInitFromNode(SNode *tree, SFilterInfo *info, uint32_t options) {
|
|||
FLT_ERR_JRET(terrno);
|
||||
}
|
||||
|
||||
FLT_ERR_JRET(filterInitUnitsFields(info));
|
||||
code = filterInitUnitsFields(info);
|
||||
if(TSDB_CODE_SUCCESS != code) {
|
||||
taosArrayDestroy(group);
|
||||
goto _return;
|
||||
}
|
||||
|
||||
SFltBuildGroupCtx tctx = {.info = info, .group = group};
|
||||
nodesWalkExpr(tree, fltTreeToGroup, (void *)&tctx);
|
||||
FLT_ERR_JRET(tctx.code);
|
||||
|
||||
FLT_ERR_JRET(filterConvertGroupFromArray(info, group));
|
||||
if (TSDB_CODE_SUCCESS != tctx.code) {
|
||||
taosArrayDestroy(group);
|
||||
code = tctx.code;
|
||||
goto _return;
|
||||
}
|
||||
code = filterConvertGroupFromArray(info, group);
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
taosArrayDestroy(group);
|
||||
goto _return;
|
||||
}
|
||||
taosArrayDestroy(group);
|
||||
|
||||
FLT_ERR_JRET(fltInitValFieldData(info));
|
||||
|
||||
if (!FILTER_GET_FLAG(info->options, FLT_OPTION_NO_REWRITE)) {
|
||||
|
|
|
@ -17,11 +17,11 @@
|
|||
#include "command.h"
|
||||
#include "query.h"
|
||||
#include "schInt.h"
|
||||
#include "tglobal.h"
|
||||
#include "tmisce.h"
|
||||
#include "tmsg.h"
|
||||
#include "tref.h"
|
||||
#include "trpc.h"
|
||||
#include "tglobal.h"
|
||||
#include "tmisce.h"
|
||||
|
||||
// clang-format off
|
||||
int32_t schValidateRspMsgType(SSchJob *pJob, SSchTask *pTask, int32_t msgType) {
|
||||
|
@ -975,11 +975,13 @@ int32_t schAsyncSendMsg(SSchJob *pJob, SSchTask *pTask, SSchTrans *trans, SQuery
|
|||
SCH_ERR_JRET(schUpdateSendTargetInfo(pMsgSendInfo, addr, pTask));
|
||||
|
||||
if (isHb && persistHandle && trans->pHandle == 0) {
|
||||
trans->pHandle = rpcAllocHandle();
|
||||
if (NULL == trans->pHandle) {
|
||||
SCH_TASK_ELOG("rpcAllocHandle failed, code:%x", terrno);
|
||||
SCH_ERR_JRET(terrno);
|
||||
int64_t refId = 0;
|
||||
code = rpcAllocHandle(&refId);
|
||||
if (code != 0) {
|
||||
SCH_TASK_ELOG("rpcAllocHandle failed, code:%x", code);
|
||||
SCH_ERR_JRET(code);
|
||||
}
|
||||
trans->pHandle = (void *)refId;
|
||||
}
|
||||
|
||||
if (pJob && pTask) {
|
||||
|
@ -1200,7 +1202,14 @@ int32_t schBuildAndSendMsg(SSchJob *pJob, SSchTask *pTask, SQueryNodeAddr *addr,
|
|||
}
|
||||
|
||||
persistHandle = true;
|
||||
SCH_SET_TASK_HANDLE(pTask, rpcAllocHandle());
|
||||
int64_t refId = 0;
|
||||
code = rpcAllocHandle(&refId);
|
||||
if (code != 0) {
|
||||
SCH_TASK_ELOG("rpcAllocHandle failed, code:%x", code);
|
||||
SCH_ERR_JRET(code);
|
||||
}
|
||||
|
||||
SCH_SET_TASK_HANDLE(pTask, (void *)refId);
|
||||
break;
|
||||
}
|
||||
case TDMT_SCH_FETCH:
|
||||
|
|
|
@ -224,7 +224,10 @@ int tdbTbcOpen(TTB *pTb, TBC **ppTbc, TXN *pTxn) {
|
|||
return -1;
|
||||
}
|
||||
|
||||
(void)tdbBtcOpen(&pTbc->btc, pTb->pBt, pTxn);
|
||||
if (tdbBtcOpen(&pTbc->btc, pTb->pBt, pTxn)) {
|
||||
taosMemoryFree(pTbc);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*ppTbc = pTbc;
|
||||
return 0;
|
||||
|
|
|
@ -148,7 +148,6 @@ typedef struct {
|
|||
STransSyncMsg* pSyncMsg; // for syncchronous with timeout API
|
||||
int64_t syncMsgRef;
|
||||
SCvtAddr cvtAddr;
|
||||
bool setMaxRetry;
|
||||
|
||||
int32_t retryMinInterval;
|
||||
int32_t retryMaxInterval;
|
||||
|
@ -207,7 +206,7 @@ typedef struct {
|
|||
|
||||
#pragma pack(pop)
|
||||
|
||||
typedef enum { Normal, Quit, Release, Register, Update } STransMsgType;
|
||||
typedef enum { Normal, Quit, Release, Register, Update, FreeById } STransMsgType;
|
||||
typedef enum { ConnNormal, ConnAcquire, ConnRelease, ConnBroken, ConnInPool } ConnStatus;
|
||||
|
||||
#define container_of(ptr, type, member) ((type*)((char*)(ptr)-offsetof(type, member)))
|
||||
|
@ -304,10 +303,10 @@ int32_t transClearBuffer(SConnBuffer* buf);
|
|||
int32_t transDestroyBuffer(SConnBuffer* buf);
|
||||
int32_t transAllocBuffer(SConnBuffer* connBuf, uv_buf_t* uvBuf);
|
||||
bool transReadComplete(SConnBuffer* connBuf);
|
||||
int transResetBuffer(SConnBuffer* connBuf, int8_t resetBuf);
|
||||
int transDumpFromBuffer(SConnBuffer* connBuf, char** buf, int8_t resetBuf);
|
||||
int32_t transResetBuffer(SConnBuffer* connBuf, int8_t resetBuf);
|
||||
int32_t transDumpFromBuffer(SConnBuffer* connBuf, char** buf, int8_t resetBuf);
|
||||
|
||||
int transSetConnOption(uv_tcp_t* stream, int keepalive);
|
||||
int32_t transSetConnOption(uv_tcp_t* stream, int keepalive);
|
||||
|
||||
void transRefSrvHandle(void* handle);
|
||||
void transUnrefSrvHandle(void* handle);
|
||||
|
@ -315,21 +314,24 @@ void transUnrefSrvHandle(void* handle);
|
|||
void transRefCliHandle(void* handle);
|
||||
void transUnrefCliHandle(void* handle);
|
||||
|
||||
int transReleaseCliHandle(void* handle);
|
||||
int transReleaseSrvHandle(void* handle);
|
||||
int32_t transReleaseCliHandle(void* handle);
|
||||
int32_t transReleaseSrvHandle(void* handle);
|
||||
|
||||
int transSendRequest(void* shandle, const SEpSet* pEpSet, STransMsg* pMsg, STransCtx* pCtx);
|
||||
int transSendRecv(void* shandle, const SEpSet* pEpSet, STransMsg* pMsg, STransMsg* pRsp);
|
||||
int transSendRecvWithTimeout(void* shandle, SEpSet* pEpSet, STransMsg* pMsg, STransMsg* pRsp, int8_t* epUpdated,
|
||||
int32_t transSendRequest(void* shandle, const SEpSet* pEpSet, STransMsg* pMsg, STransCtx* pCtx);
|
||||
int32_t transSendRecv(void* shandle, const SEpSet* pEpSet, STransMsg* pMsg, STransMsg* pRsp);
|
||||
int32_t transSendRecvWithTimeout(void* shandle, SEpSet* pEpSet, STransMsg* pMsg, STransMsg* pRsp, int8_t* epUpdated,
|
||||
int32_t timeoutMs);
|
||||
int transSendResponse(const STransMsg* msg);
|
||||
int transRegisterMsg(const STransMsg* msg);
|
||||
int transSetDefaultAddr(void* shandle, const char* ip, const char* fqdn);
|
||||
int32_t transSendRequestWithId(void* shandle, const SEpSet* pEpSet, STransMsg* pReq, int64_t* transpointId);
|
||||
int32_t transFreeConnById(void* shandle, int64_t transpointId);
|
||||
|
||||
int32_t transSendResponse(const STransMsg* msg);
|
||||
int32_t transRegisterMsg(const STransMsg* msg);
|
||||
int32_t transSetDefaultAddr(void* shandle, const char* ip, const char* fqdn);
|
||||
int32_t transSetIpWhiteList(void* shandle, void* arg, FilteFunc* func);
|
||||
|
||||
int transSockInfo2Str(struct sockaddr* sockname, char* dst);
|
||||
int32_t transSockInfo2Str(struct sockaddr* sockname, char* dst);
|
||||
|
||||
int64_t transAllocHandle();
|
||||
int32_t transAllocHandle(int64_t* refId);
|
||||
|
||||
void* transInitServer(uint32_t ip, uint32_t port, char* label, int numOfThreads, void* fp, void* shandle);
|
||||
void* transInitClient(uint32_t ip, uint32_t port, char* label, int numOfThreads, void* fp, void* shandle);
|
||||
|
|
|
@ -58,6 +58,8 @@ typedef struct {
|
|||
int32_t failFastThreshold;
|
||||
int32_t failFastInterval;
|
||||
|
||||
int8_t notWaitAvaliableConn; // 1: no delay, 0: delay
|
||||
|
||||
void (*cfp)(void* parent, SRpcMsg*, SEpSet*);
|
||||
bool (*retry)(int32_t code, tmsg_t msgType);
|
||||
bool (*startTimer)(int32_t code, tmsg_t msgType);
|
||||
|
|