diff --git a/deps/win/x64/dm_static/dmodule.lib b/deps/win/x64/dm_static/dmodule.lib index 36ce1d81d3..55afb81e3f 100644 Binary files a/deps/win/x64/dm_static/dmodule.lib and b/deps/win/x64/dm_static/dmodule.lib differ diff --git a/docs/zh/06-advanced/05-data-in/index.md b/docs/zh/06-advanced/05-data-in/index.md index 99dfbf098b..32d530acb5 100644 --- a/docs/zh/06-advanced/05-data-in/index.md +++ b/docs/zh/06-advanced/05-data-in/index.md @@ -1,276 +1,276 @@ ---- -sidebar_label: 数据写入 -title: 零代码数据源接入 -toc_max_heading_level: 4 ---- - -## 概述 - -TDengine Enterprise 配备了一个强大的可视化数据管理工具—taosExplorer。借助 taosExplorer,用户只须在浏览器中简单配置,就能轻松地向 TDengine 提交任务,实现以零代码方式将来自不同数据源的数据无缝导入 TDengine。在导入过程中,TDengine 会对数据进行自动提取、过滤和转换,以保证导入的数据质量。通过这种零代码数据源接入方式,TDengine 成功转型为一个卓越的时序大数据汇聚平台。用户无须部署额外的 ETL 工具,从而大大简化整体架构的设计,提高了数据处理效率。 - -下图展示了零代码接入平台的系统架构。 - -![零代码数据接入架构图](./data-in.png) - -## 支持的数据源 - -目前 TDengine 支持的数据源如下: - -1. Aveva PI System:一个工业数据管理和分析平台,前身为 OSIsoft PI System,它能够实时采集、整合、分析和可视化工业数据,助力企业实现智能化决策和精细化管理 -2. Aveva Historian:一个工业大数据分析软件,前身为 Wonderware Historian,专为工业环境设计,用于存储、管理和分析来自各种工业设备、传感器的实时和历史数据。 -3. OPC DA/UA:OPC 是 Open Platform Communications 的缩写,是一种开放式、标准化的通信协议,用于不同厂商的自动化设备之间进行数据交换。它最初由微软公司开发,旨在解决工业控制领域中不同设备之间互操作性差的问题。OPC 协议最初于 1996 年发布,当时称为 OPC DA (Data Access),主要用于实时数据采集和控制;2006 年,OPC 基金会发布了 OPC UA (Unified Architecture) 标准,它是一种基于服务的面向对象的协议,具有更高的灵活性和可扩展性,已成为 OPC 协议的主流版本。 -4. MQTT:Message Queuing Telemetry Transport 的缩写,一种基于发布/订阅模式的轻量级通讯协议,专为低开销、低带宽占用的即时通讯设计,广泛适用于物联网、小型设备、移动应用等领域。 -5. Kafka:由 Apache 软件基金会开发的一个开源流处理平台,主要用于处理实时数据,并提供一个统一、高通量、低延迟的消息系统。它具备高速度、可伸缩性、持久性和分布式设计等特点,使得它能够在每秒处理数十万次的读写操作,支持上千个客户端,同时保持数据的可靠性和可用性。 -6. OpenTSDB:基于 HBase 的分布式、可伸缩的时序数据库。它主要用于存储、索引和提供从大规模集群(包括网络设备、操作系统、应用程序等)中收集的指标数据,使这些数据更易于访问和图形化展示。 -7. CSV:Comma Separated Values 的缩写,是一种以逗号分隔的纯文本文件格式,通常用于电子表格或数据库软件。 -8. TDengine 2:泛指运行 TDengine 2.x 版本的 TDengine 实例。 -9. TDengine 3:泛指运行 TDengine 3.x 版本的 TDengine 实例。 -10. MySQL, PostgreSQL, Oracle 等关系型数据库。 - -## 数据提取、过滤和转换 - -因为数据源可以有多个,每个数据源的物理单位可能不一样,命名规则也不一样,时区也可能不同。为解决这个问题,TDengine 内置 ETL 功能,可以从数据源的数据包中解析、提取需要的数据,并进行过滤和转换,以保证写入数据的质量,提供统一的命名空间。具体的功能如下: - -1. 解析:使用 JSON Path 或正则表达式,从原始消息中解析字段 -2. 从列中提取或拆分:使用 split 或正则表达式,从一个原始字段中提取多个字段 -3. 过滤:只有表达式的值为 true 时,消息才会被写入 TDengine -4. 转换:建立解析后的字段和 TDengine 超级表字段之间的转换与映射关系。 - -下面详细讲解数据转换规则 - - -### 解析 - -仅非结构化的数据源需要这个步骤,目前 MQTT 和 Kafka 数据源会使用这个步骤提供的规则来解析非结构化数据,以初步获取结构化数据,即可以以字段描述的行列数据。在 explorer 中您需要提供示例数据和解析规则,来预览解析出以表格呈现的结构化数据。 - -#### 示例数据 - -![示例数据](./pic/transform-01.png) - -如图,textarea 输入框中就是示例数据,可以通过三种方式来获取示例数据: - -1. 直接在 textarea 中输入示例数据; -2. 点击右侧按钮 “从服务器检索” 则从配置的服务器获取示例数据,并追加到示例数据 textarea 中; -3. 上传文件,将文件内容追加到示例数据 textarea 中。 - -#### 解析 - -解析就是通过解析规则,将非结构化字符串解析为结构化数据。消息体的解析规则目前支持 JSON、Regex 和 UDT。 - -##### JSON 解析 - -如下 JSON 示例数据,可自动解析出字段:`groupid`、`voltage`、`current`、`ts`、`inuse`、`location`。 - -``` json -{"groupid": 170001, "voltage": "221V", "current": 12.3, "ts": "2023-12-18T22:12:00", "inuse": true, "location": "beijing.chaoyang.datun"} -{"groupid": 170001, "voltage": "220V", "current": 12.2, "ts": "2023-12-18T22:12:02", "inuse": true, "location": "beijing.chaoyang.datun"} -{"groupid": 170001, "voltage": "216V", "current": 12.5, "ts": "2023-12-18T22:12:04", "inuse": false, "location": "beijing.chaoyang.datun"} -``` - -如下嵌套结构的 JSON 数据,可自动解析出字段`groupid`、`data_voltage`、`data_current`、`ts`、`inuse`、`location_0_province`、`location_0_city`、`location_0_datun`,也可以选择要解析的字段,并设置解析的别名。 - -``` json -{"groupid": 170001, "data": { "voltage": "221V", "current": 12.3 }, "ts": "2023-12-18T22:12:00", "inuse": true, "location": [{"province": "beijing", "city":"chaoyang", "street": "datun"}]} -``` - -![JSON 解析](./pic/transform-02.png) - -##### Regex 正则表达式 - -可以使用正则表达式的**命名捕获组**从任何字符串(文本)字段中提取多个字段。如图所示,从 nginx 日志中提取访问ip、时间戳、访问的url等字段。 - -``` re -(?\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b)\s-\s-\s\[(?\d{2}/\w{3}/\d{4}:\d{2}:\d{2}:\d{2}\s\+\d{4})\]\s"(?[A-Z]+)\s(?[^\s"]+).*(?\d{3})\s(?\d+) -``` - -![Regex 解析](./pic/transform-03.png) - -##### UDT 自定义解析脚本 - -自定义 rhai 语法脚本解析输入数据(参考 `https://rhai.rs/book/` ),脚本目前仅支持 json 格式原始数据。 - -**输入**:脚本中可以使用参数 data, data 是原始数据 json 解析后的 Object Map; - -**输出**:输出的数据必须是数组。 - -例如对于数据,一次上报三相电压值,分别入到三个子表中。则需要对这类数据做解析 - -``` json -{ - "ts": "2024-06-27 18:00:00", - "voltage": "220.1,220.3,221.1", - "dev_id": "8208891" -} -``` - -那么可以使用如下脚本来提取三个电压数据。 - -``` -let v3 = data["voltage"].split(","); - -[ -#{"ts": data["ts"], "val": v3[0], "dev_id": data["dev_id"]}, -#{"ts": data["ts"], "val": v3[1], "dev_id": data["dev_id"]}, -#{"ts": data["ts"], "val": v3[2], "dev_id": data["dev_id"]} -] -``` - -最终解析结果如下所示: - -![UDT](./pic/transform-udf.png) - -### 提取或拆分 - -解析后的数据,可能还无法满足目标表的数据要求。比如智能表原始采集数据如下( json 格式): - -``` json -{"groupid": 170001, "voltage": "221V", "current": 12.3, "ts": "2023-12-18T22:12:00", "inuse": true, "location": "beijing.chaoyang.datun"} -{"groupid": 170001, "voltage": "220V", "current": 12.2, "ts": "2023-12-18T22:12:02", "inuse": true, "location": "beijing.chaoyang.datun"} -{"groupid": 170001, "voltage": "216V", "current": 12.5, "ts": "2023-12-18T22:12:04", "inuse": false, "location": "beijing.chaoyang.datun"} -``` - -使用 json 规则解析出的电压是字符串表达的带单位形式,最终入库希望能使用 int 类型记录电压值和电流值,便于统计分析,此时就需要对电压进一步拆分;另外日期期望拆分为日期和时间入库。 - -如下图所示可以对源字段`ts`使用 split 规则拆分成日期和时间,对字段`voltage`使用 regex 提取出电压值和电压单位。split 规则需要设置**分隔符**和**拆分数量**,拆分后的字段命名规则为`{原字段名}_{顺序号}`,Regex 规则同解析过程中的一样,使用**命名捕获组**命名提取字段。 - -![拆分和提取](./pic/transform-04.png) - -### 过滤 - -过滤功能可以设置过滤条件,满足条件的数据行 才会被写入目标表。过滤条件表达式的结果必须是 boolean 类型。在编写过滤条件前,必须确定 解析字段的类型,根据解析字段的类型,可以使用判断函数、比较操作符(`>`、`>=`、`<=`、`<`、`==`、`!=`)来判断。 - -#### 字段类型及转换 - -只有明确解析出的每个字段的类型,才能使用正确的语法做数据过滤。 - -使用 json 规则解析出的字段,按照属性值来自动设置类型: - -1. bool 类型:"inuse": true -2. int 类型:"voltage": 220 -3. float 类型:"current" : 12.2 -4. String 类型:"location": "MX001" - -使用 regex 规则解析的数据都是 string 类型。 -使用 split 和 regex 提取或拆分的数据是 string 类型。 - -如果提取出的数据类型不是预期中的类型,可以做数据类型转换。常用的数据类型转换就是把字符串转换成为数值类型。支持的转换函数如下: - -|Function|From type|To type|e.g.| -|:----|:----|:----|:----| -| parse_int | string | int | parse_int("56") // 结果为整数 56 | -| parse_float | string | float | parse_float("12.3") // 结果为浮点数 12.3 | - -#### 判断表达式 - -不同的数据类型有各自判断表达式的写法。 - -##### BOOL 类型 - -可以使用变量或者使用操作符`!`,比如对于字段 "inuse": true,可以编写以下表达式: - -> 1. inuse -> 2. !inuse - -##### 数值类型(int/float) - -数值类型支持使用比较操作符`==`、`!=`、`>`、`>=`、`<`、`<=`。 - -##### 字符串类型 - -使用比较操作符,比较字符串。 - -字符串函数 - -|Function|Description|e.g.| -|:----|:----|:----| -| is_empty | returns true if the string is empty | s.is_empty() | -| contains | checks if a certain character or sub-string occurs in the string | s.contains("substring") | -| starts_with | returns true if the string starts with a certain string | s.starts_with("prefix") | -| ends_with | returns true if the string ends with a certain string | s.ends_with("suffix") | -| len | returns the number of characters (not number of bytes) in the string,must be used with comparison operator | s.len == 5 判断字符串长度是否为5;len作为属性返回 int ,和前四个函数有区别,前四个直接返回 bool。 | - -##### 复合表达式 - -多个判断表达式,可以使用逻辑操作符(&&、||、!)来组合。 -比如下面的表达式表示获取北京市安装的并且电压值大于 200 的智能表数据。 - -> location.starts_with("beijing") && voltage > 200 - -### 映射 - -映射是将解析、提取、拆分的**源字段**对应到**目标表字段**,可以直接对应,也可以通过一些规则计算后再映射到目标表。 - -#### 选择目标超级表 - -选择目标超级表后,会加载出超级表所有的 tags 和 columns。 -源字段根据名称自动使用 mapping 规则映射到目标超级表的 tag 和 column。 -例如有如下解析、提取、拆分后的预览数据: - -#### 映射规则 - -支持的映射规则如下表所示: - -|rule|description| -|:----|:----| -| mapping | 直接映射,需要选择映射源字段。| -| value | 常量,可以输入字符串常量,也可以是数值常量,输入的常量值直接入库。| -| generator | 生成器,目前仅支持时间戳生成器 now,入库时会将当前时间入库。| -| join | 字符串连接器,可指定连接字符拼接选择的多个源字段。| -| format | **字符串格式化工具**,填写格式化字符串,比如有三个源字段 year, month, day 分别表示年月日,入库希望以yyyy-MM-dd的日期格式入库,则可以提供格式化字符串为 `${year}-${month}-${day}`。其中`${}`作为占位符,占位符中可以是一个源字段,也可以是 string 类型字段的函数处理| -| sum | 选择多个数值型字段做加法计算。| -| expr | **数值运算表达式**,可以对数值型字段做更加复杂的函数处理和数学运算。| - -##### format 中支持的字符串处理函数 - -|Function|description|e.g.| -|:----|:----|:----| -| pad(len, pad_chars) | pads the string with a character or a string to at least a specified length | "1.2".pad(5, '0') // 结果为"1.200" | -|trim|trims the string of whitespace at the beginning and end|" abc ee ".trim() // 结果为"abc ee"| -|sub_string(start_pos, len)|extracts a sub-string,两个参数:
1. start position, counting from end if < 0
2. (optional) number of characters to extract, none if ≤ 0, to end if omitted|"012345678".sub_string(5) // "5678"
"012345678".sub_string(5, 2) // "56"
"012345678".sub_string(-2) // "78"| -|replace(substring, replacement)|replaces a sub-string with another|"012345678".replace("012", "abc") // "abc345678"| - -##### expr 数学计算表达式 - -基本数学运算支持加`+`、减`-`、乘`*`、除`/`。 - -比如数据源采集数值以设置度为单位,目标库存储华氏度温度值。那么就需要对采集的温度数据做转换。 - -解析的源字段为`temperature`,则需要使用表达式 `temperature * 1.8 + 32`。 - -数值表达式中也支持使用数学函数,可用的数学函数如下表所示: - -|Function|description|e.g.| -|:----|:----|:----| -|sin、cos、tan、sinh、cosh|Trigonometry|a.sin() | -|asin、acos、atan、 asinh、acosh|arc-trigonometry|a.asin()| -|sqrt|Square root|a.sqrt() // 4.sqrt() == 2| -|exp|Exponential|a.exp()| -|ln、log|Logarithmic|a.ln() // e.ln() == 1
a.log() // 10.log() == 1| -|floor、ceiling、round、int、fraction|rounding|a.floor() // (4.2).floor() == 4
a.ceiling() // (4.2).ceiling() == 5
a.round() // (4.2).round() == 4
a.int() // (4.2).int() == 4
a.fraction() // (4.2).fraction() == 0.2| - -#### 子表名映射 - -子表名类型为字符串,可以使用映射规则中的字符串格式化 format 表达式定义子表名。 - -## 任务的创建 - -下面以 MQTT 数据源为例,介绍如何创建一个 MQTT 类型的任务,从 MQTT Broker 消费数据,并写入 TDengine。 - -1. 登录至 taosExplorer 以后,点击左侧导航栏上的“数据写入”,即可进入任务列表页面 -2. 在任务列表页面,点击“+ 新增数据源”,即可进入任务创建页面 -3. 输入任务名称后,选择类型为 MQTT, 然后可以创建一个新的代理,或者选择已创建的代理 -4. 输入 MQTT broker 的 IP 地址和端口号,例如:192.168.1.100:1883 -5. 配置认证和 SSL 加密: - - 如果 MQTT broker 开启了用户认证,则在认证部分,输入 MQTT broker 的用户名和密码; - - 如果 MQTT broker 开启了 SSL 加密,则可以打开页面上的 SSL 证书开关,并上传 CA 的证书,以及客户端的证书和私钥文件; -6. 在“采集配置“部分,可选择 MQTT 协议的版本,目前支持 3.1, 3.1.1, 5.0 三个版本;配置 Client ID 时要注意,如果对同一个 MQTT broker 创建了多个任务,Client ID 应不同,否则会造成 Client ID 冲突,导致任务无法正常运行;在对主题和 QoS 进行配置时,需要使用 `::` 的形式,即订阅的主题与 QoS 之间要使用两个冒号分隔,其中 QoS 的取值范围为 0, 1, 2, 分别代表 at most once, at lease once, exactly once;配置完成以上信息后,可以点击“检查连通性”按钮,对以上配置进行检查,如果连通性检查失败,请按照页面上返回的具体错误提示进行修改; -7. 在从 MQTT broker 同步数据的过程中,taosX 还支持对消息体中的字段进行提取,过滤、映射等操作。在位于 “Payload 转换”下方的文本框中,可以直接输入输入消息体样例,或是以上传文件的方式导入,以后还会支持直接从所配置的服务器中检索样例消息; -8. 对消息体字段的提取,目前支持 2 种方式:JSON 和正则表达式。对于简单的 key/value 格式的 JSON 数据,可以直接点击提取按钮,即可展示解析出的字段名;对于复杂的 JSON 数据,可以使用 JSON Path 提取感兴趣的字段;当使用正则表达式提取字段时,要保证正则表达式的正确性; -9. 消息体中的字段被解析后,可以基于解析出的字段名设置过滤规则,只有满足过滤规则的数据,才会写入 TDengine,否则会忽略该消息;例如:可以配置过滤规则为 voltage > 200,即只有当电压大于 200V 的数据才会被同步至 TDengine; -10. 最后,在配置完消息体中的字段和超级表中的字段的映射规则后,就可以提交任务了;除了基本的映射以外,在这里还可以对消息中字段的值进行转换,例如:可以通过表达式 (expr) 将原消息体中的电压和电流,计算为功率后再写入 TDengine; -11. 任务提交后,会自动返回任务列表页面,如果提交成功,任务的状态会切换至“运行中”,如果提交失败,可通过查看该任务的活动日志,查找错误原因; -12. 对于运行中的任务,点击指标的查看按钮,可以查看该任务的详细运行指标,弹出窗口划分为 2 个标签页,分别展示该任务多次运行的累计指标和本次运行的指标,这些指标每 2 秒钟会自动刷新一次。 - -## 任务管理 - +--- +sidebar_label: 数据接入 +title: 零代码第三方数据接入 +toc_max_heading_level: 4 +--- + +## 概述 + +TDengine Enterprise 配备了一个强大的可视化数据管理工具—taosExplorer。借助 taosExplorer,用户只须在浏览器中简单配置,就能轻松地向 TDengine 提交任务,实现以零代码方式将来自不同数据源的数据无缝导入 TDengine。在导入过程中,TDengine 会对数据进行自动提取、过滤和转换,以保证导入的数据质量。通过这种零代码数据源接入方式,TDengine 成功转型为一个卓越的时序大数据汇聚平台。用户无须部署额外的 ETL 工具,从而大大简化整体架构的设计,提高了数据处理效率。 + +下图展示了零代码接入平台的系统架构。 + +![零代码数据接入架构图](./data-in.png) + +## 支持的数据源 + +目前 TDengine 支持的数据源如下: + +1. Aveva PI System:一个工业数据管理和分析平台,前身为 OSIsoft PI System,它能够实时采集、整合、分析和可视化工业数据,助力企业实现智能化决策和精细化管理 +2. Aveva Historian:一个工业大数据分析软件,前身为 Wonderware Historian,专为工业环境设计,用于存储、管理和分析来自各种工业设备、传感器的实时和历史数据。 +3. OPC DA/UA:OPC 是 Open Platform Communications 的缩写,是一种开放式、标准化的通信协议,用于不同厂商的自动化设备之间进行数据交换。它最初由微软公司开发,旨在解决工业控制领域中不同设备之间互操作性差的问题。OPC 协议最初于 1996 年发布,当时称为 OPC DA (Data Access),主要用于实时数据采集和控制;2006 年,OPC 基金会发布了 OPC UA (Unified Architecture) 标准,它是一种基于服务的面向对象的协议,具有更高的灵活性和可扩展性,已成为 OPC 协议的主流版本。 +4. MQTT:Message Queuing Telemetry Transport 的缩写,一种基于发布/订阅模式的轻量级通讯协议,专为低开销、低带宽占用的即时通讯设计,广泛适用于物联网、小型设备、移动应用等领域。 +5. Kafka:由 Apache 软件基金会开发的一个开源流处理平台,主要用于处理实时数据,并提供一个统一、高通量、低延迟的消息系统。它具备高速度、可伸缩性、持久性和分布式设计等特点,使得它能够在每秒处理数十万次的读写操作,支持上千个客户端,同时保持数据的可靠性和可用性。 +6. OpenTSDB:基于 HBase 的分布式、可伸缩的时序数据库。它主要用于存储、索引和提供从大规模集群(包括网络设备、操作系统、应用程序等)中收集的指标数据,使这些数据更易于访问和图形化展示。 +7. CSV:Comma Separated Values 的缩写,是一种以逗号分隔的纯文本文件格式,通常用于电子表格或数据库软件。 +8. TDengine 2:泛指运行 TDengine 2.x 版本的 TDengine 实例。 +9. TDengine 3:泛指运行 TDengine 3.x 版本的 TDengine 实例。 +10. MySQL, PostgreSQL, Oracle 等关系型数据库。 + +## 数据提取、过滤和转换 + +因为数据源可以有多个,每个数据源的物理单位可能不一样,命名规则也不一样,时区也可能不同。为解决这个问题,TDengine 内置 ETL 功能,可以从数据源的数据包中解析、提取需要的数据,并进行过滤和转换,以保证写入数据的质量,提供统一的命名空间。具体的功能如下: + +1. 解析:使用 JSON Path 或正则表达式,从原始消息中解析字段 +2. 从列中提取或拆分:使用 split 或正则表达式,从一个原始字段中提取多个字段 +3. 过滤:只有表达式的值为 true 时,消息才会被写入 TDengine +4. 转换:建立解析后的字段和 TDengine 超级表字段之间的转换与映射关系。 + +下面详细讲解数据转换规则 + + +### 解析 + +仅非结构化的数据源需要这个步骤,目前 MQTT 和 Kafka 数据源会使用这个步骤提供的规则来解析非结构化数据,以初步获取结构化数据,即可以以字段描述的行列数据。在 explorer 中您需要提供示例数据和解析规则,来预览解析出以表格呈现的结构化数据。 + +#### 示例数据 + +![示例数据](./pic/transform-01.png) + +如图,textarea 输入框中就是示例数据,可以通过三种方式来获取示例数据: + +1. 直接在 textarea 中输入示例数据; +2. 点击右侧按钮 “从服务器检索” 则从配置的服务器获取示例数据,并追加到示例数据 textarea 中; +3. 上传文件,将文件内容追加到示例数据 textarea 中。 + +#### 解析 + +解析就是通过解析规则,将非结构化字符串解析为结构化数据。消息体的解析规则目前支持 JSON、Regex 和 UDT。 + +##### JSON 解析 + +如下 JSON 示例数据,可自动解析出字段:`groupid`、`voltage`、`current`、`ts`、`inuse`、`location`。 + +``` json +{"groupid": 170001, "voltage": "221V", "current": 12.3, "ts": "2023-12-18T22:12:00", "inuse": true, "location": "beijing.chaoyang.datun"} +{"groupid": 170001, "voltage": "220V", "current": 12.2, "ts": "2023-12-18T22:12:02", "inuse": true, "location": "beijing.chaoyang.datun"} +{"groupid": 170001, "voltage": "216V", "current": 12.5, "ts": "2023-12-18T22:12:04", "inuse": false, "location": "beijing.chaoyang.datun"} +``` + +如下嵌套结构的 JSON 数据,可自动解析出字段`groupid`、`data_voltage`、`data_current`、`ts`、`inuse`、`location_0_province`、`location_0_city`、`location_0_datun`,也可以选择要解析的字段,并设置解析的别名。 + +``` json +{"groupid": 170001, "data": { "voltage": "221V", "current": 12.3 }, "ts": "2023-12-18T22:12:00", "inuse": true, "location": [{"province": "beijing", "city":"chaoyang", "street": "datun"}]} +``` + +![JSON 解析](./pic/transform-02.png) + +##### Regex 正则表达式 + +可以使用正则表达式的**命名捕获组**从任何字符串(文本)字段中提取多个字段。如图所示,从 nginx 日志中提取访问ip、时间戳、访问的url等字段。 + +``` re +(?\b(?:[0-9]{1,3}\.){3}[0-9]{1,3}\b)\s-\s-\s\[(?\d{2}/\w{3}/\d{4}:\d{2}:\d{2}:\d{2}\s\+\d{4})\]\s"(?[A-Z]+)\s(?[^\s"]+).*(?\d{3})\s(?\d+) +``` + +![Regex 解析](./pic/transform-03.png) + +##### UDT 自定义解析脚本 + +自定义 rhai 语法脚本解析输入数据(参考 `https://rhai.rs/book/` ),脚本目前仅支持 json 格式原始数据。 + +**输入**:脚本中可以使用参数 data, data 是原始数据 json 解析后的 Object Map; + +**输出**:输出的数据必须是数组。 + +例如对于数据,一次上报三相电压值,分别入到三个子表中。则需要对这类数据做解析 + +``` json +{ + "ts": "2024-06-27 18:00:00", + "voltage": "220.1,220.3,221.1", + "dev_id": "8208891" +} +``` + +那么可以使用如下脚本来提取三个电压数据。 + +``` +let v3 = data["voltage"].split(","); + +[ +#{"ts": data["ts"], "val": v3[0], "dev_id": data["dev_id"]}, +#{"ts": data["ts"], "val": v3[1], "dev_id": data["dev_id"]}, +#{"ts": data["ts"], "val": v3[2], "dev_id": data["dev_id"]} +] +``` + +最终解析结果如下所示: + +![UDT](./pic/transform-udf.png) + +### 提取或拆分 + +解析后的数据,可能还无法满足目标表的数据要求。比如智能表原始采集数据如下( json 格式): + +``` json +{"groupid": 170001, "voltage": "221V", "current": 12.3, "ts": "2023-12-18T22:12:00", "inuse": true, "location": "beijing.chaoyang.datun"} +{"groupid": 170001, "voltage": "220V", "current": 12.2, "ts": "2023-12-18T22:12:02", "inuse": true, "location": "beijing.chaoyang.datun"} +{"groupid": 170001, "voltage": "216V", "current": 12.5, "ts": "2023-12-18T22:12:04", "inuse": false, "location": "beijing.chaoyang.datun"} +``` + +使用 json 规则解析出的电压是字符串表达的带单位形式,最终入库希望能使用 int 类型记录电压值和电流值,便于统计分析,此时就需要对电压进一步拆分;另外日期期望拆分为日期和时间入库。 + +如下图所示可以对源字段`ts`使用 split 规则拆分成日期和时间,对字段`voltage`使用 regex 提取出电压值和电压单位。split 规则需要设置**分隔符**和**拆分数量**,拆分后的字段命名规则为`{原字段名}_{顺序号}`,Regex 规则同解析过程中的一样,使用**命名捕获组**命名提取字段。 + +![拆分和提取](./pic/transform-04.png) + +### 过滤 + +过滤功能可以设置过滤条件,满足条件的数据行 才会被写入目标表。过滤条件表达式的结果必须是 boolean 类型。在编写过滤条件前,必须确定 解析字段的类型,根据解析字段的类型,可以使用判断函数、比较操作符(`>`、`>=`、`<=`、`<`、`==`、`!=`)来判断。 + +#### 字段类型及转换 + +只有明确解析出的每个字段的类型,才能使用正确的语法做数据过滤。 + +使用 json 规则解析出的字段,按照属性值来自动设置类型: + +1. bool 类型:"inuse": true +2. int 类型:"voltage": 220 +3. float 类型:"current" : 12.2 +4. String 类型:"location": "MX001" + +使用 regex 规则解析的数据都是 string 类型。 +使用 split 和 regex 提取或拆分的数据是 string 类型。 + +如果提取出的数据类型不是预期中的类型,可以做数据类型转换。常用的数据类型转换就是把字符串转换成为数值类型。支持的转换函数如下: + +|Function|From type|To type|e.g.| +|:----|:----|:----|:----| +| parse_int | string | int | parse_int("56") // 结果为整数 56 | +| parse_float | string | float | parse_float("12.3") // 结果为浮点数 12.3 | + +#### 判断表达式 + +不同的数据类型有各自判断表达式的写法。 + +##### BOOL 类型 + +可以使用变量或者使用操作符`!`,比如对于字段 "inuse": true,可以编写以下表达式: + +> 1. inuse +> 2. !inuse + +##### 数值类型(int/float) + +数值类型支持使用比较操作符`==`、`!=`、`>`、`>=`、`<`、`<=`。 + +##### 字符串类型 + +使用比较操作符,比较字符串。 + +字符串函数 + +|Function|Description|e.g.| +|:----|:----|:----| +| is_empty | returns true if the string is empty | s.is_empty() | +| contains | checks if a certain character or sub-string occurs in the string | s.contains("substring") | +| starts_with | returns true if the string starts with a certain string | s.starts_with("prefix") | +| ends_with | returns true if the string ends with a certain string | s.ends_with("suffix") | +| len | returns the number of characters (not number of bytes) in the string,must be used with comparison operator | s.len == 5 判断字符串长度是否为5;len作为属性返回 int ,和前四个函数有区别,前四个直接返回 bool。 | + +##### 复合表达式 + +多个判断表达式,可以使用逻辑操作符(&&、||、!)来组合。 +比如下面的表达式表示获取北京市安装的并且电压值大于 200 的智能表数据。 + +> location.starts_with("beijing") && voltage > 200 + +### 映射 + +映射是将解析、提取、拆分的**源字段**对应到**目标表字段**,可以直接对应,也可以通过一些规则计算后再映射到目标表。 + +#### 选择目标超级表 + +选择目标超级表后,会加载出超级表所有的 tags 和 columns。 +源字段根据名称自动使用 mapping 规则映射到目标超级表的 tag 和 column。 +例如有如下解析、提取、拆分后的预览数据: + +#### 映射规则 + +支持的映射规则如下表所示: + +|rule|description| +|:----|:----| +| mapping | 直接映射,需要选择映射源字段。| +| value | 常量,可以输入字符串常量,也可以是数值常量,输入的常量值直接入库。| +| generator | 生成器,目前仅支持时间戳生成器 now,入库时会将当前时间入库。| +| join | 字符串连接器,可指定连接字符拼接选择的多个源字段。| +| format | **字符串格式化工具**,填写格式化字符串,比如有三个源字段 year, month, day 分别表示年月日,入库希望以yyyy-MM-dd的日期格式入库,则可以提供格式化字符串为 `${year}-${month}-${day}`。其中`${}`作为占位符,占位符中可以是一个源字段,也可以是 string 类型字段的函数处理| +| sum | 选择多个数值型字段做加法计算。| +| expr | **数值运算表达式**,可以对数值型字段做更加复杂的函数处理和数学运算。| + +##### format 中支持的字符串处理函数 + +|Function|description|e.g.| +|:----|:----|:----| +| pad(len, pad_chars) | pads the string with a character or a string to at least a specified length | "1.2".pad(5, '0') // 结果为"1.200" | +|trim|trims the string of whitespace at the beginning and end|" abc ee ".trim() // 结果为"abc ee"| +|sub_string(start_pos, len)|extracts a sub-string,两个参数:
1. start position, counting from end if < 0
2. (optional) number of characters to extract, none if ≤ 0, to end if omitted|"012345678".sub_string(5) // "5678"
"012345678".sub_string(5, 2) // "56"
"012345678".sub_string(-2) // "78"| +|replace(substring, replacement)|replaces a sub-string with another|"012345678".replace("012", "abc") // "abc345678"| + +##### expr 数学计算表达式 + +基本数学运算支持加`+`、减`-`、乘`*`、除`/`。 + +比如数据源采集数值以设置度为单位,目标库存储华氏度温度值。那么就需要对采集的温度数据做转换。 + +解析的源字段为`temperature`,则需要使用表达式 `temperature * 1.8 + 32`。 + +数值表达式中也支持使用数学函数,可用的数学函数如下表所示: + +|Function|description|e.g.| +|:----|:----|:----| +|sin、cos、tan、sinh、cosh|Trigonometry|a.sin() | +|asin、acos、atan、 asinh、acosh|arc-trigonometry|a.asin()| +|sqrt|Square root|a.sqrt() // 4.sqrt() == 2| +|exp|Exponential|a.exp()| +|ln、log|Logarithmic|a.ln() // e.ln() == 1
a.log() // 10.log() == 1| +|floor、ceiling、round、int、fraction|rounding|a.floor() // (4.2).floor() == 4
a.ceiling() // (4.2).ceiling() == 5
a.round() // (4.2).round() == 4
a.int() // (4.2).int() == 4
a.fraction() // (4.2).fraction() == 0.2| + +#### 子表名映射 + +子表名类型为字符串,可以使用映射规则中的字符串格式化 format 表达式定义子表名。 + +## 任务的创建 + +下面以 MQTT 数据源为例,介绍如何创建一个 MQTT 类型的任务,从 MQTT Broker 消费数据,并写入 TDengine。 + +1. 登录至 taosExplorer 以后,点击左侧导航栏上的“数据写入”,即可进入任务列表页面 +2. 在任务列表页面,点击“+ 新增数据源”,即可进入任务创建页面 +3. 输入任务名称后,选择类型为 MQTT, 然后可以创建一个新的代理,或者选择已创建的代理 +4. 输入 MQTT broker 的 IP 地址和端口号,例如:192.168.1.100:1883 +5. 配置认证和 SSL 加密: + - 如果 MQTT broker 开启了用户认证,则在认证部分,输入 MQTT broker 的用户名和密码; + - 如果 MQTT broker 开启了 SSL 加密,则可以打开页面上的 SSL 证书开关,并上传 CA 的证书,以及客户端的证书和私钥文件; +6. 在“采集配置“部分,可选择 MQTT 协议的版本,目前支持 3.1, 3.1.1, 5.0 三个版本;配置 Client ID 时要注意,如果对同一个 MQTT broker 创建了多个任务,Client ID 应不同,否则会造成 Client ID 冲突,导致任务无法正常运行;在对主题和 QoS 进行配置时,需要使用 `::` 的形式,即订阅的主题与 QoS 之间要使用两个冒号分隔,其中 QoS 的取值范围为 0, 1, 2, 分别代表 at most once, at lease once, exactly once;配置完成以上信息后,可以点击“检查连通性”按钮,对以上配置进行检查,如果连通性检查失败,请按照页面上返回的具体错误提示进行修改; +7. 在从 MQTT broker 同步数据的过程中,taosX 还支持对消息体中的字段进行提取,过滤、映射等操作。在位于 “Payload 转换”下方的文本框中,可以直接输入输入消息体样例,或是以上传文件的方式导入,以后还会支持直接从所配置的服务器中检索样例消息; +8. 对消息体字段的提取,目前支持 2 种方式:JSON 和正则表达式。对于简单的 key/value 格式的 JSON 数据,可以直接点击提取按钮,即可展示解析出的字段名;对于复杂的 JSON 数据,可以使用 JSON Path 提取感兴趣的字段;当使用正则表达式提取字段时,要保证正则表达式的正确性; +9. 消息体中的字段被解析后,可以基于解析出的字段名设置过滤规则,只有满足过滤规则的数据,才会写入 TDengine,否则会忽略该消息;例如:可以配置过滤规则为 voltage > 200,即只有当电压大于 200V 的数据才会被同步至 TDengine; +10. 最后,在配置完消息体中的字段和超级表中的字段的映射规则后,就可以提交任务了;除了基本的映射以外,在这里还可以对消息中字段的值进行转换,例如:可以通过表达式 (expr) 将原消息体中的电压和电流,计算为功率后再写入 TDengine; +11. 任务提交后,会自动返回任务列表页面,如果提交成功,任务的状态会切换至“运行中”,如果提交失败,可通过查看该任务的活动日志,查找错误原因; +12. 对于运行中的任务,点击指标的查看按钮,可以查看该任务的详细运行指标,弹出窗口划分为 2 个标签页,分别展示该任务多次运行的累计指标和本次运行的指标,这些指标每 2 秒钟会自动刷新一次。 + +## 任务管理 + 在任务列表页面,还可以对任务进行启动、停止、查看、删除、复制等操作,也可以查看各个任务的运行情况,包括写入的记录条数、流量等。 \ No newline at end of file diff --git a/docs/zh/07-operation/05-monitor.md b/docs/zh/07-operation/05-monitor.md index c5b4cbac06..cd8a9772cd 100644 --- a/docs/zh/07-operation/05-monitor.md +++ b/docs/zh/07-operation/05-monitor.md @@ -8,57 +8,13 @@ toc_max_heading_level: 4 至于如何获取和使用这些监控数据,用户可以使用第三方的监测工具比如 Zabbix 来获取这些保存的系统监测数据,进而将 TDengine 的运行状况无缝集成到现有的 IT 监控系统中。也可以使用 TDengine 提供的 TDinsight 插件,使用该插件用户可以通过 Grafana 平台直观地展示和管理这些监控信息,如下图所示。这为用户提供了灵活的监控选项,以满足不同场景下的运维需求。 -~[通过监控组件管理监控信息](./grafana.png) +![通过监控组件管理监控信息](./grafana.png) ## 配置 taosKeeper 因为 TDengine 的监控数据都通过 taosKeeper 上报并存储,所以本节先介绍 taosKeeper 的配置。 -taosKeeper 的配置文件默认位于 `/etc/taos/taoskeeper.toml`。 下面为一个示例配置文件,更多详细信息见参考手册。其中最为关键的一个配置项是 `database`,它决定了收集到的监控数据存储在目标系统的哪个数据库中。 - -```toml -# gin 框架是否启用 debug -debug = false - -# 服务监听端口, 默认为 6043 -port = 6043 - -# 日志级别,包含 panic、error、info、debug、trace等 -loglevel = "info" - -# 程序中使用协程池的大小 -gopoolsize = 50000 - -# 查询 TDengine 监控数据轮询间隔 -RotationInterval = "15s" - -[tdengine] -host = "127.0.0.1" -port = 6041 -username = "root" -password = "taosdata" - -# 需要被监控的 taosAdapter -[taosAdapter] -address = ["127.0.0.1:6041"] - -[metrics] -# 监控指标前缀 -prefix = "taos" - -# 集群数据的标识符 -cluster = "production" - -# 存放监控数据的数据库 -database = "log" - -# 指定需要监控的普通表 -tables = [] - -# database options for db storing metrics data -[metrics.databaseoptions] -cachemodel = "none" -``` +taosKeeper 的配置文件默认位于 `/etc/taos/taoskeeper.toml`。 详细配置见 [参考手册](../../reference/components/taoskeeper/#配置文件)。其中最为关键的一个配置项是 `database`,它决定了收集到的监控数据存储在目标系统的哪个数据库中。 ## 监控 taosd @@ -66,9 +22,9 @@ cachemodel = "none" 为了简化用户在 TDengine 监控方面的配置工作,TDengine 提供了一个名为 TDinsight 的 Grafana 插件。该插件与 taosKeeper 协同工作,能够实时监控 TDengine 的各项性能指标。 -通过集成 Grafana 和 TDengine 数据源插件,TDinsight 能够读取 taosKeeper 收集并存储的监控数据。这使得用户可以在 Grafana 平台上直观地查看 TDengine 集群的状态、节点信息、读写请求以及资源使用情况等关键指标,实现数据的可视化展示。 +通过集成 Grafana 和 TDengine 数据源插件,TDinsight 能够读取 taosKeeper 收集的监控数据。这使得用户可以在 Grafana 平台上直观地查看 TDengine 集群的状态、节点信息、读写请求以及资源使用情况等关键指标,实现数据的可视化展示。 -此外,TDinsight 还具备针对 vnode、dnode 和 mnode 节点的异常状态告警功能,为开发者提供实时的集群运行状态监控,确保 TDengine 集群的稳定性和可靠性。以下是TDinsight 的详细使用说明,以帮助你充分利用这一强大工具。 +以下是TDinsight 的详细使用说明,以帮助你充分利用这一强大工具。 #### 前置条件 @@ -76,314 +32,31 @@ cachemodel = "none" - TDengine 已安装并正常运行。 - taosAdapter 已经安装并正常运行。 - taosKeeper 已经安装并正常运行。 -- Grafana 已安装并正常运行,以下介绍以 Grafna 10.4.0 为例。 +- Grafana 已安装并正常运行,以下介绍以 Grafna 11.0.0 为例。 同时记录以下信息。 -- taosAdapter 的 RESTful 接口地址,如 http://www.example.com:6041。 +- taosAdapter 的 RESTful 接口地址,如 `http://www.example.com:6041`。 - TDengine 集群的认证信息,包括用户名及密码。 #### 导入仪表盘 TDengine 数据源插件已被提交至 Grafana 官网,完成插件的安装和数据源的创建后,可以进行 TDinsight 仪表盘的导入。 -在 Grafana 的 Home-Dashboards 页面,点击位于右上角的 New → mport 按钮,即可进入 Dashboard 的导入页面,它支持以下两种导入方式。 +在 Grafana 的 ”Home“ -> ”Dashboards“ 页面,点击位于右上角的 ”New“ -> ”import“ 按钮,即可进入 Dashboard 的导入页面,它支持以下两种导入方式。 - Dashboard ID:18180。 - Dashboard URL:https://grafana.com/grafana/dashboards/18180-tdinsight-for-3-x/ -填写以上 Dashboard ID 或 Dashboard URL 以后,点击 Load 按钮,按照向导操作,即可完成导入。导入成功后,Dashboards 列表页面会出现 TDinsight for 3.x 仪盘,点击进入后,就可以看到 TDinsight 中已创建的各个指标的面板,如下图所示: +填写以上 Dashboard ID 或 Dashboard URL 以后,点击 ”Load“ 按钮,按照向导操作,即可完成导入。导入成功后,Dashboards 列表页面会出现 ”TDinsight for 3.x“ 仪表盘,点击进入后,就可以看到 TDinsight 中已创建的各个指标的面板,如下图所示: -![TDinsight 界面示例](./tdinsight.png) +![TDinsight 界面示例](./TDinsight-1-cluster-status.webp) -**注意** 在 TDinsight 界面左上角的 Log from 下拉列表中可以选择 log 数据库。 +**注意** 在 TDinsight 界面左上角的 ”Log from“ 下拉列表中可以选择 `log` 数据库。 -### taosd 监控数据 +### TDengine V3 监控数据 -TDinsight dashboard 数据来源于 log 库(存放监控数据的默认 db,可以在 taoskeeper 配置文件中修改。以下是由 taosd 上报由 taosKeeper 存储在 log 库中的数据。 - -1. taosd\_cluster\_basic 表 - -`taosd_cluster_basic` 表记录集群基础信息。 - -|field|type|is\_tag|comment| -|:----|:---|:-----|:------| -|ts|TIMESTAMP||timestamp| -|first\_ep|VARCHAR||集群 first ep| -|first\_ep\_dnode\_id|INT||集群 first ep 的 dnode id| -|cluster_version|VARCHAR||tdengine version。例如:3.0.4.0| -|cluster\_id|VARCHAR|TAG|cluster id| - -2. taosd\_cluster\_info 表 - -`taosd_cluster_info` 表记录集群信息。 - -|field|type|is\_tag|comment| -|:----|:---|:-----|:------| -|ts|TIMESTAMP||timestamp| -|cluster_uptime|DOUBLE||当前 master 节点的uptime。单位:秒| -|dbs\_total|DOUBLE||database 总数| -|tbs\_total|DOUBLE||当前集群 table 总数| -|stbs\_total|DOUBLE||当前集群 stable 总数| -|dnodes\_total|DOUBLE||当前集群 dnode 总数| -|dnodes\_alive|DOUBLE||当前集群 dnode 存活总数| -|mnodes\_total|DOUBLE||当前集群 mnode 总数| -|mnodes\_alive|DOUBLE||当前集群 mnode 存活总数| -|vgroups\_total|DOUBLE||当前集群 vgroup 总数| -|vgroups\_alive|DOUBLE||当前集群 vgroup 存活总数| -|vnodes\_total|DOUBLE||当前集群 vnode 总数| -|vnodes\_alive|DOUBLE||当前集群 vnode 存活总数| -|connections\_total|DOUBLE||当前集群连接总数| -|topics\_total|DOUBLE||当前集群 topic 总数| -|streams\_total|DOUBLE||当前集群 stream 总数| -|grants_expire\_time|DOUBLE||认证过期时间,企业版有效,社区版为 DOUBLE 最大值| -|grants_timeseries\_used|DOUBLE||已用测点数| -|grants_timeseries\_total|DOUBLE||总测点数,开源版本为 DOUBLE 最大值| -|cluster\_id|VARCHAR|TAG|cluster id| - -3. taosd\_vgroups\_info 表 - -`taosd_vgroups_info` 表记录虚拟节点组信息。 - -|field|type|is\_tag|comment| -|:----|:---|:-----|:------| -|ts|TIMESTAMP||timestamp| -|tables\_num|DOUBLE||vgroup 中 table 数量| -|status|DOUBLE||vgroup 状态, 取值范围:unsynced = 0, ready = 1| -|vgroup\_id|VARCHAR|TAG|vgroup id| -|database\_name|VARCHAR|TAG|vgroup 所属的 database 名字| -|cluster\_id|VARCHAR|TAG|cluster id| - -4. taosd\_dnodes\_info 表 - -`taosd_dnodes_info` 记录 dnode 信息。 - -|field|type|is\_tag|comment| -|:----|:---|:-----|:------| -|ts|TIMESTAMP||timestamp| -|uptime|DOUBLE||dnode uptime,单位:秒| -|cpu\_engine|DOUBLE||taosd cpu 使用率,从 `/proc//stat` 读取| -|cpu\_system|DOUBLE||服务器 cpu 使用率,从 `/proc/stat` 读取| -|cpu\_cores|DOUBLE||服务器 cpu 核数| -|mem\_engine|DOUBLE||taosd 内存使用率,从 `/proc//status` 读取| -|mem\_free|DOUBLE||服务器可用内存,单位 KB| -|mem\_total|DOUBLE||服务器内存总量,单位 KB| -|disk\_used|DOUBLE||data dir 挂载的磁盘使用量,单位 bytes| -|disk\_total|DOUBLE||data dir 挂载的磁盘总容量,单位 bytes| -|system\_net\_in|DOUBLE||网络吞吐率,从 `/proc/net/dev` 中读取的 received bytes。单位 byte/s| -|system\_net\_out|DOUBLE||网络吞吐率,从 `/proc/net/dev` 中读取的 transmit bytes。单位 byte/s| -|io\_read|DOUBLE||io 吞吐率,从 `/proc//io` 中读取的 rchar 与上次数值计算之后,计算得到速度。单位 byte/s| -|io\_write|DOUBLE||io 吞吐率,从 `/proc//io` 中读取的 wchar 与上次数值计算之后,计算得到速度。单位 byte/s| -|io\_read\_disk|DOUBLE||磁盘 io 吞吐率,从 `/proc//io` 中读取的 read_bytes。单位 byte/s| -|io\_write\_disk|DOUBLE||磁盘 io 吞吐率,从 `/proc//io` 中读取的 write_bytes。单位 byte/s| -|vnodes\_num|DOUBLE||dnode 上 vnodes 数量| -|masters|DOUBLE||dnode 上 master node 数量| -|has\_mnode|DOUBLE||dnode 是否包含 mnode,取值范围:包含=1,不包含=0| -|has\_qnode|DOUBLE||dnode 是否包含 qnode,取值范围:包含=1,不包含=0| -|has\_snode|DOUBLE||dnode 是否包含 snode,取值范围:包含=1,不包含=0| -|has\_bnode|DOUBLE||dnode 是否包含 bnode,取值范围:包含=1,不包含=0| -|error\_log\_count|DOUBLE||error 总数| -|info\_log\_count|DOUBLE||info 总数| -|debug\_log\_count|DOUBLE||debug 总数| -|trace\_log\_count|DOUBLE||trace 总数| -|dnode\_id|VARCHAR|TAG|dnode id| -|dnode\_ep|VARCHAR|TAG|dnode endpoint| -|cluster\_id|VARCHAR|TAG|cluster id| - -5. taosd\_dnodes\_status 表 - -`taosd_dnodes_status` 表记录 dnode 状态信息。 - -|field|type|is\_tag|comment| -|:----|:---|:-----|:------| -|ts|TIMESTAMP||timestamp| -|status|DOUBLE||dnode 状态,取值范围:ready=1,offline =0| -|dnode\_id|VARCHAR|TAG|dnode id| -|dnode\_ep|VARCHAR|TAG|dnode endpoint| -|cluster\_id|VARCHAR|TAG|cluster id| - -6. taosd\_dnodes\_log\_dir 表 - -`taosd_dnodes_log_dir` 表记录 log 目录信息。 - -|field|type|is\_tag|comment| -|:----|:---|:-----|:------| -|ts|TIMESTAMP||timestamp| -|avail|DOUBLE||log 目录可用空间。单位 byte| -|used|DOUBLE||log 目录已使用空间。单位 byte| -|total|DOUBLE||log 目录空间。单位 byte| -|name|VARCHAR|TAG|log 目录名,一般为 `/var/log/taos/`| -|dnode\_id|VARCHAR|TAG|dnode id| -|dnode\_ep|VARCHAR|TAG|dnode endpoint| -|cluster\_id|VARCHAR|TAG|cluster id| - -7. taosd\_dnodes\_data\_dir 表 - -`taosd_dnodes_data_dir` 表记录 data 目录信息。 - -|field|type|is\_tag|comment| -|:----|:---|:-----|:------| -|ts|TIMESTAMP||timestamp| -|avail|DOUBLE||data 目录可用空间。单位 byte| -|used|DOUBLE||data 目录已使用空间。单位 byte| -|total|DOUBLE||data 目录空间。单位 byte| -|level|VARCHAR|TAG|0、1、2 多级存储级别| -|name|VARCHAR|TAG|data 目录,一般为 `/var/lib/taos`| -|dnode\_id|VARCHAR|TAG|dnode id| -|dnode\_ep|VARCHAR|TAG|dnode endpoint| -|cluster\_id|VARCHAR|TAG|cluster id| - -8. taosd\_mnodes\_info 表 - -`taosd_mnodes_info` 表记录 mnode 角色信息。 - -|field|type|is\_tag|comment| -|:----|:---|:-----|:------| -|ts|TIMESTAMP||timestamp| -|role|DOUBLE||mnode 角色, 取值范围:offline = 0,follower = 100,candidate = 101,leader = 102,error = 103,learner = 104| -|mnode\_id|VARCHAR|TAG|master node id| -|mnode\_ep|VARCHAR|TAG|master node endpoint| -|cluster\_id|VARCHAR|TAG|cluster id| - -9. taosd\_vnodes\_role 表 - -`taosd_vnodes_role` 表记录虚拟节点角色信息。 - -|field|type|is\_tag|comment| -|:----|:---|:-----|:------| -|ts|TIMESTAMP||timestamp| -|vnode\_role|DOUBLE||vnode 角色,取值范围:offline = 0,follower = 100,candidate = 101,leader = 102,error = 103,learner = 104| -|vgroup\_id|VARCHAR|TAG|dnode id| -|dnode\_id|VARCHAR|TAG|dnode id| -|database\_name|VARCHAR|TAG|vgroup 所属的 database 名字| -|cluster\_id|VARCHAR|TAG|cluster id| - -10. taosd\_sql\_req 表 - -`taosd_sql_req` 记录授权信息。 - -|field|type|is\_tag|comment| -|:----|:---|:-----|:------| -|ts|TIMESTAMP||timestamp| -|count|DOUBLE||sql 数量| -|result|VARCHAR|TAG|sql的执行结果,取值范围:Success, Failed| -|username|VARCHAR|TAG|执行sql的user name| -|sql\_type|VARCHAR|TAG|sql类型,取值范围:inserted_rows| -|dnode\_id|VARCHAR|TAG|dnode id| -|dnode\_ep|VARCHAR|TAG|dnode endpoint| -|vgroup\_id|VARCHAR|TAG|dnode id| -|cluster\_id|VARCHAR|TAG|cluster id| - -11. taos\_sql\_req 表 - -`taos_sql_req` 记录授权信息。 - -|field|type|is\_tag|comment| -|:----|:---|:-----|:------| -|ts|TIMESTAMP||timestamp| -|count|DOUBLE||sql 数量| -|result|VARCHAR|TAG|sql的执行结果,取值范围:Success, Failed| -|username|VARCHAR|TAG|执行sql的user name| -|sql\_type|VARCHAR|TAG|sql类型,取值范围:select, insert,delete| -|cluster\_id|VARCHAR|TAG|cluster id| - -12. taos\_slow\_sql 表 - -`taos_slow_sql` 记录授权信息。 - -|field|type|is\_tag|comment| -|:----|:---|:-----|:------| -|ts|TIMESTAMP||timestamp| -|count|DOUBLE||sql 数量| -|result|VARCHAR|TAG|sql的执行结果,取值范围:Success, Failed| -|username|VARCHAR|TAG|执行sql的user name| -|duration|VARCHAR|TAG|sql执行耗时,取值范围:3-10s,10-100s,100-1000s,1000s-| -|cluster\_id|VARCHAR|TAG|cluster id| - -13. keeper\_monitor 表 - -`keeper_monitor` 记录 taoskeeper 监控数据。 - -|field|type|is\_tag|comment| -|:----|:---|:-----|:------| -|ts|TIMESTAMP||timestamp| -|cpu|DOUBLE||cpu 使用率| -|mem|DOUBLE||内存使用率| -|identify|NCHAR|TAG|| - -14. taosadapter\_restful\_http\_request\_total 表 - -`taosadapter_restful_http_request_total` 记录 taosadapter rest 请求信息,该表为 schemaless 方式创建的表,时间戳字段名为 `_ts`。 - -|field|type|is\_tag|comment| -|:----|:---|:-----|:------| -|\_ts|TIMESTAMP||timestamp| -|gauge|DOUBLE||监控指标值| -|client\_ip|NCHAR|TAG|client ip| -|endpoint|NCHAR|TAG|taosadpater endpoint| -|request\_method|NCHAR|TAG|request method| -|request\_uri|NCHAR|TAG|request uri| -|status\_code|NCHAR|TAG|status code| - -15. taosadapter\_restful\_http\_request\_fail 表 - -`taosadapter_restful_http_request_fail` 记录 taosadapter rest 请求失败信息,该表为 schemaless 方式创建的表,时间戳字段名为 `_ts`。 - -|field|type|is\_tag|comment| -|:----|:---|:-----|:------| -|\_ts|TIMESTAMP||timestamp| -|gauge|DOUBLE||监控指标值| -|client\_ip|NCHAR|TAG|client ip| -|endpoint|NCHAR|TAG|taosadpater endpoint| -|request\_method|NCHAR|TAG|request method| -|request\_uri|NCHAR|TAG|request uri| -|status\_code|NCHAR|TAG|status code| - -16. taosadapter\_restful\_http\_request\_in\_flight 表 - -`taosadapter_restful_http_request_in_flight` 记录 taosadapter rest 实时请求信息,该表为 schemaless 方式创建的表,时间戳字段名为 `_ts`。 - -|field|type|is\_tag|comment| -|:----|:---|:-----|:------| -|\_ts|TIMESTAMP||timestamp| -|gauge|DOUBLE||监控指标值| -|endpoint|NCHAR|TAG|taosadpater endpoint| - -17. taosadapter\_restful\_http\_request\_summary\_milliseconds 表 - -`taosadapter_restful_http_request_summary_milliseconds` 记录 taosadapter rest 请求汇总信息,该表为 schemaless 方式创建的表,时间戳字段名为 `_ts`。 - -|field|type|is\_tag|comment| -|:----|:---|:-----|:------| -|\_ts|TIMESTAMP||timestamp| -|count|DOUBLE||| -|sum|DOUBLE||| -|0.5|DOUBLE||| -|0.9|DOUBLE||| -|0.99|DOUBLE||| -|0.1|DOUBLE||| -|0.2|DOUBLE||| -|endpoint|NCHAR|TAG|taosadpater endpoint| -|request\_method|NCHAR|TAG|request method| -|request\_uri|NCHAR|TAG|request uri| - -18. taosadapter\_system\_mem\_percent 表 - -`taosadapter_system_mem_percent` 表记录 taosadapter 内存使用情况,该表为 schemaless 方式创建的表,时间戳字段名为 `_ts`。 - -|field|type|is\_tag|comment| -|:----|:---|:-----|:------| -|\_ts|TIMESTAMP||timestamp| -|gauge|DOUBLE||监控指标值| -|endpoint|NCHAR|TAG|taosadpater endpoint| - -19. taosadapter\_system\_cpu\_percent 表 - -`taosadapter_system_cpu_percent` 表记录 taosadapter cpu 使用情况,该表为 schemaless 方式创建的表,时间戳字段名为 `_ts`。 - -|field|type|is\_tag|comment| -|:----|:---|:-----|:------| -|\_ts|TIMESTAMP||timestamp| -|gauge|DOUBLE||监控指标值| -|endpoint|NCHAR|TAG|taosadpater endpoint| +TDinsight dashboard 数据来源于 `log` 库(存放监控数据的默认数据库,可以在 taoskeeper 配置文件中修改)。”TDinsight for 3.x“ 仪表盘查询了 taosd 和 TaosAdapter 的监控指标。 +- taosd 的监控指标请参考 [taosd 监控指标](../../reference/components/taosd/#taosd-监控指标) +- taosAdapter 的监控指标请参考 [taosAdapter 监控指标](../../reference/components/taosadapter/#taosadapter-监控指标) ## 监控 taosX @@ -396,13 +69,13 @@ taosX 是 TDengine 中提供零代码数据接入能力的核心组件,对它 ### 版本支持 1. TDengine 企业版本 3.2.3.0 或以上版本包含的 taosX 才包含此功能。如果单独安装 taosX,需要 taosX 1.5.0 或以上版本。 -1. 需要安装 Grafana 插件 [TDengie Datasource v3.5.0](https://grafana.com/grafana/plugins/tdengine-datasource/) 或以上版本。 +2. 需要安装 Grafana 插件 [TDengie Datasource v3.5.0](https://grafana.com/grafana/plugins/tdengine-datasource/) 或以上版本。 ### 准备工作 -假设你已经部署好了 taosd,taosAdapter 和 taosAdapter。 那么还需要: -2. 启动 taosX 服务。 -3. 部署 Grafana ,安装 TDengine Datasource 插件,配置好数据源。 +假设你已经部署好了 taosd,taosAdapter 和 taosAdapter。 那么还需要: +1. 启动 taosX 服务。 +2. 部署 Grafana ,安装 TDengine Datasource 插件,配置好数据源。 ### 配置 taosX @@ -426,52 +99,50 @@ toasX 的配置文件(默认 /etc/taos/taosx.toml) 中与 monitor 相关的配 | port | --monitor-port | MONITOR_PORT | taosKeeper 服务的端口 | | 6043 | | interval | --monitor-interval | MONITTOR_INTERVAL | taosX 发送 metrics 数据到 taosKeeper 的时间间隔,单位秒 | 1-10 | 10 | -TDinsight for taosX - -"TDinsight for taosX" 专门为 taosX 监控创建的 Grafana 面板。使用前需要先导入这个面板。 - ### 基于 TDinsight 监控 tasoX +"TDinsight for taosX" 是专门为 taosX 监控创建的 Grafana 面板。使用前需要先导入这个面板。 + #### 进入面板 -1. 选择 TDengine Datasource - ![TDengine Datasource](./pic/monitor-01.jpg) -2. 点击 “Dashboard”, 选择 TDinsight for taosX 面板。(第一次使用需要先导入)。 - ![Dashboard](./pic/monitor-02.jpg) +1. 在 Grafana 界面菜单中点击 ”Data sources“, 然后选择已经配置好的 TDengine 数据源。 +2. 在数据源配置界面选择 “Dashboard” Tab, 然后导入 ”TDinsight for taosX“ 面板(第一次使用需要先导入)。 下面是一个示例图: + ![monitor rows](./pic/monitor-04.jpg) - 该面板每一行代表一个或一类监控对象。最上面是 taosX 监控行,然后是 Agent 监控行, 最后是各类数据写入任务的监控。 - :::note - 1. 如果打开这个面板后看不到任何数据,你很可能需要点击左上角的数据库列表(即 “Log from” 下拉菜单),切换到监控数据所在的数据库。 - 2. 数据库包含多少个 Agent 的数据就会自动创建多少个 Agent 行。(如上图) - - ::: + + 该面板每一行代表一个或一类监控对象。最上面是 taosX 监控行,然后是 Agent 监控行, 最后是各类数据写入任务的监控。 + :::note + - 如果打开这个面板后看不到任何数据,你很可能需要点击左上角的数据库列表(即 “Log from” 下拉菜单),切换到监控数据所在的数据库。 + - 数据库包含多少个 Agent 的数据就会自动创建多少个 Agent 行。(如上图) + ::: #### 监控示例 -1. taosX 监控示例 +1. taosX 监控示例图 -![monitor taosx](./pic/monitor-03.png) + ![monitor taosx](./pic/monitor-03.png) -2. Agent 监控示例 +2. Agent 监控示例图 -![monitor agent](./pic/monitor-09.jpg) + ![monitor agent](./pic/monitor-09.jpg) -3. TDengine2 数据源监控示例 +3. TDengine2 数据源监控示例图 -![monitor tdengine2](./pic/monitor-05.png) + ![monitor tdengine2](./pic/monitor-05.png) -:::info -监控面板只展示了数据写入任务的部分监控指标,在 Explorer 页面上有更全面的监控指标,且有每个指标的具体说明。 + :::info + 监控面板只展示了数据写入任务的部分监控指标,在 Explorer 页面上有更全面的监控指标,且有每个指标的具体说明。 -::: + ::: -3. TDengine3 数据源监控示例 -![monitor tdengine3](./pic/monitor-06.jpg) +4. TDengine3 数据源监控示例图 + + ![monitor tdengine3](./pic/monitor-06.jpg) -4. 其它数据源监控示例 -![monitor task](./pic/monitor-10.jpg) +5. 其它数据源监控示例图 + ![monitor task](./pic/monitor-10.jpg) #### 限制 diff --git a/docs/zh/07-operation/TDinsight-1-cluster-status.webp b/docs/zh/07-operation/TDinsight-1-cluster-status.webp new file mode 100644 index 0000000000..7f7792b2e9 Binary files /dev/null and b/docs/zh/07-operation/TDinsight-1-cluster-status.webp differ diff --git a/docs/zh/07-operation/tdinsight.png b/docs/zh/07-operation/tdinsight.png deleted file mode 100644 index 0d90950318..0000000000 Binary files a/docs/zh/07-operation/tdinsight.png and /dev/null differ diff --git a/docs/zh/08-develop/09-udf.md b/docs/zh/08-develop/09-udf.md index 45e4ae6134..700bbb2ae0 100644 --- a/docs/zh/08-develop/09-udf.md +++ b/docs/zh/08-develop/09-udf.md @@ -6,29 +6,28 @@ toc_max_heading_level: 4 ## UDF 简介 -在某些应用场景中,应用逻辑需要的查询功能无法直接使用TDengine内置的函数来实现。TDengine允许编写用户自定义函数(UDF),以便解决特殊应用场景中的使用需求。UDF在集群中注册成功后,可以像系统内置函数一样在SQL中调用,就使用角度而言没有任何区别。UDF分为标量函数和聚合函数。标量函数对每行数据输出一个值,如求绝对值abs、正弦函数sin、字符串拼接函数concat等。聚合函数对多行数据输出一个值,如求平均数avg、取最大值max等。 +在某些应用场景中,应用逻辑需要的查询功能无法直接使用内置函数来实现,TDengine 允许编写用户自定义函数(UDF),以便解决特殊应用场景中的使用需求。UDF 在集群中注册成功后,可以像系统内置函数一样在 SQL 中调用,就使用角度而言没有任何区别。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。 - -接口函数的名称是 UDF 名称,或者是 UDF 名称和特定后缀(`_start`, `_finish`, `_init`, `_destroy`)的连接。列表中的scalarfn,aggfn, udf需要替换成udf函数名。 +- 聚合函数需要实现聚合接口函数 aggfn_start、aggfn、aggfn_finish。 +- 如果需要初始化,实现 udf_init。 +- 如果需要清理工作,实现 udf_destroy。 ### 接口定义 -在TDengine中,UDF的接口函数名称可以是UDF名称,也可以是UDF名称和特定后缀(如_start、_finish、_init、_destroy)的连接。后面内容中描述的函数名称,例如scalarfn、aggfn,需要替换成UDF名称。。 +接口函数的名称是 UDF 名称,或者是 UDF 名称和特定后缀(_start、_finish、_init、_destroy)的连接。后面内容中描述的函数名称,例如 scalarfn、aggfn,需要替换成 UDF 名称。 #### 标量函数接口 标量函数是一种将输入数据转换为输出数据的函数,通常用于对单个数据值进行计算和转换。标量函数的接口函数原型如下。 ```c -int32_t scalarfn(SUdfDataBlock* inputDataBlock, SUdfColumn *resultColumn) +int32_t scalarfn(SUdfDataBlock* inputDataBlock, SUdfColumn *resultColumn); ``` 主要参数说明如下。 - inputDataBlock:输入的数据块。 @@ -37,23 +36,22 @@ 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 条数据,具体取决于聚 合函数的类型和输入数据。 聚合函数的接口函数原型如下。 ```c -int32_t aggfn_start(SUdfInterBuf *interBuf) -int32_t aggfn(SUdfDataBlock* inputBlock, SUdfInterBuf *interBuf, SUdfInterBuf *newInterBuf) -int32_t aggfn_finish(SUdfInterBuf* interBuf, SUdfInterBuf *result) +int32_t aggfn_start(SUdfInterBuf *interBuf); +int32_t aggfn(SUdfDataBlock* inputBlock, SUdfInterBuf *interBuf, SUdfInterBuf *newInterBuf); +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 +59,49 @@ 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 +109,211 @@ 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 忽略空值。 + +
+bit_and.c + +```c +{{#include tests/script/sh/bit_and.c}} +``` + +
+ +#### 聚合函数示例1 返回值为数值类型 [l2norm](https://github.com/taosdata/TDengine/blob/3.0/tests/script/sh/l2norm.c) + +l2norm 实现了输入列的所有数据的二阶范数,即对每个数据先平方,再累加求和,最后开方。 + +
+l2norm.c + +```c +{{#include tests/script/sh/l2norm.c}} +``` + +
+ +#### 聚合函数示例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; +``` + +
+max_vol.c + +```c +{{#include tests/script/sh/max_vol.c}} +``` + +
## 用 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 +323,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 +335,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 +355,7 @@ def destroy() - init 完成初始化工作 - destroy 完成清理工作 -**注意** 用Python开发UDF时必须定义init函数和destroy函数 +**注意** 用 Python 开发 UDF 时必须定义 init 函数和 destroy 函数 ### 标量函数模板 @@ -204,7 +380,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 +393,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 | 不支持 | ### 开发示例 @@ -262,7 +438,7 @@ create function myfun as '/root/udf/myfun.py' outputtype double language 'Python 其输出如下 ```shell - taos> create function myfun as '/root/udf/myfun.py' outputtype double language 'Python'; +taos> create function myfun as '/root/udf/myfun.py' outputtype double language 'Python'; Create OK, 0 row(s) affected (0.005202s) ``` @@ -460,7 +636,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 +803,77 @@ close log file: spread.log 通过这个示例,我们学会了如何定义聚合函数,并打印自定义的日志信息。 +### 更多 Python UDF 示例代码 +#### 标量函数示例 [pybitand](https://github.com/taosdata/TDengine/blob/3.0/tests/script/sh/pybitand.py) + +pybitand 实现多列的按位与功能。如果只有一列,返回这一列。pybitand 忽略空值。 + +
+pybitand.py + +```Python +{{#include tests/script/sh/pybitand.py}} +``` + +
+ +#### 聚合函数示例 [pyl2norm](https://github.com/taosdata/TDengine/blob/3.0/tests/script/sh/pyl2norm.py) + +pyl2norm 实现了输入列的所有数据的二阶范数,即对每个数据先平方,再累加求和,最后开方。 + +
+pyl2norm.py + +```c +{{#include tests/script/sh/pyl2norm.py}} +``` + +
+ +#### 聚合函数示例 [pycumsum](https://github.com/taosdata/TDengine/blob/3.0/tests/script/sh/pycumsum.py) + +pycumsum 使用 numpy 计算输入列所有数据的累积和。 +
+pycumsum.py + +```c +{{#include tests/script/sh/pycumsum.py}} +``` + +
+ ## 管理 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 +887,15 @@ DROP FUNCTION function_name; ### 查看 UDF -显示集群中当前可用的所有UDF的SQL如下。 +显示集群中当前可用的所有 UDF 的 SQL 如下。 ```sql show functions; ``` +### 查看函数信息 + +同名的 UDF 每更新一次,版本号会增加 1。 +```sql +select * from ins_functions \G; +``` + diff --git a/docs/zh/14-reference/01-components/01-taosd.md b/docs/zh/14-reference/01-components/01-taosd.md index 0e9c4eb926..02cf2155a0 100644 --- a/docs/zh/14-reference/01-components/01-taosd.md +++ b/docs/zh/14-reference/01-components/01-taosd.md @@ -27,42 +27,42 @@ taosd 命令行参数如下 ### 连接相关 -| 参数名称 | 参数说明 | -|:-------------:|:----------------------------------------------------------------:| -|firstEp | taosd 启动时,主动连接的集群中首个 dnode 的 end point,缺省值:localhost:6030 | -|secondEp | taosd 启动时,如果 firstEp 连接不上,尝试连接集群中第二个 dnode 的 endpoint,缺省值:无| -|fqdn | 启动 taosd 后所监听的服务地址,缺省值:所在服务器上配置的第一个 hostname | -|serverPort | 启动 taosd 后所监听的端口,缺省值:6030 | -|maxShellConns | 一个 dnode 容许的连接数,取值范围为 10-5000000,缺省值:5000 | -|numOfRpcSessions | 允许一个客户端能创建的最大连接数,取值范围 100-100000,缺省值:30000 | -|timeToGetAvailableConn | 获得可用连接的最长等待时间,取值范围 10-50000000,单位为毫秒,缺省值:500000 | +| 参数名称 | 参数说明 | +| :--------------------: | :-------------------------------------------------------------------------------------: | +| firstEp | taosd 启动时,主动连接的集群中首个 dnode 的 end point,缺省值:localhost:6030 | +| secondEp | taosd 启动时,如果 firstEp 连接不上,尝试连接集群中第二个 dnode 的 endpoint,缺省值:无 | +| fqdn | 启动 taosd 后所监听的服务地址,缺省值:所在服务器上配置的第一个 hostname | +| serverPort | 启动 taosd 后所监听的端口,缺省值:6030 | +| maxShellConns | 一个 dnode 容许的连接数,取值范围为 10-5000000,缺省值:5000 | +| numOfRpcSessions | 允许一个客户端能创建的最大连接数,取值范围 100-100000,缺省值:30000 | +| timeToGetAvailableConn | 获得可用连接的最长等待时间,取值范围 10-50000000,单位为毫秒,缺省值:500000 | ### 监控相关 -| 参数名称 | 参数说明 | -|:-------------:|:----------------------------------------------------------------:| -|monitor | 是否收集监控数据并上报,0: 关闭;1:打开;缺省值:0 | -|monitorFqdn | taosKeeper 服务所在服务器的 FQDN,缺省值:无 | -|monitorPort | taosKeeper 服务所监听的端口号,缺省值:6043 | -|monitorInternal | 监控数据库记录系统参数(CPU/内存)的时间间隔,单位是秒,取值范围 1-200000 ,缺省值:30| -|telemetryReporting | 是否上传 telemetry,0: 不上传,1:上传,缺省值:1 | -|crashReporting | 是否上传 crash 信息;0: 不上传,1: 上传;缺省值: 1| +| 参数名称 | 参数说明 | +| :----------------: | :------------------------------------------------------------------------------------: | +| monitor | 是否收集监控数据并上报,0: 关闭;1:打开;缺省值:0 | +| monitorFqdn | taosKeeper 服务所在服务器的 FQDN,缺省值:无 | +| monitorPort | taosKeeper 服务所监听的端口号,缺省值:6043 | +| monitorInternal | 监控数据库记录系统参数(CPU/内存)的时间间隔,单位是秒,取值范围 1-200000 ,缺省值:30 | +| telemetryReporting | 是否上传 telemetry,0: 不上传,1:上传,缺省值:1 | +| crashReporting | 是否上传 crash 信息;0: 不上传,1: 上传;缺省值: 1 | ### 查询相关 -| 参数名称 | 参数说明 | -|:-------------:|:----------------------------------------------------------------:| -|queryPolicy | 查询策略,1: 只使用 vnode,不使用 qnode; 2: 没有扫描算子的子任务在 qnode 执行,带扫描算子的子任务在 vnode 执行; 3: vnode 只运行扫描算子,其余算子均在 qnode 执行 ;缺省值:1 | -|maxNumOfDistinctRes | 允许返回的 distinct 结果最大行数,默认值 10 万,最大允许值 1 亿 | -|countAlwaysReturnValue | ount/hyperloglog函数在输入数据为空或者NULL的情况下是否返回值,0: 返回空行,1: 返回;该参数设置为 1 时,如果查询中含有 INTERVAL 子句或者该查询使用了TSMA时, 且相应的组或窗口内数据为空或者NULL, 对应的组或窗口将不返回查询结果. 注意此参数客户端和服务端值应保持一致.| +| 参数名称 | 参数说明 | +| :--------------------: | :-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | +| queryPolicy | 查询策略,1: 只使用 vnode,不使用 qnode; 2: 没有扫描算子的子任务在 qnode 执行,带扫描算子的子任务在 vnode 执行; 3: vnode 只运行扫描算子,其余算子均在 qnode 执行 ;缺省值:1 | +| maxNumOfDistinctRes | 允许返回的 distinct 结果最大行数,默认值 10 万,最大允许值 1 亿 | +| countAlwaysReturnValue | ount/hyperloglog函数在输入数据为空或者NULL的情况下是否返回值,0: 返回空行,1: 返回;该参数设置为 1 时,如果查询中含有 INTERVAL 子句或者该查询使用了TSMA时, 且相应的组或窗口内数据为空或者NULL, 对应的组或窗口将不返回查询结果. 注意此参数客户端和服务端值应保持一致. | ### 区域相关 -| 参数名称 | 参数说明 | -|:-------------:|:----------------------------------------------------------------:| -|timezone | 时区,缺省值:当前服务器所配置的时区 | -|locale | 系统区位信息及编码格式 ,缺省值:系统中动态获取,如果自动获取失败,需要用户在配置文件设置或通过 API 设置 | -|charset | 字符集编码,缺省值:系统自动获取 | +| 参数名称 | 参数说明 | +| :------: | :------------------------------------------------------------------------------------------------------: | +| timezone | 时区,缺省值:当前服务器所配置的时区 | +| locale | 系统区位信息及编码格式 ,缺省值:系统中动态获取,如果自动获取失败,需要用户在配置文件设置或通过 API 设置 | +| charset | 字符集编码,缺省值:系统自动获取 | :::info 1. 为应对多时区的数据写入和查询问题,TDengine 采用 Unix 时间戳(Unix Timestamp)来记录和存储时间戳。Unix 时间戳的特点决定了任一时刻不论在任何时区,产生的时间戳均一致。需要注意的是,Unix 时间戳是在客户端完成转换和记录。为了确保客户端其他形式的时间转换为正确的 Unix 时间戳,需要设置正确的时区。 @@ -141,64 +141,64 @@ charset 的有效值是 UTF-8。 ### 存储相关 -| 参数名称 | 参数说明 | -|:-------------:|:----------------------------------------------------------------:| -|dataDir | 数据文件目录,所有的数据文件都将写入该目录,缺省值:/var/lib | -|tempDir | 指定所有系统运行过程中的临时文件生成的目录,缺省值:/tmp | -|minimalTmpDirGB | tempDir 所指定的临时文件目录所需要保留的最小空间,单位 GB,缺省值: 1| -|minimalDataDirGB | dataDir 指定的时序数据存储目录所需要保留的最小空间,单位 GB,缺省值: 2 | +| 参数名称 | 参数说明 | +| :--------------: | :--------------------------------------------------------------------: | +| dataDir | 数据文件目录,所有的数据文件都将写入该目录,缺省值:/var/lib | +| tempDir | 指定所有系统运行过程中的临时文件生成的目录,缺省值:/tmp | +| minimalTmpDirGB | tempDir 所指定的临时文件目录所需要保留的最小空间,单位 GB,缺省值: 1 | +| minimalDataDirGB | dataDir 指定的时序数据存储目录所需要保留的最小空间,单位 GB,缺省值: 2 | ### 集群相关 -| 参数名称 | 参数说明 | -|:-------------:|:----------------------------------------------------------------:| -|supportVnodes | dnode 支持的最大 vnode 数目,取值范围:0-4096,缺省值: CPU 核数的 2 倍 + 5 | +| 参数名称 | 参数说明 | +| :-----------: | :-------------------------------------------------------------------------: | +| supportVnodes | dnode 支持的最大 vnode 数目,取值范围:0-4096,缺省值: CPU 核数的 2 倍 + 5 | ### 性能调优 -| 参数名称 | 参数说明 | -|:-------------:|:----------------------------------------------------------------:| -|numOfCommitThreads | 写入线程的最大数量,取值范围 0-1024,缺省值为 4 | +| 参数名称 | 参数说明 | +| :----------------: | :---------------------------------------------: | +| numOfCommitThreads | 写入线程的最大数量,取值范围 0-1024,缺省值为 4 | ### 日志相关 -| 参数名称 | 参数说明 | -|:-------------:|:----------------------------------------------------------------:| -|logDir | 日志文件目录,运行日志将写入该目录,缺省值:/var/log/taos | -|minimalLogDirGB | 当日志文件夹所在磁盘可用空间大小小于该值时,停止写日志,单位GB,缺省值:1| -|numOfLogLines | 单个日志文件允许的最大行数,缺省值:10,000,000 | -|asyncLog | 日志写入模式,0: 同步,1: 异步,缺省值: 1 | -|logKeepDays | 日志文件的最长保存时间 ,单位:天,缺省值:0,意味着无限保存;当设置为大于0 的值时,日志文件会被重命名为 taosdlog.xxx,其中 xxx 为日志文件最后修改的时间戳。 | -|slowLogThreshold | 慢查询门限值,大于等于门限值认为是慢查询,单位秒,默认值: 3 | -|slowLogScope | 定启动记录哪些类型的慢查询,可选值:ALL, QUERY, INSERT, OHTERS, NONE; 默认值:ALL | -|debugFlag | 运行日志开关,131(输出错误和警告日志),135(输出错误、警告和调试日志),143(输出错误、警告、调试和跟踪日志); 默认值:131 或 135 (取决于不同模块)| -|tmrDebugFlag | 定时器模块的日志开关,取值范围同上 | -|uDebugFlag | 共用功能模块的日志开关,取值范围同上 | -|rpcDebugFlag | rpc 模块的日志开关,取值范围同上 | -|jniDebugFlag | jni 模块的日志开关,取值范围同上 | -|qDebugFlag | query 模块的日志开关,取值范围同上 | -|dDebugFlag | dnode 模块的日志开关,取值范围同上,缺省值 135 | -|vDebugFlag | vnode 模块的日志开关,取值范围同上 | -|mDebugFlag | mnode 模块的日志开关,取值范围同上 | -|wDebugFlag | wal 模块的日志开关,取值范围同上 | -|sDebugFlag | sync 模块的日志开关,取值范围同上 | -|tsdbDebugFlag | tsdb 模块的日志开关,取值范围同上 | -|tqDebugFlag | tq 模块的日志开关,取值范围同上 | -|fsDebugFlag | fs 模块的日志开关,取值范围同上 | -|udfDebugFlag | udf 模块的日志开关,取值范围同上 | -|smaDebugFlag | sma 模块的日志开关,取值范围同上 | -|idxDebugFlag | index 模块的日志开关,取值范围同上 | -|tdbDebugFlag | tdb 模块的日志开关,取值范围同上 | +| 参数名称 | 参数说明 | +| :--------------: | :----------------------------------------------------------------------------------------------------------------------------------------------------------: | +| logDir | 日志文件目录,运行日志将写入该目录,缺省值:/var/log/taos | +| minimalLogDirGB | 当日志文件夹所在磁盘可用空间大小小于该值时,停止写日志,单位GB,缺省值:1 | +| numOfLogLines | 单个日志文件允许的最大行数,缺省值:10,000,000 | +| asyncLog | 日志写入模式,0: 同步,1: 异步,缺省值: 1 | +| logKeepDays | 日志文件的最长保存时间 ,单位:天,缺省值:0,意味着无限保存;当设置为大于0 的值时,日志文件会被重命名为 taosdlog.xxx,其中 xxx 为日志文件最后修改的时间戳。 | +| slowLogThreshold | 慢查询门限值,大于等于门限值认为是慢查询,单位秒,默认值: 3 | +| slowLogScope | 定启动记录哪些类型的慢查询,可选值:ALL, QUERY, INSERT, OHTERS, NONE; 默认值:ALL | +| debugFlag | 运行日志开关,131(输出错误和警告日志),135(输出错误、警告和调试日志),143(输出错误、警告、调试和跟踪日志); 默认值:131 或 135 (取决于不同模块) | +| tmrDebugFlag | 定时器模块的日志开关,取值范围同上 | +| uDebugFlag | 共用功能模块的日志开关,取值范围同上 | +| rpcDebugFlag | rpc 模块的日志开关,取值范围同上 | +| jniDebugFlag | jni 模块的日志开关,取值范围同上 | +| qDebugFlag | query 模块的日志开关,取值范围同上 | +| dDebugFlag | dnode 模块的日志开关,取值范围同上,缺省值 135 | +| vDebugFlag | vnode 模块的日志开关,取值范围同上 | +| mDebugFlag | mnode 模块的日志开关,取值范围同上 | +| wDebugFlag | wal 模块的日志开关,取值范围同上 | +| sDebugFlag | sync 模块的日志开关,取值范围同上 | +| tsdbDebugFlag | tsdb 模块的日志开关,取值范围同上 | +| tqDebugFlag | tq 模块的日志开关,取值范围同上 | +| fsDebugFlag | fs 模块的日志开关,取值范围同上 | +| udfDebugFlag | udf 模块的日志开关,取值范围同上 | +| smaDebugFlag | sma 模块的日志开关,取值范围同上 | +| idxDebugFlag | index 模块的日志开关,取值范围同上 | +| tdbDebugFlag | tdb 模块的日志开关,取值范围同上 | ### 压缩参数 -| 参数名称 | 参数说明 | -|:-------------:|:----------------------------------------------------------------:| -| compressMsgSize | 是否对 RPC 消息进行压缩;-1: 所有消息都不压缩; 0: 所有消息都压缩; N (N>0): 只有大于 N 个字节的消息才压缩;缺省值 -1 | -| fPrecision | 设置 float 类型浮点数压缩精度 ,取值范围:0.1 ~ 0.00000001 ,默认值 0.00000001 , 小于此值的浮点数尾数部分将被截断 | -|dPrecision | 设置 double 类型浮点数压缩精度 , 取值范围:0.1 ~ 0.0000000000000001 , 缺省值 0.0000000000000001 , 小于此值的浮点数尾数部分将被截取 | -|lossyColumn | 对 float 和/或 double 类型启用 TSZ 有损压缩;取值范围: float, double, none;缺省值: none,表示关闭无损压缩 | -|ifAdtFse | 在启用 TSZ 有损压缩时,使用 FSE 算法替换 HUFFMAN 算法, FSE 算法压缩速度更快,但解压稍慢,追求压缩速度可选用此算法; 0: 关闭,1:打开;默认值为 0 | +| 参数名称 | 参数说明 | +| :-------------: | :----------------------------------------------------------------------------------------------------------------------------------------------: | +| compressMsgSize | 是否对 RPC 消息进行压缩;-1: 所有消息都不压缩; 0: 所有消息都压缩; N (N>0): 只有大于 N 个字节的消息才压缩;缺省值 -1 | +| fPrecision | 设置 float 类型浮点数压缩精度 ,取值范围:0.1 ~ 0.00000001 ,默认值 0.00000001 , 小于此值的浮点数尾数部分将被截断 | +| dPrecision | 设置 double 类型浮点数压缩精度 , 取值范围:0.1 ~ 0.0000000000000001 , 缺省值 0.0000000000000001 , 小于此值的浮点数尾数部分将被截取 | +| lossyColumn | 对 float 和/或 double 类型启用 TSZ 有损压缩;取值范围: float, double, none;缺省值: none,表示关闭无损压缩 | +| ifAdtFse | 在启用 TSZ 有损压缩时,使用 FSE 算法替换 HUFFMAN 算法, FSE 算法压缩速度更快,但解压稍慢,追求压缩速度可选用此算法; 0: 关闭,1:打开;默认值为 0 | **补充说明** @@ -216,10 +216,214 @@ lossyColumns float|double ### 其他参数 -| 参数名称 | 参数说明 | -|:-------------:|:----------------------------------------------------------------:| -|enableCoreFile | crash 时是否生成 core 文件;0: 不生成,1:生成;默认值 为 1; 不同的启动方式,生成 core 文件的目录如下:1、systemctl start taosd 启动:生成的 core 在根目录下
2、手动启动,就在 taosd 执行目录下。| -|udf | 是否启动 UDF 服务;0: 不启动,1:启动;默认值 为 0 | -|ttlChangeOnWrite | ttl 到期时间是否伴随表的修改操作改变; 0: 不改变,1:改变 ;默认值 为 | -| tmqMaxTopicNum| 订阅最多可建立的 topic 数量; 取值范围 1-10000;缺省值 为20 | -|maxTsmaNum | 集群内可创建的TSMA个数;取值范围:0-3;缺省值: 3| \ No newline at end of file +| 参数名称 | 参数说明 | +| :--------------: | :------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------: | +| enableCoreFile | crash 时是否生成 core 文件;0: 不生成,1:生成;默认值 为 1; 不同的启动方式,生成 core 文件的目录如下:1、systemctl start taosd 启动:生成的 core 在根目录下
2、手动启动,就在 taosd 执行目录下。 | +| udf | 是否启动 UDF 服务;0: 不启动,1:启动;默认值 为 0 | +| ttlChangeOnWrite | ttl 到期时间是否伴随表的修改操作改变; 0: 不改变,1:改变 ;默认值 为 | +| tmqMaxTopicNum | 订阅最多可建立的 topic 数量; 取值范围 1-10000;缺省值 为20 | +| maxTsmaNum | 集群内可创建的TSMA个数;取值范围:0-3;缺省值: 3 | + + +## taosd 监控指标 + +taosd 会将监控指标上报给 taosKeeper,这些监控指标会被 taosKeeper 写入监控数据库,默认是 `log` 库,可以在 taoskeeper 配置文件中修改。以下是这些监控指标的详细介绍。 + +### taosd\_cluster\_basic 表 + +`taosd_cluster_basic` 表记录集群基础信息。 + +| field | type | is\_tag | comment | +| :------------------- | :-------- | :------ | :------------------------------ | +| ts | TIMESTAMP | | timestamp | +| first\_ep | VARCHAR | | 集群 first ep | +| first\_ep\_dnode\_id | INT | | 集群 first ep 的 dnode id | +| cluster_version | VARCHAR | | tdengine version。例如:3.0.4.0 | +| cluster\_id | VARCHAR | TAG | cluster id | + +### taosd\_cluster\_info 表 + +`taosd_cluster_info` 表记录集群信息。 + +| field | type | is\_tag | comment | +| :----------------------- | :-------- | :------ | :----------------------------------------------- | +| \_ts | TIMESTAMP | | timestamp | +| cluster_uptime | DOUBLE | | 当前 master 节点的uptime。单位:秒 | +| dbs\_total | DOUBLE | | database 总数 | +| tbs\_total | DOUBLE | | 当前集群 table 总数 | +| stbs\_total | DOUBLE | | 当前集群 stable 总数 | +| dnodes\_total | DOUBLE | | 当前集群 dnode 总数 | +| dnodes\_alive | DOUBLE | | 当前集群 dnode 存活总数 | +| mnodes\_total | DOUBLE | | 当前集群 mnode 总数 | +| mnodes\_alive | DOUBLE | | 当前集群 mnode 存活总数 | +| vgroups\_total | DOUBLE | | 当前集群 vgroup 总数 | +| vgroups\_alive | DOUBLE | | 当前集群 vgroup 存活总数 | +| vnodes\_total | DOUBLE | | 当前集群 vnode 总数 | +| vnodes\_alive | DOUBLE | | 当前集群 vnode 存活总数 | +| connections\_total | DOUBLE | | 当前集群连接总数 | +| topics\_total | DOUBLE | | 当前集群 topic 总数 | +| streams\_total | DOUBLE | | 当前集群 stream 总数 | +| grants_expire\_time | DOUBLE | | 认证过期时间,企业版有效,社区版为 DOUBLE 最大值 | +| grants_timeseries\_used | DOUBLE | | 已用测点数 | +| grants_timeseries\_total | DOUBLE | | 总测点数,开源版本为 DOUBLE 最大值 | +| cluster\_id | VARCHAR | TAG | cluster id | + +### taosd\_vgroups\_info 表 + +`taosd_vgroups_info` 表记录虚拟节点组信息。 + +| field | type | is\_tag | comment | +| :------------- | :-------- | :------ | :--------------------------------------------- | +| \_ts | TIMESTAMP | | timestamp | +| tables\_num | DOUBLE | | vgroup 中 table 数量 | +| status | DOUBLE | | vgroup 状态, 取值范围:unsynced = 0, ready = 1 | +| vgroup\_id | VARCHAR | TAG | vgroup id | +| database\_name | VARCHAR | TAG | vgroup 所属的 database 名字 | +| cluster\_id | VARCHAR | TAG | cluster id | + +### taosd\_dnodes\_info 表 + +`taosd_dnodes_info` 记录 dnode 信息。 + +| field | type | is\_tag | comment | +| :---------------- | :-------- | :------ | :------------------------------------------------------------------------------------------------ | +| \_ts | TIMESTAMP | | timestamp | +| uptime | DOUBLE | | dnode uptime,单位:秒 | +| cpu\_engine | DOUBLE | | taosd cpu 使用率,从 `/proc//stat` 读取 | +| cpu\_system | DOUBLE | | 服务器 cpu 使用率,从 `/proc/stat` 读取 | +| cpu\_cores | DOUBLE | | 服务器 cpu 核数 | +| mem\_engine | DOUBLE | | taosd 内存使用率,从 `/proc//status` 读取 | +| mem\_free | DOUBLE | | 服务器可用内存,单位 KB | +| mem\_total | DOUBLE | | 服务器内存总量,单位 KB | +| disk\_used | DOUBLE | | data dir 挂载的磁盘使用量,单位 bytes | +| disk\_total | DOUBLE | | data dir 挂载的磁盘总容量,单位 bytes | +| system\_net\_in | DOUBLE | | 网络吞吐率,从 `/proc/net/dev` 中读取的 received bytes。单位 byte/s | +| system\_net\_out | DOUBLE | | 网络吞吐率,从 `/proc/net/dev` 中读取的 transmit bytes。单位 byte/s | +| io\_read | DOUBLE | | io 吞吐率,从 `/proc//io` 中读取的 rchar 与上次数值计算之后,计算得到速度。单位 byte/s | +| io\_write | DOUBLE | | io 吞吐率,从 `/proc//io` 中读取的 wchar 与上次数值计算之后,计算得到速度。单位 byte/s | +| io\_read\_disk | DOUBLE | | 磁盘 io 吞吐率,从 `/proc//io` 中读取的 read_bytes。单位 byte/s | +| io\_write\_disk | DOUBLE | | 磁盘 io 吞吐率,从 `/proc//io` 中读取的 write_bytes。单位 byte/s | +| vnodes\_num | DOUBLE | | dnode 上 vnodes 数量 | +| masters | DOUBLE | | dnode 上 master node 数量 | +| has\_mnode | DOUBLE | | dnode 是否包含 mnode,取值范围:包含=1,不包含=0 | +| has\_qnode | DOUBLE | | dnode 是否包含 qnode,取值范围:包含=1,不包含=0 | +| has\_snode | DOUBLE | | dnode 是否包含 snode,取值范围:包含=1,不包含=0 | +| has\_bnode | DOUBLE | | dnode 是否包含 bnode,取值范围:包含=1,不包含=0 | +| error\_log\_count | DOUBLE | | error 总数 | +| info\_log\_count | DOUBLE | | info 总数 | +| debug\_log\_count | DOUBLE | | debug 总数 | +| trace\_log\_count | DOUBLE | | trace 总数 | +| dnode\_id | VARCHAR | TAG | dnode id | +| dnode\_ep | VARCHAR | TAG | dnode endpoint | +| cluster\_id | VARCHAR | TAG | cluster id | + +### taosd\_dnodes\_status 表 + +`taosd_dnodes_status` 表记录 dnode 状态信息。 + +| field | type | is\_tag | comment | +| :---------- | :-------- | :------ | :--------------------------------------- | +| \_ts | TIMESTAMP | | timestamp | +| status | DOUBLE | | dnode 状态,取值范围:ready=1,offline =0 | +| dnode\_id | VARCHAR | TAG | dnode id | +| dnode\_ep | VARCHAR | TAG | dnode endpoint | +| cluster\_id | VARCHAR | TAG | cluster id | + +### taosd\_dnodes\_log\_dir 表 + +`taosd_dnodes_log_dir` 表记录 log 目录信息。 + +| field | type | is\_tag | comment | +| :---------- | :-------- | :------ | :---------------------------------- | +| \_ts | TIMESTAMP | | timestamp | +| avail | DOUBLE | | log 目录可用空间。单位 byte | +| used | DOUBLE | | log 目录已使用空间。单位 byte | +| total | DOUBLE | | log 目录空间。单位 byte | +| name | VARCHAR | TAG | log 目录名,一般为 `/var/log/taos/` | +| dnode\_id | VARCHAR | TAG | dnode id | +| dnode\_ep | VARCHAR | TAG | dnode endpoint | +| cluster\_id | VARCHAR | TAG | cluster id | + +### taosd\_dnodes\_data\_dir 表 + +`taosd_dnodes_data_dir` 表记录 data 目录信息。 + +| field | type | is\_tag | comment | +| :---------- | :-------- | :------ | :-------------------------------- | +| \_ts | TIMESTAMP | | timestamp | +| avail | DOUBLE | | data 目录可用空间。单位 byte | +| used | DOUBLE | | data 目录已使用空间。单位 byte | +| total | DOUBLE | | data 目录空间。单位 byte | +| level | VARCHAR | TAG | 0、1、2 多级存储级别 | +| name | VARCHAR | TAG | data 目录,一般为 `/var/lib/taos` | +| dnode\_id | VARCHAR | TAG | dnode id | +| dnode\_ep | VARCHAR | TAG | dnode endpoint | +| cluster\_id | VARCHAR | TAG | cluster id | + +### taosd\_mnodes\_info 表 + +`taosd_mnodes_info` 表记录 mnode 角色信息。 + +| field | type | is\_tag | comment | +| :---------- | :-------- | :------ | :------------------------------------------------------------------------------------------------------- | +| \_ts | TIMESTAMP | | timestamp | +| role | DOUBLE | | mnode 角色, 取值范围:offline = 0,follower = 100,candidate = 101,leader = 102,error = 103,learner = 104 | +| mnode\_id | VARCHAR | TAG | master node id | +| mnode\_ep | VARCHAR | TAG | master node endpoint | +| cluster\_id | VARCHAR | TAG | cluster id | + +### taosd\_vnodes\_role 表 + +`taosd_vnodes_role` 表记录虚拟节点角色信息。 + +| field | type | is\_tag | comment | +| :------------- | :-------- | :------ | :------------------------------------------------------------------------------------------------------ | +| \_ts | TIMESTAMP | | timestamp | +| vnode\_role | DOUBLE | | vnode 角色,取值范围:offline = 0,follower = 100,candidate = 101,leader = 102,error = 103,learner = 104 | +| vgroup\_id | VARCHAR | TAG | dnode id | +| dnode\_id | VARCHAR | TAG | dnode id | +| database\_name | VARCHAR | TAG | vgroup 所属的 database 名字 | +| cluster\_id | VARCHAR | TAG | cluster id | + +### taosd\_sql\_req 表 + +`taosd_sql_req` 记录服务端 sql 请求信息。 + +| field | type | is\_tag | comment | +| :---------- | :-------- | :------ | :--------------------------------------- | +| \_ts | TIMESTAMP | | timestamp | +| count | DOUBLE | | sql 数量 | +| result | VARCHAR | TAG | sql的执行结果,取值范围:Success, Failed | +| username | VARCHAR | TAG | 执行sql的user name | +| sql\_type | VARCHAR | TAG | sql类型,取值范围:inserted_rows | +| dnode\_id | VARCHAR | TAG | dnode id | +| dnode\_ep | VARCHAR | TAG | dnode endpoint | +| vgroup\_id | VARCHAR | TAG | dnode id | +| cluster\_id | VARCHAR | TAG | cluster id | + +### taos\_sql\_req 表 + +`taos_sql_req` 记录客户端 sql 请求信息。 + +| field | type | is\_tag | comment | +| :---------- | :-------- | :------ | :---------------------------------------- | +| \_ts | TIMESTAMP | | timestamp | +| count | DOUBLE | | sql 数量 | +| result | VARCHAR | TAG | sql的执行结果,取值范围:Success, Failed | +| username | VARCHAR | TAG | 执行sql的user name | +| sql\_type | VARCHAR | TAG | sql类型,取值范围:select, insert,delete | +| cluster\_id | VARCHAR | TAG | cluster id | + +### taos\_slow\_sql 表 + +`taos_slow_sql` 记录客户端慢查询信息。 + +| field | type | is\_tag | comment | +| :---------- | :-------- | :------ | :---------------------------------------------------- | +| \_ts | TIMESTAMP | | timestamp | +| count | DOUBLE | | sql 数量 | +| result | VARCHAR | TAG | sql的执行结果,取值范围:Success, Failed | +| username | VARCHAR | TAG | 执行sql的user name | +| duration | VARCHAR | TAG | sql执行耗时,取值范围:3-10s,10-100s,100-1000s,1000s- | +| cluster\_id | VARCHAR | TAG | cluster id | + diff --git a/docs/zh/14-reference/01-components/03-taosadapter.md b/docs/zh/14-reference/01-components/03-taosadapter.md index 06ba4a9a07..84facad093 100644 --- a/docs/zh/14-reference/01-components/03-taosadapter.md +++ b/docs/zh/14-reference/01-components/03-taosadapter.md @@ -289,31 +289,32 @@ http 返回内容: ## taosAdapter 监控指标 -taosAdapter 采集 http 相关指标、CPU 百分比和内存百分比。 +taosAdapter 采集 REST/Websocket 相关请求的监控指标。将监控指标上报给 taosKeeper,这些监控指标会被 taosKeeper 写入监控数据库,默认是 `log` 库,可以在 taoskeeper 配置文件中修改。以下是这些监控指标的详细介绍。 -### http 接口 +#### adapter\_requests 表 -提供符合 [OpenMetrics](https://github.com/OpenObservability/OpenMetrics/blob/main/specification/OpenMetrics.md) 接口: +`adapter_requests` 记录 taosadapter 监控数据。 -```text -http://:6041/metrics -``` - -### 写入 TDengine - -taosAdapter 支持将 http 监控、CPU 百分比和内存百分比写入 TDengine。 - -有关配置参数 - -| **配置项** | **描述** | **默认值** | -|-------------------------|--------------------------------------------|----------| -| monitor.collectDuration | CPU 和内存采集间隔 | 3s | -| monitor.identity | 当前taosadapter 的标识符如果不设置将使用 'hostname:port' | | -| monitor.incgroup | 是否是 cgroup 中运行(容器中运行设置为 true) | false | -| monitor.writeToTD | 是否写入到 TDengine | false | -| monitor.user | TDengine 连接用户名 | root | -| monitor.password | TDengine 连接密码 | taosdata | -| monitor.writeInterval | 写入TDengine 间隔 | 30s | +| field | type | is\_tag | comment | +| :----------------- | :----------- | :------ | :---------------------------------- | +| ts | TIMESTAMP | | timestamp | +| total | INT UNSIGNED | | 总请求数 | +| query | INT UNSIGNED | | 查询请求数 | +| write | INT UNSIGNED | | 写入请求数 | +| other | INT UNSIGNED | | 其他请求数 | +| in\_process | INT UNSIGNED | | 正在处理请求数 | +| success | INT UNSIGNED | | 成功请求数 | +| fail | INT UNSIGNED | | 失败请求数 | +| query\_success | INT UNSIGNED | | 查询成功请求数 | +| query\_fail | INT UNSIGNED | | 查询失败请求数 | +| write\_success | INT UNSIGNED | | 写入成功请求数 | +| write\_fail | INT UNSIGNED | | 写入失败请求数 | +| other\_success | INT UNSIGNED | | 其他成功请求数 | +| other\_fail | INT UNSIGNED | | 其他失败请求数 | +| query\_in\_process | INT UNSIGNED | | 正在处理查询请求数 | +| write\_in\_process | INT UNSIGNED | | 正在处理写入请求数 | +| endpoint | VARCHAR | | 请求端点 | +| req\_type | NCHAR | TAG | 请求类型:0 为 REST,1 为 Websocket | ## 结果返回条数限制 @@ -342,11 +343,11 @@ taosAdapter 从 3.0.4.0 版本开始,提供参数 `smlAutoCreateDB` 来控制 在 TDengine server 2.2.x.x 或更早期版本中,taosd 进程包含一个内嵌的 http 服务。如前面所述,taosAdapter 是一个使用 systemd 管理的独立软件,拥有自己的进程。并且两者有一些配置参数和行为是不同的,请见下表: -| **#** | **embedded httpd** | **taosAdapter** | **comment** | -|-------|---------------------|-------------------------------|------------------------------------------------------------------------------------------------| -| 1 | httpEnableRecordSql | --logLevel=debug | | -| 2 | httpMaxThreads | n/a | taosAdapter 自动管理线程池,无需此参数 | +| **#** | **embedded httpd** | **taosAdapter** | **comment** | +| ----- | ------------------- | ------------------------------------ | ------------------------------------------------------------------------------------------------------------------------------------------ | +| 1 | httpEnableRecordSql | --logLevel=debug | | +| 2 | httpMaxThreads | n/a | taosAdapter 自动管理线程池,无需此参数 | | 3 | telegrafUseFieldNum | 请参考 taosAdapter telegraf 配置方法 | -| 4 | restfulRowLimit | restfulRowLimit | 内嵌 httpd 默认输出 10240 行数据,最大允许值为 102400。taosAdapter 也提供 restfulRowLimit 但是默认不做限制。您可以根据实际场景需求进行配置 | -| 5 | httpDebugFlag | 不适用 | httpdDebugFlag 对 taosAdapter 不起作用 | -| 6 | httpDBNameMandatory | 不适用 | taosAdapter 要求 URL 中必须指定数据库名 | +| 4 | restfulRowLimit | restfulRowLimit | 内嵌 httpd 默认输出 10240 行数据,最大允许值为 102400。taosAdapter 也提供 restfulRowLimit 但是默认不做限制。您可以根据实际场景需求进行配置 | +| 5 | httpDebugFlag | 不适用 | httpdDebugFlag 对 taosAdapter 不起作用 | +| 6 | httpDBNameMandatory | 不适用 | taosAdapter 要求 URL 中必须指定数据库名 | diff --git a/docs/zh/14-reference/01-components/04-taosx.md b/docs/zh/14-reference/01-components/04-taosx.md index 166b6ea760..e378c18800 100644 --- a/docs/zh/14-reference/01-components/04-taosx.md +++ b/docs/zh/14-reference/01-components/04-taosx.md @@ -90,11 +90,11 @@ taosx privileges -i ./user-pass-privileges-backup.json -t "taos:///" 可用参数列表: -| 参数 | 说明 | -| ---- | ---- | -| -u | 包含用户基本信息(密码、是否启用等) | -| -p | 包含权限信息 | -| -w | 包含白名单信息 | +| 参数 | 说明 | +| ---- | ------------------------------------ | +| -u | 包含用户基本信息(密码、是否启用等) | +| -p | 包含权限信息 | +| -w | 包含白名单信息 | 当 `-u`/`-p` 参数应用时,将仅包含指定的信息,不带参数时,表示所有信息(用户名、密码、权限和白名单)。 @@ -324,4 +324,131 @@ Linux 下 `journalctl` 查看日志的命令如下: ```bash journalctl -u taosx [-f] -``` \ No newline at end of file +``` + +## taosX 监控指标 + +taosX 会将监控指标上报给 taosKeeper,这些监控指标会被 taosKeeper 写入监控数据库,默认是 `log` 库,可以在 taoskeeper 配置文件中修改。以下是这些监控指标的详细介绍。 + +### taosX 服务 + +| 字段 | 描述 | +| -------------------------- | ----------------------------------------------------------------------------- | +| sys_cpu_cores | 系统 CPU 核数 | +| sys_total_memory | 系统总内存,单位:字节 | +| sys_used_memory | 系统已用内存, 单位:字节 | +| sys_available_memory | 系统可用内存, 单位:字节 | +| process_uptime | taosX 运行时长,单位:秒 | +| process_id | taosX 进程 ID | +| running_tasks | taosX 当前执行任务数 | +| completed_tasks | taosX 进程在一个监控周期(比如10s)内完成的任务数 | +| failed_tasks | taosX 进程在一个监控周期(比如10s)内失败的任务数 | +| process_cpu_percent | taosX 进程占用 CPU 百分比, 单位 % | +| process_memory_percent | taosX 进程占用内存百分比, 单位 % | +| process_disk_read_bytes | taosX 进程在一个监控周期(比如10s)内从硬盘读取的字节数的平均值,单位 bytes/s | +| process_disk_written_bytes | taosX 进程在一个监控周期(比如10s)内写到硬盘的字节数的平均值,单位 bytres/s | + + +### Agent + +| 字段 | 描述 | +| -------------------------- | ----------------------------------------------------------------------------- | +| sys_cpu_cores | 系统 CPU 核数 | +| sys_total_memory | 系统总内存,单位:字节 | +| sys_used_memory | 系统已用内存, 单位:字节 | +| sys_available_memory | 系统可用内存, 单位:字节 | +| process_uptime | agent 运行时长,单位:秒 | +| process_id | agent 进程 id | +| process_cpu_percent | agent 进程占用 CPU 百分比 | +| process_memory_percent | agent 进程占用内存百分比 | +| process_uptime | 进程启动时间,单位秒 | +| process_disk_read_bytes | agent 进程在一个监控周期(比如10s)内从硬盘读取的字节数的平均值,单位 bytes/s | +| process_disk_written_bytes | agent 进程在一个监控周期(比如10s)内写到硬盘的字节数的平均值,单位 bytes/s | + +### Connector + +| 字段 | 描述 | +| -------------------------- | --------------------------------------------------------------------------------- | +| process_id | connector 进程 id | +| process_uptime | 进程启动时间,单位秒 | +| process_cpu_percent | 进程占用 CPU 百分比, 单位 % | +| process_memory_percent | 进程占用内存百分比, 单位 % | +| process_disk_read_bytes | connector 进程在一个监控周期(比如10s)内从硬盘读取的字节数的平均值,单位 bytes/s | +| process_disk_written_bytes | connector 进程在一个监控周期(比如10s)内写到硬盘的字节数的平均值,单位 bytes/s | + +### taosX 通用数据源任务 + +| 字段 | 描述 | +| -------------------- | --------------------------------------------------------------- | +| total_execute_time | 任务累计运行时间,单位毫秒 | +| total_written_rowsls | 成功写入 TDengine 的总行数(包括重复记录) | +| total_written_points | 累计写入成功点数 (等于数据块包含的行数乘以数据块包含的列数) | +| start_time | 任务启动时间 (每次重启任务会被重置) | +| written_rows | 本次运行此任务成功写入 TDengine 的总行数(包括重复记录) | +| written_points | 本次运行写入成功点数 (等于数据块包含的行数乘以数据块包含的列数) | +| execute_time | 任务本次运行时间,单位秒 | + +### taosX TDengine V2 任务 + +| 字段 | 描述 | +| --------------------- | -------------------------------------------------------------------- | +| read_concurrency | 并发读取数据源的数据 worker 数, 也等于并发写入 TDengine 的 worker 数 | +| total_stables | 需要迁移的超级表数据数量 | +| total_updated_tags | 累计更新 tag 数 | +| total_created_tables | 累计创建子表数 | +| total_tables | 需要迁移的子表数量 | +| total_finished_tables | 完成数据迁移的子表数 (任务中断重启可能大于实际值) | +| total_success_blocks | 累计写入成功的数据块数 | +| finished_tables | 本次运行完成迁移子表数 | +| success_blocks | 本次写入成功的数据块数 | +| created_tables | 本次运行创建子表数 | +| updated_tags | 本次运行更新 tag 数 | + +### taosX TDengine V3 任务 + +| 字段 | 描述 | +| ---------------------- | ------------------------------------------------------- | +| total_messages | 通过 TMQ 累计收到的消息总数 | +| total_messages_of_meta | 通过 TMQ 累计收到的 Meta 类型的消息总数 | +| total_messages_of_data | 通过 TMQ 累计收到的 Data 和 MetaData 类型的消息总数 | +| total_write_raw_fails | 累计写入 raw meta 失败的次数 | +| total_success_blocks | 累计写入成功的数据块数 | +| topics | 通过 TMQ 订阅的主题数 | +| consumers | TMQ 消费者数 | +| messages | 本次运行通过 TMQ 收到的消息总数 | +| messages_of_meta | 本次运行通过 TMQ 收到的 Meta 类型的消息总数 | +| messages_of_data | 本次运行通过 TMQ 收到的 Data 和 MetaData 类型的消息总数 | +| write_raw_fails | 本次运行写入 raw meta 失败的次数 | +| success_blocks | 本次写入成功的数据块数 | + + +### taosX 其他数据源 任务 + +这些数据源包括: InfluxDB,OpenTSDB,OPC UA,OPC DA,PI,CSV,MQTT,AVEVA Historian 和 Kafka。 + +| 字段 | 描述 | +| ----------------------- | ----------------------------------------------------------- | +| total_received_batches | 通过 IPC Stream 收到的数据总批数 | +| total_processed_batches | 已经处理的批数 | +| total_processed_rows | 已经处理的总行数(等于每批包含数据行数之和) | +| total_inserted_sqls | 执行的 INSERT SQL 总条数 | +| total_failed_sqls | 执行失败的 INSERT SQL 总条数 | +| total_created_stables | 创建的超级表总数(可能大于实际值) | +| total_created_tables | 尝试创建子表总数(可能大于实际值) | +| total_failed_rows | 写入失败的总行数 | +| total_failed_point | 写入失败的总点数 | +| total_written_blocks | 写入成功的 raw block 总数 | +| total_failed_blocks | 写入失败的 raw block 总数 | +| received_batches | 本次运行此任务通过 IPC Stream 收到的数据总批数 | +| processed_batches | 本次运行已处理批数 | +| processed_rows | 本次处理的总行数(等于包含数据的 batch 包含的数据行数之和) | +| received_records | 本次运行此任务通过 IPC Stream 收到的数据总行数 | +| inserted_sqls | 本次运行此任务执行的 INSERT SQL 总条数 | +| failed_sqls | 本次运行此任务执行失败的 INSERT SQL 总条数 | +| created_stables | 本次运行此任务尝试创建超级表数(可能大于实际值) | +| created_tables | 本次运行此任务尝试创建子表数(可能大于实际值) | +| failed_rows | 本次运行此任务写入失败的行数 | +| failed_points | 本次运行此任务写入失败的点数 | +| written_blocks | 本次运行此任务写人成功的 raw block 数 | +| failed_blocks | 本次运行此任务写入失败的 raw block 数 | + diff --git a/docs/zh/14-reference/01-components/06-taoskeeper.md b/docs/zh/14-reference/01-components/06-taoskeeper.md index a1297230c4..2877728077 100644 --- a/docs/zh/14-reference/01-components/06-taoskeeper.md +++ b/docs/zh/14-reference/01-components/06-taoskeeper.md @@ -317,3 +317,19 @@ scrape_configs: 在 Grafana Dashboard 菜单点击 `import`,dashboard ID 填写 `18587`,点击 `Load` 按钮即可导入 `TaosKeeper Prometheus Dashboard for 3.x` dashboard。 + + +## taosKeeper 监控指标 + +taosKeeper 也会将自己采集的监控数据写入监控数据库,默认是 `log` 库,可以在 taoskeeper 配置文件中修改。 + +### keeper\_monitor 表 + +`keeper_monitor` 记录 taoskeeper 监控数据。 + +| field | type | is\_tag | comment | +| :------- | :-------- | :------ | :----------- | +| ts | TIMESTAMP | | timestamp | +| cpu | DOUBLE | | cpu 使用率 | +| mem | DOUBLE | | 内存使用率 | +| identify | NCHAR | TAG | 身份标识信息 | diff --git a/docs/zh/14-reference/01-components/12-tdinsight/index.mdx b/docs/zh/14-reference/01-components/12-tdinsight/index.mdx index 4058e579de..224fd5908d 100644 --- a/docs/zh/14-reference/01-components/12-tdinsight/index.mdx +++ b/docs/zh/14-reference/01-components/12-tdinsight/index.mdx @@ -15,8 +15,8 @@ TDengine 通过 taosKeeper 将服务器的 CPU、内存、硬盘空间、带宽 首先检查下面服务: - TDengine 已经安装并正常运行,此仪表盘需要 TDengine 3.0.0.0 及以上,并开启监控上报配置,具体配置请参考:[TDengine 监控配置](../taosd/#监控相关)。 -- taosAdapter 已经安装并正常运行。具体细节请参考:[taosAdapter 使用手册](../taosadapter) -- taosKeeper 已安装并正常运行。具体细节请参考:[taosKeeper 使用手册](../taoskeeper) +- taosAdapter 已经安装并正常运行。具体细节请参考:[taosAdapter 参考手册](../taosadapter) +- taosKeeper 已安装并正常运行。具体细节请参考:[taosKeeper 参考手册](../taoskeeper) 然后记录以下信息: diff --git a/docs/zh/14-reference/01-components/index.md b/docs/zh/14-reference/01-components/index.md index 4f26d202cc..65f3a10eca 100644 --- a/docs/zh/14-reference/01-components/index.md +++ b/docs/zh/14-reference/01-components/index.md @@ -1,6 +1,13 @@ ---- -sidebar_label: 产品组件 -title: 产品组件 -toc_max_heading_level: 4 -description: TDengine 产品组件参考手册 ---- \ No newline at end of file +--- +title: 产品组件 +description: TDengine 产品组件参考手册 +--- + +本节详细说明 TDengine 中的主要产品组件的功能、命令行参数、配置参数等。 + +```mdx-code-block +import DocCardList from '@theme/DocCardList'; +import {useCurrentSidebarCategory} from '@docusaurus/theme-common'; + + +``` \ No newline at end of file diff --git a/docs/zh/14-reference/05-connector/index.md b/docs/zh/14-reference/05-connector/index.md index be25521a30..1c051bf163 100644 --- a/docs/zh/14-reference/05-connector/index.md +++ b/docs/zh/14-reference/05-connector/index.md @@ -118,3 +118,9 @@ import VerifyMacOS from "./_verify_macos.mdx"; +```mdx-code-block +import DocCardList from '@theme/DocCardList'; +import {useCurrentSidebarCategory} from '@docusaurus/theme-common'; + + +``` \ No newline at end of file diff --git a/docs/zh/26-tdinternal/01-arch.md b/docs/zh/26-tdinternal/01-arch.md index fdec606239..04e47797a8 100644 --- a/docs/zh/26-tdinternal/01-arch.md +++ b/docs/zh/26-tdinternal/01-arch.md @@ -301,7 +301,7 @@ TDengine 采用了一种数据驱动的策略来实现缓存数据的持久化 对于采集的数据,通常会有一定的保留期限,该期限由数据库参数 keep 指定。超出设定天数的数据文件将被集群自动移除,并释放相应的存储空间。 -当设置 duration 和 keep 两个参数后,一个处于典型工作状态的 vnode 中,总的数据文件数量应为向上取整 (keep/duration)+1 个。数据文件的总个数应保持在一个合理的范围内,不宜过多也不宜过少,通常介于 10 到 100 之间较为适宜。基于这一原则,可以合理设置 duration 参数。在本书编写时的版本中,可以调整参数 keep,但参数 duration 一旦设定,则无法更改。 +当设置 duration 和 keep 两个参数后,一个处于典型工作状态的 vnode 中,总的数据文件数量应为向上取整 (keep/duration)+1 个。数据文件的总个数应保持在一个合理的范围内,不宜过多也不宜过少,通常介于 10 到 100 之间较为适宜。基于这一原则,可以合理设置 duration 参数。可以调整参数 keep,但参数 duration 一旦设定,则无法更改。 在每个数据文件中,表的数据是以块的形式存储的。一张表可能包含一到多个数据文件块。在一个文件块内,数据采用列式存储,占据连续的存储空间,这有助于显著提高读取度。文件块的大小由数据库参数 maxRows(每块最大记录条数)控制,默认值为 4096。这个值应适中,过大可能导致定位特定时间段数据的搜索时间变长,影响读取速度;过小则可能导致数据文件块的索引过大,压缩效率降低,同样影响读取速度。 diff --git a/include/client/taos.h b/include/client/taos.h index 1d2b3a913c..73ab52357a 100644 --- a/include/client/taos.h +++ b/include/client/taos.h @@ -270,7 +270,10 @@ DLL_EXPORT TAOS_RES *taos_schemaless_insert_raw_ttl(TAOS *taos, char *lines, int int precision, int32_t ttl); DLL_EXPORT TAOS_RES *taos_schemaless_insert_raw_ttl_with_reqid(TAOS *taos, char *lines, int len, int32_t *totalRows, int protocol, int precision, int32_t ttl, int64_t reqid); - +DLL_EXPORT TAOS_RES *taos_schemaless_insert_raw_ttl_with_reqid_tbname_key(TAOS *taos, char *lines, int len, int32_t *totalRows, + int protocol, int precision, int32_t ttl, int64_t reqid, char *tbnameKey); +DLL_EXPORT TAOS_RES *taos_schemaless_insert_ttl_with_reqid_tbname_key(TAOS *taos, char *lines[], int numLines, int protocol, + int precision, int32_t ttl, int64_t reqid, char *tbnameKey); /* --------------------------TMQ INTERFACE------------------------------- */ typedef struct tmq_t tmq_t; diff --git a/include/libs/executor/storageapi.h b/include/libs/executor/storageapi.h index 06a0a0348f..0cf52faa4f 100644 --- a/include/libs/executor/storageapi.h +++ b/include/libs/executor/storageapi.h @@ -246,12 +246,12 @@ typedef struct SStoreSnapshotFn { } SStoreSnapshotFn; typedef struct SStoreMeta { - SMTbCursor* (*openTableMetaCursor)(void* pVnode); // metaOpenTbCursor - void (*closeTableMetaCursor)(SMTbCursor* pTbCur); // metaCloseTbCursor - void (*pauseTableMetaCursor)(SMTbCursor* pTbCur); // metaPauseTbCursor - void (*resumeTableMetaCursor)(SMTbCursor* pTbCur, int8_t first, int8_t move); // metaResumeTbCursor - int32_t (*cursorNext)(SMTbCursor* pTbCur, ETableType jumpTableType); // metaTbCursorNext - int32_t (*cursorPrev)(SMTbCursor* pTbCur, ETableType jumpTableType); // metaTbCursorPrev + SMTbCursor* (*openTableMetaCursor)(void* pVnode); // metaOpenTbCursor + void (*closeTableMetaCursor)(SMTbCursor* pTbCur); // metaCloseTbCursor + void (*pauseTableMetaCursor)(SMTbCursor* pTbCur); // metaPauseTbCursor + int32_t (*resumeTableMetaCursor)(SMTbCursor* pTbCur, int8_t first, int8_t move); // metaResumeTbCursor + int32_t (*cursorNext)(SMTbCursor* pTbCur, ETableType jumpTableType); // metaTbCursorNext + int32_t (*cursorPrev)(SMTbCursor* pTbCur, ETableType jumpTableType); // metaTbCursorPrev int32_t (*getTableTags)(void* pVnode, uint64_t suid, SArray* uidList); int32_t (*getTableTagsByUid)(void* pVnode, int64_t suid, SArray* uidList); diff --git a/include/libs/function/taosudf.h b/include/libs/function/taosudf.h index 04b92a897a..0b59d7c2f5 100644 --- a/include/libs/function/taosudf.h +++ b/include/libs/function/taosudf.h @@ -320,6 +320,30 @@ typedef int32_t (*TScriptUdfDestoryFunc)(void *udfCtx); typedef int32_t (*TScriptOpenFunc)(SScriptUdfEnvItem *items, int numItems); typedef int32_t (*TScriptCloseFunc)(); +// clang-format off +#ifdef WINDOWS + #define fnFatal(...) {} + #define fnError(...) {} + #define fnWarn(...) {} + #define fnInfo(...) {} + #define fnDebug(...) {} + #define fnTrace(...) {} +#else + DLL_EXPORT void taosPrintLog(const char *flags, int32_t level, int32_t dflag, const char *format, ...) +#ifdef __GNUC__ + __attribute__((format(printf, 4, 5))) +#endif + ; + extern int32_t udfDebugFlag; + #define udfFatal(...) { if (udfDebugFlag & 1) { taosPrintLog("UDF FATAL ", 1, 255, __VA_ARGS__); }} + #define udfError(...) { if (udfDebugFlag & 1) { taosPrintLog("UDF ERROR ", 1, 255, __VA_ARGS__); }} + #define udfWarn(...) { if (udfDebugFlag & 2) { taosPrintLog("UDF WARN ", 2, 255, __VA_ARGS__); }} + #define udfInfo(...) { if (udfDebugFlag & 2) { taosPrintLog("UDF ", 2, 255, __VA_ARGS__); }} + #define udfDebug(...) { if (udfDebugFlag & 4) { taosPrintLog("UDF ", 4, udfDebugFlag, __VA_ARGS__); }} + #define udfTrace(...) { if (udfDebugFlag & 8) { taosPrintLog("UDF ", 8, udfDebugFlag, __VA_ARGS__); }} +#endif +// clang-format on + #ifdef __cplusplus } #endif diff --git a/include/util/tcompare.h b/include/util/tcompare.h index 80f992f646..c7a29cad57 100644 --- a/include/util/tcompare.h +++ b/include/util/tcompare.h @@ -49,6 +49,7 @@ int32_t InitRegexCache(); void DestroyRegexCache(); int32_t patternMatch(const char *pattern, size_t psize, const char *str, size_t ssize, const SPatternCompareInfo *pInfo); int32_t checkRegexPattern(const char *pPattern); +void DestoryThreadLocalRegComp(); int32_t wcsPatternMatch(const TdUcs4 *pattern, size_t psize, const TdUcs4 *str, size_t ssize, const SPatternCompareInfo *pInfo); diff --git a/include/util/tlog.h b/include/util/tlog.h index 67aafbfe44..b4dbbef532 100644 --- a/include/util/tlog.h +++ b/include/util/tlog.h @@ -74,13 +74,13 @@ void taosCloseLog(); void taosResetLog(); void taosDumpData(uint8_t *msg, int32_t len); -void taosPrintLog(const char *flags, ELogLevel level, int32_t dflag, const char *format, ...) +void taosPrintLog(const char *flags, int32_t level, int32_t dflag, const char *format, ...) #ifdef __GNUC__ __attribute__((format(printf, 4, 5))) #endif ; -void taosPrintLongString(const char *flags, ELogLevel level, int32_t dflag, const char *format, ...) +void taosPrintLongString(const char *flags, int32_t level, int32_t dflag, const char *format, ...) #ifdef __GNUC__ __attribute__((format(printf, 4, 5))) #endif diff --git a/source/client/inc/clientSml.h b/source/client/inc/clientSml.h index e901f86b41..209c376f30 100644 --- a/source/client/inc/clientSml.h +++ b/source/client/inc/clientSml.h @@ -204,6 +204,7 @@ typedef struct { STableMeta *currSTableMeta; STableDataCxt *currTableDataCtx; bool needModifySchema; + char *tbnameKey; } SSmlHandle; extern int64_t smlFactorNS[]; @@ -219,9 +220,10 @@ bool smlParseNumberOld(SSmlKv *kvVal, SSmlMsgBuf *msg); void smlBuildInvalidDataMsg(SSmlMsgBuf *pBuf, const char *msg1, const char *msg2); int32_t smlParseNumber(SSmlKv *kvVal, SSmlMsgBuf *msg); int64_t smlGetTimeValue(const char *value, int32_t len, uint8_t fromPrecision, uint8_t toPrecision); -int32_t smlBuildTableInfo(int numRows, const char* measure, int32_t measureLen, SSmlTableInfo** tInfo); + +int32_t smlBuildTableInfo(int numRows, const char* measure, int32_t measureLen, SSmlTableInfo** tInfo); int32_t smlBuildSTableMeta(bool isDataFormat, SSmlSTableMeta** sMeta); -int32_t smlSetCTableName(SSmlTableInfo *oneTable); +int32_t smlSetCTableName(SSmlTableInfo *oneTable, char *tbnameKey); int32_t getTableUid(SSmlHandle *info, SSmlLineInfo *currElement, SSmlTableInfo *tinfo); int32_t smlGetMeta(SSmlHandle *info, const void* measure, int32_t measureLen, STableMeta **pTableMeta); int32_t is_same_child_table_telnet(const void *a, const void *b); diff --git a/source/client/src/clientEnv.c b/source/client/src/clientEnv.c index 35e6651c41..d63701c529 100644 --- a/source/client/src/clientEnv.c +++ b/source/client/src/clientEnv.c @@ -374,8 +374,8 @@ int32_t openTransporter(const char *user, const char *auth, int32_t numOfThread, *pDnodeConn = rpcOpen(&rpcInit); if (*pDnodeConn == NULL) { - tscError("failed to init connection to server."); - code = TSDB_CODE_FAILED; + tscError("failed to init connection to server since %s", tstrerror(terrno)); + code = terrno; } return code; @@ -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(TSDB_CODE_TSC_DISCONNECTED); } 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; } @@ -869,7 +871,7 @@ _return: TSC_ERR_RET(terrno); } - return TSDB_CODE_SUCCESS; + return code; } void tscStopCrashReport() { diff --git a/source/client/src/clientHb.c b/source/client/src/clientHb.c index a174ae4b13..415c2d6685 100644 --- a/source/client/src/clientHb.c +++ b/source/client/src/clientHb.c @@ -1405,7 +1405,7 @@ _return: TSC_ERR_RET(terrno); } - return TSDB_CODE_SUCCESS; + return code; } static void hbStopThread() { diff --git a/source/client/src/clientImpl.c b/source/client/src/clientImpl.c index 4aa78caa15..664de5619f 100644 --- a/source/client/src/clientImpl.c +++ b/source/client/src/clientImpl.c @@ -2467,7 +2467,8 @@ TSDB_SERVER_STATUS taos_check_server_status(const char* fqdn, int port, char* de clientRpc = rpcOpen(&rpcInit); if (clientRpc == NULL) { - tscError("failed to init server status client"); + code = terrno; + tscError("failed to init server status client since %s", tstrerror(code)); goto _OVER; } diff --git a/source/client/src/clientSml.c b/source/client/src/clientSml.c index c244d36eb7..55be514e40 100644 --- a/source/client/src/clientSml.c +++ b/source/client/src/clientSml.c @@ -402,7 +402,7 @@ int32_t smlProcessChildTable(SSmlHandle *info, SSmlLineInfo *elements) { if (kv->valueEscaped) kv->value = NULL; } - code = smlSetCTableName(tinfo); + code = smlSetCTableName(tinfo, info->tbnameKey); if (code != TSDB_CODE_SUCCESS){ smlDestroyTableInfo(&tinfo); return code; @@ -486,10 +486,10 @@ int32_t smlParseEndLine(SSmlHandle *info, SSmlLineInfo *elements, SSmlKv *kvTs) return TSDB_CODE_SUCCESS; } -static int32_t smlParseTableName(SArray *tags, char *childTableName) { +static int32_t smlParseTableName(SArray *tags, char *childTableName, char *tbnameKey) { bool autoChildName = false; size_t delimiter = strlen(tsSmlAutoChildTableNameDelimiter); - if (delimiter > 0) { + if(delimiter > 0 && tbnameKey == NULL){ size_t totalNameLen = delimiter * (taosArrayGetSize(tags) - 1); for (int i = 0; i < taosArrayGetSize(tags); i++) { SSmlKv *tag = (SSmlKv *)taosArrayGet(tags, i); @@ -517,8 +517,11 @@ static int32_t smlParseTableName(SArray *tags, char *childTableName) { if (tsSmlDot2Underline) { smlStrReplace(childTableName, strlen(childTableName)); } - } else { - size_t childTableNameLen = strlen(tsSmlChildTableName); + }else{ + if (tbnameKey == NULL){ + tbnameKey = tsSmlChildTableName; + } + size_t childTableNameLen = strlen(tbnameKey); if (childTableNameLen <= 0) return TSDB_CODE_SUCCESS; for (int i = 0; i < taosArrayGetSize(tags); i++) { @@ -527,7 +530,7 @@ static int32_t smlParseTableName(SArray *tags, char *childTableName) { return TSDB_CODE_SML_INVALID_DATA; } // handle child table name - if (childTableNameLen == tag->keyLen && strncmp(tag->key, tsSmlChildTableName, tag->keyLen) == 0) { + if (childTableNameLen == tag->keyLen && strncmp(tag->key, tbnameKey, tag->keyLen) == 0) { (void)memset(childTableName, 0, TSDB_TABLE_NAME_LEN); (void)strncpy(childTableName, tag->value, (tag->length < TSDB_TABLE_NAME_LEN ? tag->length : TSDB_TABLE_NAME_LEN)); if (tsSmlDot2Underline) { @@ -542,8 +545,8 @@ static int32_t smlParseTableName(SArray *tags, char *childTableName) { return TSDB_CODE_SUCCESS; } -int32_t smlSetCTableName(SSmlTableInfo *oneTable) { - int32_t code = smlParseTableName(oneTable->tags, oneTable->childTableName); +int32_t smlSetCTableName(SSmlTableInfo *oneTable, char *tbnameKey) { + int32_t code = smlParseTableName(oneTable->tags, oneTable->childTableName, tbnameKey); if(code != TSDB_CODE_SUCCESS){ return code; } @@ -2127,7 +2130,7 @@ void smlSetReqSQL(SRequestObj *request, char *lines[], char *rawLine, char *rawL } TAOS_RES *taos_schemaless_insert_inner(TAOS *taos, char *lines[], char *rawLine, char *rawLineEnd, int numLines, - int protocol, int precision, int32_t ttl, int64_t reqid) { + int protocol, int precision, int32_t ttl, int64_t reqid, char *tbnameKey) { int32_t code = TSDB_CODE_SUCCESS; if (NULL == taos) { uError("SML:taos_schemaless_insert error taos is null"); @@ -2159,6 +2162,7 @@ TAOS_RES *taos_schemaless_insert_inner(TAOS *taos, char *lines[], char *rawLine, info->msgBuf.buf = info->pRequest->msgBuf; info->msgBuf.len = ERROR_MSG_BUF_DEFAULT_SIZE; info->lineNum = numLines; + info->tbnameKey = tbnameKey; smlSetReqSQL(request, lines, rawLine, rawLineEnd); @@ -2237,9 +2241,14 @@ end: * @return TAOS_RES */ +TAOS_RES *taos_schemaless_insert_ttl_with_reqid_tbname_key(TAOS *taos, char *lines[], int numLines, int protocol, + int precision, int32_t ttl, int64_t reqid, char *tbnameKey){ + return taos_schemaless_insert_inner(taos, lines, NULL, NULL, numLines, protocol, precision, ttl, reqid, tbnameKey); +} + TAOS_RES *taos_schemaless_insert_ttl_with_reqid(TAOS *taos, char *lines[], int numLines, int protocol, int precision, int32_t ttl, int64_t reqid) { - return taos_schemaless_insert_inner(taos, lines, NULL, NULL, numLines, protocol, precision, ttl, reqid); + return taos_schemaless_insert_ttl_with_reqid_tbname_key(taos, lines, numLines, protocol, precision, ttl, reqid, NULL); } TAOS_RES *taos_schemaless_insert(TAOS *taos, char *lines[], int numLines, int protocol, int precision) { @@ -2272,10 +2281,15 @@ static void getRawLineLen(char *lines, int len, int32_t *totalRows, int protocol } } +TAOS_RES *taos_schemaless_insert_raw_ttl_with_reqid_tbname_key(TAOS *taos, char *lines, int len, int32_t *totalRows, + int protocol, int precision, int32_t ttl, int64_t reqid, char *tbnameKey){ + getRawLineLen(lines, len, totalRows, protocol); + return taos_schemaless_insert_inner(taos, NULL, lines, lines + len, *totalRows, protocol, precision, ttl, reqid, tbnameKey); +} + TAOS_RES *taos_schemaless_insert_raw_ttl_with_reqid(TAOS *taos, char *lines, int len, int32_t *totalRows, int protocol, int precision, int32_t ttl, int64_t reqid) { - getRawLineLen(lines, len, totalRows, protocol); - return taos_schemaless_insert_inner(taos, NULL, lines, lines + len, *totalRows, protocol, precision, ttl, reqid); + return taos_schemaless_insert_raw_ttl_with_reqid_tbname_key(taos, lines, len, totalRows, protocol, precision, ttl, reqid, NULL); } TAOS_RES *taos_schemaless_insert_raw_with_reqid(TAOS *taos, char *lines, int len, int32_t *totalRows, int protocol, diff --git a/source/client/src/clientTmq.c b/source/client/src/clientTmq.c index 8cf39a51b9..197a65add8 100644 --- a/source/client/src/clientTmq.c +++ b/source/client/src/clientTmq.c @@ -1275,7 +1275,7 @@ tmq_t* tmq_consumer_new(tmq_conf_t* conf, char* errstr, int32_t errstrLen) { // init semaphore if (tsem2_init(&pTmq->rspSem, 0, 0) != 0) { - tscError("consumer:0x %" PRIx64 " setup failed since %s, consumer group %s", pTmq->consumerId, terrstr(), + tscError("consumer:0x %" PRIx64 " setup failed since %s, consumer group %s", pTmq->consumerId, tstrerror(TAOS_SYSTEM_ERROR(errno)), pTmq->groupId); SET_ERROR_MSG_TMQ("init t_sem failed") goto _failed; diff --git a/source/dnode/mgmt/node_mgmt/src/dmTransport.c b/source/dnode/mgmt/node_mgmt/src/dmTransport.c index 9bbfdd18b0..6de9665db9 100644 --- a/source/dnode/mgmt/node_mgmt/src/dmTransport.c +++ b/source/dnode/mgmt/node_mgmt/src/dmTransport.c @@ -393,8 +393,8 @@ int32_t dmInitClient(SDnode *pDnode) { pTrans->clientRpc = rpcOpen(&rpcInit); if (pTrans->clientRpc == NULL) { - dError("failed to init dnode rpc client"); - return -1; + dError("failed to init dnode rpc client since:%s", tstrerror(terrno)); + return terrno; } dDebug("dnode rpc client is initialized"); @@ -437,8 +437,8 @@ int32_t dmInitStatusClient(SDnode *pDnode) { pTrans->statusRpc = rpcOpen(&rpcInit); if (pTrans->statusRpc == NULL) { - dError("failed to init dnode rpc status client"); - return TSDB_CODE_OUT_OF_MEMORY; + dError("failed to init dnode rpc status client since %s", tstrerror(terrno)); + return terrno; } dDebug("dnode rpc status client is initialized"); @@ -482,8 +482,8 @@ int32_t dmInitSyncClient(SDnode *pDnode) { pTrans->syncRpc = rpcOpen(&rpcInit); if (pTrans->syncRpc == NULL) { - dError("failed to init dnode rpc sync client"); - return TSDB_CODE_OUT_OF_MEMORY; + dError("failed to init dnode rpc sync client since %s", tstrerror(terrno)); + return terrno; } dDebug("dnode rpc sync client is initialized"); @@ -532,7 +532,7 @@ int32_t dmInitServer(SDnode *pDnode) { (void)taosVersionStrToInt(version, &(rpcInit.compatibilityVer)); pTrans->serverRpc = rpcOpen(&rpcInit); if (pTrans->serverRpc == NULL) { - dError("failed to init dnode rpc server"); + dError("failed to init dnode rpc server since:%s", tstrerror(terrno)); return terrno; } diff --git a/source/dnode/mnode/impl/inc/mndConsumer.h b/source/dnode/mnode/impl/inc/mndConsumer.h index a773c61986..175730b91e 100644 --- a/source/dnode/mnode/impl/inc/mndConsumer.h +++ b/source/dnode/mnode/impl/inc/mndConsumer.h @@ -46,7 +46,7 @@ const char *mndConsumerStatusName(int status); #define MND_TMQ_NULL_CHECK(c) \ do { \ if (c == NULL) { \ - code = TSDB_CODE_OUT_OF_MEMORY; \ + code = TAOS_GET_TERRNO(TSDB_CODE_OUT_OF_MEMORY); \ goto END; \ } \ } while (0) diff --git a/source/dnode/mnode/impl/src/mndSubscribe.c b/source/dnode/mnode/impl/src/mndSubscribe.c index fe7c597e57..bff313dbaf 100644 --- a/source/dnode/mnode/impl/src/mndSubscribe.c +++ b/source/dnode/mnode/impl/src/mndSubscribe.c @@ -882,7 +882,7 @@ static int32_t buildRebOutput(SMnode *pMnode, SMqRebInputObj *rebInput, SMqRebOu rebInput->oldConsumerNum = 0; code = mndCreateSubscription(pMnode, pTopic, key, &rebOutput->pSub); if (code != 0) { - mError("[rebalance] mq rebalance %s failed create sub since %s, ignore", key, terrstr()); + mError("[rebalance] mq rebalance %s failed create sub since %s, ignore", key, tstrerror(code)); taosRUnLockLatch(&pTopic->lock); mndReleaseTopic(pMnode, pTopic); return code; @@ -1067,7 +1067,7 @@ static int32_t mndProcessDropCgroupReq(SRpcMsg *pMsg) { return 0; } else { code = TSDB_CODE_MND_SUBSCRIBE_NOT_EXIST; - mError("topic:%s, cgroup:%s, failed to drop since %s", dropReq.topic, dropReq.cgroup, terrstr()); + mError("topic:%s, cgroup:%s, failed to drop since %s", dropReq.topic, dropReq.cgroup, tstrerror(code)); return code; } } @@ -1075,7 +1075,7 @@ static int32_t mndProcessDropCgroupReq(SRpcMsg *pMsg) { taosWLockLatch(&pSub->lock); if (taosHashGetSize(pSub->consumerHash) != 0) { code = TSDB_CODE_MND_CGROUP_USED; - mError("cgroup:%s on topic:%s, failed to drop since %s", dropReq.cgroup, dropReq.topic, terrstr()); + mError("cgroup:%s on topic:%s, failed to drop since %s", dropReq.cgroup, dropReq.topic, tstrerror(code)); goto END; } diff --git a/source/dnode/mnode/impl/src/mndTopic.c b/source/dnode/mnode/impl/src/mndTopic.c index 4bca13508e..c27cc04ae8 100644 --- a/source/dnode/mnode/impl/src/mndTopic.c +++ b/source/dnode/mnode/impl/src/mndTopic.c @@ -574,7 +574,7 @@ static int32_t mndProcessCreateTopicReq(SRpcMsg *pReq) { END: if (code != 0 && code != TSDB_CODE_ACTION_IN_PROGRESS) { - mError("failed to create topic:%s since %s", createTopicReq.name, terrstr()); + mError("failed to create topic:%s since %s", createTopicReq.name, tstrerror(code)); } mndReleaseTopic(pMnode, pTopic); @@ -699,7 +699,7 @@ static int32_t mndProcessDropTopicReq(SRpcMsg *pReq) { tFreeSMDropTopicReq(&dropReq); return 0; } else { - mError("topic:%s, failed to drop since %s", dropReq.name, terrstr()); + mError("topic:%s, failed to drop since %s", dropReq.name, tstrerror(code)); tFreeSMDropTopicReq(&dropReq); return code; } @@ -727,7 +727,7 @@ END: mndReleaseTopic(pMnode, pTopic); mndTransDrop(pTrans); if (code != 0) { - mError("topic:%s, failed to drop since %s", dropReq.name, terrstr()); + mError("topic:%s, failed to drop since %s", dropReq.name, tstrerror(code)); tFreeSMDropTopicReq(&dropReq); return code; } diff --git a/source/dnode/vnode/src/inc/vnodeInt.h b/source/dnode/vnode/src/inc/vnodeInt.h index c45d6e6edf..416438b2ec 100644 --- a/source/dnode/vnode/src/inc/vnodeInt.h +++ b/source/dnode/vnode/src/inc/vnodeInt.h @@ -131,7 +131,7 @@ typedef SVCreateTSmaReq SSmaCfg; SMTbCursor* metaOpenTbCursor(void* pVnode); void metaCloseTbCursor(SMTbCursor* pTbCur); void metaPauseTbCursor(SMTbCursor* pTbCur); -void metaResumeTbCursor(SMTbCursor* pTbCur, int8_t first, int8_t move); +int32_t metaResumeTbCursor(SMTbCursor* pTbCur, int8_t first, int8_t move); int32_t metaTbCursorNext(SMTbCursor* pTbCur, ETableType jumpTableType); int32_t metaTbCursorPrev(SMTbCursor* pTbCur, ETableType jumpTableType); diff --git a/source/dnode/vnode/src/meta/metaQuery.c b/source/dnode/vnode/src/meta/metaQuery.c index e5dc34f4ab..1d284aaf1f 100644 --- a/source/dnode/vnode/src/meta/metaQuery.c +++ b/source/dnode/vnode/src/meta/metaQuery.c @@ -231,6 +231,7 @@ _exit: #if 1 // =================================================== SMTbCursor *metaOpenTbCursor(void *pVnode) { SMTbCursor *pTbCur = NULL; + int32_t code; pTbCur = (SMTbCursor *)taosMemoryCalloc(1, sizeof(*pTbCur)); if (pTbCur == NULL) { @@ -241,7 +242,12 @@ SMTbCursor *metaOpenTbCursor(void *pVnode) { // tdbTbcMoveToFirst((TBC *)pTbCur->pDbc); pTbCur->pMeta = pVnodeObj->pMeta; pTbCur->paused = 1; - metaResumeTbCursor(pTbCur, 1, 0); + code = metaResumeTbCursor(pTbCur, 1, 0); + if (code) { + terrno = code; + taosMemoryFree(pTbCur); + return NULL; + } return pTbCur; } @@ -266,28 +272,39 @@ void metaPauseTbCursor(SMTbCursor *pTbCur) { pTbCur->paused = 1; } } -void metaResumeTbCursor(SMTbCursor *pTbCur, int8_t first, int8_t move) { +int32_t metaResumeTbCursor(SMTbCursor *pTbCur, int8_t first, int8_t move) { + int32_t code = 0; + int32_t lino; + if (pTbCur->paused) { metaReaderDoInit(&pTbCur->mr, pTbCur->pMeta, META_READER_LOCK); - (void)tdbTbcOpen(((SMeta *)pTbCur->pMeta)->pUidIdx, (TBC **)&pTbCur->pDbc, NULL); + code = tdbTbcOpen(((SMeta *)pTbCur->pMeta)->pUidIdx, (TBC **)&pTbCur->pDbc, NULL); + TSDB_CHECK_CODE(code, lino, _exit); if (first) { - (void)tdbTbcMoveToFirst((TBC *)pTbCur->pDbc); + code = tdbTbcMoveToFirst((TBC *)pTbCur->pDbc); + TSDB_CHECK_CODE(code, lino, _exit); } else { int c = 1; - (void)tdbTbcMoveTo(pTbCur->pDbc, pTbCur->pKey, pTbCur->kLen, &c); + code = tdbTbcMoveTo(pTbCur->pDbc, pTbCur->pKey, pTbCur->kLen, &c); + TSDB_CHECK_CODE(code, lino, _exit); if (c == 0) { if (move) tdbTbcMoveToNext(pTbCur->pDbc); } else if (c < 0) { - (void)tdbTbcMoveToPrev(pTbCur->pDbc); + code = tdbTbcMoveToPrev(pTbCur->pDbc); + TSDB_CHECK_CODE(code, lino, _exit); } else { - (void)tdbTbcMoveToNext(pTbCur->pDbc); + code = tdbTbcMoveToNext(pTbCur->pDbc); + TSDB_CHECK_CODE(code, lino, _exit); } } pTbCur->paused = 0; } + +_exit: + return code; } int32_t metaTbCursorNext(SMTbCursor *pTbCur, ETableType jumpTableType) { @@ -355,7 +372,9 @@ _query: version = ((SUidIdxVal *)pData)[0].version; - (void)tdbTbGet(pMeta->pTbDb, &(STbDbKey){.uid = uid, .version = version}, sizeof(STbDbKey), &pData, &nData); + if (tdbTbGet(pMeta->pTbDb, &(STbDbKey){.uid = uid, .version = version}, sizeof(STbDbKey), &pData, &nData) != 0) { + goto _err; + } SMetaEntry me = {0}; tDecoderInit(&dc, pData, nData); @@ -385,7 +404,9 @@ _query: } tDecoderInit(&dc, pData, nData); - (void)tDecodeSSchemaWrapperEx(&dc, &schema); + if (tDecodeSSchemaWrapperEx(&dc, &schema) != 0) { + goto _err; + } pSchema = tCloneSSchemaWrapper(&schema); tDecoderClear(&dc); @@ -588,6 +609,7 @@ STSchema *metaGetTbTSchema(SMeta *pMeta, tb_uid_t uid, int32_t sver, int lock) { int32_t metaGetTbTSchemaEx(SMeta *pMeta, tb_uid_t suid, tb_uid_t uid, int32_t sver, STSchema **ppTSchema) { int32_t code = 0; + int32_t lino; void *pData = NULL; int nData = 0; @@ -603,7 +625,8 @@ int32_t metaGetTbTSchemaEx(SMeta *pMeta, tb_uid_t suid, tb_uid_t uid, int32_t sv skmDbKey.uid = suid ? suid : uid; skmDbKey.sver = INT32_MAX; - (void)tdbTbcOpen(pMeta->pSkmDb, &pSkmDbC, NULL); + code = tdbTbcOpen(pMeta->pSkmDb, &pSkmDbC, NULL); + TSDB_CHECK_CODE(code, lino, _exit); metaRLock(pMeta); if (tdbTbcMoveTo(pSkmDbC, &skmDbKey, sizeof(skmDbKey), &c) < 0) { diff --git a/source/dnode/vnode/src/meta/metaTable.c b/source/dnode/vnode/src/meta/metaTable.c index 2badeec2c9..596fbf70b0 100644 --- a/source/dnode/vnode/src/meta/metaTable.c +++ b/source/dnode/vnode/src/meta/metaTable.c @@ -306,12 +306,13 @@ _err: } int metaDropSTable(SMeta *pMeta, int64_t verison, SVDropStbReq *pReq, SArray *tbUidList) { - void *pKey = NULL; - int nKey = 0; - void *pData = NULL; - int nData = 0; - int c = 0; - int rc = 0; + void *pKey = NULL; + int nKey = 0; + void *pData = NULL; + int nData = 0; + int c = 0; + int rc = 0; + int32_t lino; // check if super table exists rc = tdbTbGet(pMeta->pNameIdx, pReq->name, strlen(pReq->name) + 1, &pData, &nData); @@ -323,7 +324,11 @@ int metaDropSTable(SMeta *pMeta, int64_t verison, SVDropStbReq *pReq, SArray *tb // drop all child tables TBC *pCtbIdxc = NULL; - (void)(void)tdbTbcOpen(pMeta->pCtbIdx, &pCtbIdxc, NULL); + rc = tdbTbcOpen(pMeta->pCtbIdx, &pCtbIdxc, NULL); + if (rc) { + return (terrno = rc); + } + rc = tdbTbcMoveTo(pCtbIdxc, &(SCtbIdxKey){.suid = pReq->suid, .uid = INT64_MIN}, sizeof(SCtbIdxKey), &c); if (rc < 0) { (void)tdbTbcClose(pCtbIdxc); @@ -379,20 +384,20 @@ _exit: return 0; } -static void metaGetSubtables(SMeta *pMeta, int64_t suid, SArray *uids) { - if (!uids) return; +static int32_t metaGetSubtables(SMeta *pMeta, int64_t suid, SArray *uids) { + if (!uids) return TSDB_CODE_INVALID_PARA; int c = 0; void *pKey = NULL; int nKey = 0; TBC *pCtbIdxc = NULL; - (void)tdbTbcOpen(pMeta->pCtbIdx, &pCtbIdxc, NULL); + TAOS_CHECK_RETURN(tdbTbcOpen(pMeta->pCtbIdx, &pCtbIdxc, NULL)); int rc = tdbTbcMoveTo(pCtbIdxc, &(SCtbIdxKey){.suid = suid, .uid = INT64_MIN}, sizeof(SCtbIdxKey), &c); if (rc < 0) { (void)tdbTbcClose(pCtbIdxc); metaWLock(pMeta); - return; + return 0; } for (;;) { @@ -405,12 +410,17 @@ static void metaGetSubtables(SMeta *pMeta, int64_t suid, SArray *uids) { break; } - (void)taosArrayPush(uids, &(((SCtbIdxKey *)pKey)->uid)); + if (taosArrayPush(uids, &(((SCtbIdxKey *)pKey)->uid)) == NULL) { + tdbFree(pKey); + (void)tdbTbcClose(pCtbIdxc); + return terrno; + } } tdbFree(pKey); (void)tdbTbcClose(pCtbIdxc); + return 0; } int metaAlterSTable(SMeta *pMeta, int64_t version, SVCreateStbReq *pReq) { @@ -425,7 +435,7 @@ int metaAlterSTable(SMeta *pMeta, int64_t version, SVCreateStbReq *pReq) { int32_t ret; int32_t c = -2; - (void)tdbTbcOpen(pMeta->pUidIdx, &pUidIdxc, NULL); + TAOS_CHECK_RETURN(tdbTbcOpen(pMeta->pUidIdx, &pUidIdxc, NULL)); ret = tdbTbcMoveTo(pUidIdxc, &pReq->suid, sizeof(tb_uid_t), &c); if (ret < 0 || c) { (void)tdbTbcClose(pUidIdxc); @@ -442,7 +452,7 @@ int metaAlterSTable(SMeta *pMeta, int64_t version, SVCreateStbReq *pReq) { oversion = ((SUidIdxVal *)pData)[0].version; - (void)tdbTbcOpen(pMeta->pTbDb, &pTbDbc, NULL); + TAOS_CHECK_RETURN(tdbTbcOpen(pMeta->pTbDb, &pTbDbc, NULL)); ret = tdbTbcMoveTo(pTbDbc, &((STbDbKey){.uid = pReq->suid, .version = oversion}), sizeof(STbDbKey), &c); if (!(ret == 0 && c == 0)) { (void)tdbTbcClose(pUidIdxc); @@ -486,7 +496,7 @@ int metaAlterSTable(SMeta *pMeta, int64_t version, SVCreateStbReq *pReq) { int16_t cid = pReq->schemaRow.pSchema[nCols - 1].colId; int8_t col_type = pReq->schemaRow.pSchema[nCols - 1].type; - metaGetSubtables(pMeta, pReq->suid, uids); + TAOS_CHECK_RETURN(metaGetSubtables(pMeta, pReq->suid, uids)); (void)tsdbCacheNewSTableColumn(pTsdb, uids, cid, col_type); } else if (deltaCol == -1) { int16_t cid = -1; @@ -502,7 +512,7 @@ int metaAlterSTable(SMeta *pMeta, int64_t version, SVCreateStbReq *pReq) { } if (cid != -1) { - metaGetSubtables(pMeta, pReq->suid, uids); + TAOS_CHECK_RETURN(metaGetSubtables(pMeta, pReq->suid, uids)); (void)tsdbCacheDropSTableColumn(pTsdb, uids, cid, hasPrimaryKey); } } @@ -619,7 +629,7 @@ int metaAddIndexToSTable(SMeta *pMeta, int64_t version, SVCreateStbReq *pReq) { * iterator all pTdDbc by uid and version */ TBC *pCtbIdxc = NULL; - (void)tdbTbcOpen(pMeta->pCtbIdx, &pCtbIdxc, NULL); + TAOS_CHECK_RETURN(tdbTbcOpen(pMeta->pCtbIdx, &pCtbIdxc, NULL)); int rc = tdbTbcMoveTo(pCtbIdxc, &(SCtbIdxKey){.suid = suid, .uid = INT64_MIN}, sizeof(SCtbIdxKey), &c); if (rc < 0) { (void)tdbTbcClose(pCtbIdxc); @@ -756,7 +766,7 @@ int metaDropIndexFromSTable(SMeta *pMeta, int64_t version, SDropIndexReq *pReq) * iterator all pTdDbc by uid and version */ TBC *pCtbIdxc = NULL; - (void)tdbTbcOpen(pMeta->pCtbIdx, &pCtbIdxc, NULL); + TAOS_CHECK_RETURN(tdbTbcOpen(pMeta->pCtbIdx, &pCtbIdxc, NULL)); int rc = tdbTbcMoveTo(pCtbIdxc, &(SCtbIdxKey){.suid = suid, .uid = INT64_MIN}, sizeof(SCtbIdxKey), &c); if (rc < 0) { (void)tdbTbcClose(pCtbIdxc); @@ -1424,7 +1434,7 @@ static int metaAlterTableColumn(SMeta *pMeta, int64_t version, SVAlterTbReq *pAl // search uid index TBC *pUidIdxc = NULL; - (void)tdbTbcOpen(pMeta->pUidIdx, &pUidIdxc, NULL); + TAOS_CHECK_RETURN(tdbTbcOpen(pMeta->pUidIdx, &pUidIdxc, NULL)); (void)tdbTbcMoveTo(pUidIdxc, &uid, sizeof(uid), &c); if (c != 0) { (void)tdbTbcClose(pUidIdxc); @@ -1438,7 +1448,7 @@ static int metaAlterTableColumn(SMeta *pMeta, int64_t version, SVAlterTbReq *pAl // search table.db TBC *pTbDbc = NULL; - (void)tdbTbcOpen(pMeta->pTbDb, &pTbDbc, NULL); + TAOS_CHECK_RETURN(tdbTbcOpen(pMeta->pTbDb, &pTbDbc, NULL)); (void)tdbTbcMoveTo(pTbDbc, &((STbDbKey){.uid = uid, .version = oversion}), sizeof(STbDbKey), &c); if (c != 0) { (void)tdbTbcClose(pUidIdxc); @@ -1689,7 +1699,7 @@ static int metaUpdateTableTagVal(SMeta *pMeta, int64_t version, SVAlterTbReq *pA // search uid index TBC *pUidIdxc = NULL; - (void)tdbTbcOpen(pMeta->pUidIdx, &pUidIdxc, NULL); + TAOS_CHECK_RETURN(tdbTbcOpen(pMeta->pUidIdx, &pUidIdxc, NULL)); (void)tdbTbcMoveTo(pUidIdxc, &uid, sizeof(uid), &c); if (c != 0) { (void)tdbTbcClose(pUidIdxc); @@ -1706,7 +1716,7 @@ static int metaUpdateTableTagVal(SMeta *pMeta, int64_t version, SVAlterTbReq *pA SDecoder dc2 = {0}; /* get ctbEntry */ - (void)tdbTbcOpen(pMeta->pTbDb, &pTbDbc, NULL); + TAOS_CHECK_RETURN(tdbTbcOpen(pMeta->pTbDb, &pTbDbc, NULL)); (void)tdbTbcMoveTo(pTbDbc, &((STbDbKey){.uid = uid, .version = oversion}), sizeof(STbDbKey), &c); if (c != 0) { (void)tdbTbcClose(pUidIdxc); @@ -1869,7 +1879,7 @@ static int metaUpdateTableOptions(SMeta *pMeta, int64_t version, SVAlterTbReq *p // search uid index TBC *pUidIdxc = NULL; - (void)tdbTbcOpen(pMeta->pUidIdx, &pUidIdxc, NULL); + TAOS_CHECK_RETURN(tdbTbcOpen(pMeta->pUidIdx, &pUidIdxc, NULL)); (void)tdbTbcMoveTo(pUidIdxc, &uid, sizeof(uid), &c); if (c != 0) { (void)tdbTbcClose(pUidIdxc); @@ -1883,7 +1893,7 @@ static int metaUpdateTableOptions(SMeta *pMeta, int64_t version, SVAlterTbReq *p // search table.db TBC *pTbDbc = NULL; - (void)tdbTbcOpen(pMeta->pTbDb, &pTbDbc, NULL); + TAOS_CHECK_RETURN(tdbTbcOpen(pMeta->pTbDb, &pTbDbc, NULL)); (void)tdbTbcMoveTo(pTbDbc, &((STbDbKey){.uid = uid, .version = oversion}), sizeof(STbDbKey), &c); if (c != 0) { (void)tdbTbcClose(pUidIdxc); @@ -2018,7 +2028,7 @@ static int metaAddTagIndex(SMeta *pMeta, int64_t version, SVAlterTbReq *pAlterTb * iterator all pTdDbc by uid and version */ TBC *pCtbIdxc = NULL; - (void)tdbTbcOpen(pMeta->pCtbIdx, &pCtbIdxc, NULL); + TAOS_CHECK_RETURN(tdbTbcOpen(pMeta->pCtbIdx, &pCtbIdxc, NULL)); int rc = tdbTbcMoveTo(pCtbIdxc, &(SCtbIdxKey){.suid = suid, .uid = INT64_MIN}, sizeof(SCtbIdxKey), &c); if (rc < 0) { (void)tdbTbcClose(pCtbIdxc); @@ -2157,7 +2167,7 @@ static int metaDropTagIndex(SMeta *pMeta, int64_t version, SVAlterTbReq *pAlterT SArray *tagIdxList = taosArrayInit(512, sizeof(SMetaPair)); TBC *pTagIdxc = NULL; - (void)tdbTbcOpen(pMeta->pTagIdx, &pTagIdxc, NULL); + TAOS_CHECK_RETURN(tdbTbcOpen(pMeta->pTagIdx, &pTagIdxc, NULL)); int rc = tdbTbcMoveTo(pTagIdxc, &(STagIdxKey){.suid = suid, .cid = INT32_MIN, .type = pCol->type}, sizeof(STagIdxKey), &c); for (;;) { diff --git a/source/dnode/vnode/src/tq/tqScan.c b/source/dnode/vnode/src/tq/tqScan.c index d072d7199c..4357456790 100644 --- a/source/dnode/vnode/src/tq/tqScan.c +++ b/source/dnode/vnode/src/tq/tqScan.c @@ -101,6 +101,7 @@ int32_t tqScanData(STQ* pTq, STqHandle* pHandle, SMqDataRsp* pRsp, STqOffsetVal* TSDB_CHECK_CODE(code, line, END); qStreamSetSourceExcluded(task, pRequest->sourceExcluded); + uint64_t st = taosGetTimestampMs(); while (1) { SSDataBlock* pDataBlock = NULL; code = getDataBlock(task, pHandle, vgId, &pDataBlock); @@ -160,7 +161,7 @@ int32_t tqScanData(STQ* pTq, STqHandle* pHandle, SMqDataRsp* pRsp, STqOffsetVal* pRsp->common.blockNum++; totalRows += pDataBlock->info.rows; - if (totalRows >= tmqRowSize) { + if (totalRows >= tmqRowSize || (taosGetTimestampMs() - st > 1000)) { break; } } diff --git a/source/libs/command/src/command.c b/source/libs/command/src/command.c index 2811402ea1..11ddc89d4c 100644 --- a/source/libs/command/src/command.c +++ b/source/libs/command/src/command.c @@ -38,7 +38,7 @@ static int32_t buildRetrieveTableRsp(SSDataBlock* pBlock, int32_t numOfCols, SRe size_t rspSize = sizeof(SRetrieveTableRsp) + blockGetEncodeSize(pBlock) + PAYLOAD_PREFIX_LEN; *pRsp = taosMemoryCalloc(1, rspSize); if (NULL == *pRsp) { - return TSDB_CODE_OUT_OF_MEMORY; + return terrno; } (*pRsp)->useconds = 0; @@ -289,7 +289,7 @@ static int32_t buildRetension(SArray* pRetension, char **ppRetentions ) { char* p1 = taosMemoryCalloc(1, 100); if(NULL == p1) { - return TSDB_CODE_OUT_OF_MEMORY; + return terrno; } int32_t len = 0; @@ -849,7 +849,7 @@ _return: static int32_t buildLocalVariablesResultDataBlock(SSDataBlock** pOutput) { SSDataBlock* pBlock = taosMemoryCalloc(1, sizeof(SSDataBlock)); if (NULL == pBlock) { - return TSDB_CODE_OUT_OF_MEMORY; + return terrno; } pBlock->info.hasVarCol = true; diff --git a/source/libs/command/src/explain.c b/source/libs/command/src/explain.c index 8d9f1fb9cc..3a73c05de2 100644 --- a/source/libs/command/src/explain.c +++ b/source/libs/command/src/explain.c @@ -227,7 +227,7 @@ int32_t qExplainGenerateResNode(SPhysiNode *pNode, SExplainGroup *group, SExplai SExplainResNode *resNode = taosMemoryCalloc(1, sizeof(SExplainResNode)); if (NULL == resNode) { qError("calloc SPhysiNodeExplainRes failed"); - return TSDB_CODE_OUT_OF_MEMORY; + return terrno; } int32_t code = 0; diff --git a/source/libs/executor/src/aggregateoperator.c b/source/libs/executor/src/aggregateoperator.c index af10bf8e49..093555c9c5 100644 --- a/source/libs/executor/src/aggregateoperator.c +++ b/source/libs/executor/src/aggregateoperator.c @@ -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; } @@ -340,6 +343,7 @@ int32_t doAggregateImpl(SOperatorInfo* pOperator, SqlFunctionCtx* pCtx) { static int32_t createDataBlockForEmptyInput(SOperatorInfo* pOperator, SSDataBlock** ppBlock) { int32_t code = TSDB_CODE_SUCCESS; int32_t lino = 0; + SSDataBlock* pBlock = NULL; if (!tsCountAlwaysReturnValue) { return TSDB_CODE_SUCCESS; } @@ -363,7 +367,6 @@ static int32_t createDataBlockForEmptyInput(SOperatorInfo* pOperator, SSDataBloc return TSDB_CODE_SUCCESS; } - SSDataBlock* pBlock = NULL; code = createDataBlock(&pBlock); if (code) { return code; @@ -411,6 +414,7 @@ static int32_t createDataBlockForEmptyInput(SOperatorInfo* pOperator, SSDataBloc _end: if (code != TSDB_CODE_SUCCESS) { + blockDataDestroy(pBlock); qError("%s failed at line %d since %s", __func__, __LINE__, tstrerror(code)); } return code; diff --git a/source/libs/executor/src/cachescanoperator.c b/source/libs/executor/src/cachescanoperator.c index 652ebc0f9a..5c8ca49813 100644 --- a/source/libs/executor/src/cachescanoperator.c +++ b/source/libs/executor/src/cachescanoperator.c @@ -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; } diff --git a/source/libs/executor/src/countwindowoperator.c b/source/libs/executor/src/countwindowoperator.c index 63c0c5fe87..9019fa0fef 100644 --- a/source/libs/executor/src/countwindowoperator.c +++ b/source/libs/executor/src/countwindowoperator.c @@ -294,10 +294,11 @@ int32_t createCountwindowOperatorInfo(SOperatorInfo* downstream, SPhysiNode* phy SSDataBlock* pResBlock = createDataBlockFromDescNode(pCountWindowNode->window.node.pOutputDataBlockDesc); QUERY_CHECK_NULL(pResBlock, code, lino, _error, terrno); + initBasicInfo(&pInfo->binfo, pResBlock); + code = blockDataEnsureCapacity(pResBlock, pOperator->resultInfo.capacity); QUERY_CHECK_CODE(code, lino, _error); - initBasicInfo(&pInfo->binfo, pResBlock); initResultRowInfo(&pInfo->binfo.resultRowInfo); pInfo->binfo.inputTsOrder = physiNode->inputTsOrder; pInfo->binfo.outputTsOrder = physiNode->outputTsOrder; @@ -341,7 +342,10 @@ _error: destroyCountWindowOperatorInfo(pInfo); } - destroyOperator(pOperator); + if (pOperator != NULL) { + pOperator->info = NULL; + destroyOperator(pOperator); + } pTaskInfo->code = code; return code; } diff --git a/source/libs/executor/src/eventwindowoperator.c b/source/libs/executor/src/eventwindowoperator.c index f9ae8be84f..d4e5dedd20 100644 --- a/source/libs/executor/src/eventwindowoperator.c +++ b/source/libs/executor/src/eventwindowoperator.c @@ -110,11 +110,11 @@ int32_t createEventwindowOperatorInfo(SOperatorInfo* downstream, SPhysiNode* phy SSDataBlock* pResBlock = createDataBlockFromDescNode(pEventWindowNode->window.node.pOutputDataBlockDesc); QUERY_CHECK_NULL(pResBlock, code, lino, _error, terrno); + initBasicInfo(&pInfo->binfo, pResBlock); code = blockDataEnsureCapacity(pResBlock, pOperator->resultInfo.capacity); QUERY_CHECK_CODE(code, lino, _error); - initBasicInfo(&pInfo->binfo, pResBlock); initResultRowInfo(&pInfo->binfo.resultRowInfo); pInfo->binfo.inputTsOrder = physiNode->inputTsOrder; pInfo->binfo.outputTsOrder = physiNode->outputTsOrder; @@ -145,7 +145,10 @@ _error: destroyEWindowOperatorInfo(pInfo); } - destroyOperator(pOperator); + if (pOperator != NULL) { + pOperator->info = NULL; + destroyOperator(pOperator); + } pTaskInfo->code = code; return code; } diff --git a/source/libs/executor/src/exchangeoperator.c b/source/libs/executor/src/exchangeoperator.c index 22bb6524f1..e4ebb74252 100644 --- a/source/libs/executor/src/exchangeoperator.c +++ b/source/libs/executor/src/exchangeoperator.c @@ -452,7 +452,10 @@ _error: doDestroyExchangeOperatorInfo(pInfo); } - destroyOperator(pOperator); + if (pOperator != NULL) { + pOperator->info = NULL; + destroyOperator(pOperator); + } pTaskInfo->code = code; return code; } @@ -707,8 +710,9 @@ 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); @@ -731,7 +735,7 @@ int32_t extractDataBlockFromFetchRsp(SSDataBlock* pRes, char* pData, SArray* pCo pStart += sizeof(SSysTableSchema); } - SSDataBlock* pBlock = NULL; + pBlock = NULL; code = createDataBlock(&pBlock); QUERY_CHECK_CODE(code, lino, _end); @@ -756,10 +760,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; diff --git a/source/libs/executor/src/executil.c b/source/libs/executor/src/executil.c index ae6351ab53..01d2ecd3c4 100644 --- a/source/libs/executor/src/executil.c +++ b/source/libs/executor/src/executil.c @@ -278,7 +278,7 @@ SSDataBlock* createDataBlockFromDescNode(SDataBlockDescNode* pNode) { qError("%s failed at line %d since %s", __func__, __LINE__, tstrerror(code)); blockDataDestroy(pBlock); pBlock = NULL; - terrno = code; + terrno = TSDB_CODE_INVALID_PARA; break; } SColumnInfoData idata = @@ -1094,7 +1094,7 @@ SSDataBlock* createTagValBlockForFilter(SArray* pColList, int32_t numOfTables, S code = blockDataEnsureCapacity(pResBlock, numOfTables); if (code != TSDB_CODE_SUCCESS) { terrno = code; - taosMemoryFree(pResBlock); + blockDataDestroy(pResBlock); return NULL; } @@ -1166,7 +1166,7 @@ SSDataBlock* createTagValBlockForFilter(SArray* pColList, int32_t numOfTables, S _end: if (code != TSDB_CODE_SUCCESS) { - taosMemoryFree(pResBlock); + blockDataDestroy(pResBlock); qError("%s failed at line %d since %s", __func__, lino, tstrerror(code)); terrno = code; return NULL; diff --git a/source/libs/executor/src/filloperator.c b/source/libs/executor/src/filloperator.c index 882a0dc4b6..f61b514626 100644 --- a/source/libs/executor/src/filloperator.c +++ b/source/libs/executor/src/filloperator.c @@ -567,7 +567,10 @@ _error: } pTaskInfo->code = code; - destroyOperator(pOperator); + if (pOperator != NULL) { + pOperator->info = NULL; + destroyOperator(pOperator); + } return code; } diff --git a/source/libs/executor/src/groupcacheoperator.c b/source/libs/executor/src/groupcacheoperator.c index f2e24f160c..00b8c3b9ae 100644 --- a/source/libs/executor/src/groupcacheoperator.c +++ b/source/libs/executor/src/groupcacheoperator.c @@ -1504,7 +1504,10 @@ _error: destroyGroupCacheOperator(pInfo); } - destroyOperator(pOperator); + if (pOperator != NULL) { + pOperator->info = NULL; + destroyOperator(pOperator); + } pTaskInfo->code = code; return code; } diff --git a/source/libs/executor/src/groupoperator.c b/source/libs/executor/src/groupoperator.c index 309fb4b52f..69a9045004 100644 --- a/source/libs/executor/src/groupoperator.c +++ b/source/libs/executor/src/groupoperator.c @@ -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; } diff --git a/source/libs/executor/src/operator.c b/source/libs/executor/src/operator.c index 376890771c..c2913108b0 100644 --- a/source/libs/executor/src/operator.c +++ b/source/libs/executor/src/operator.c @@ -652,7 +652,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); } diff --git a/source/libs/executor/src/projectoperator.c b/source/libs/executor/src/projectoperator.c index 7c9f242a63..3f1eb43578 100644 --- a/source/libs/executor/src/projectoperator.c +++ b/source/libs/executor/src/projectoperator.c @@ -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; } diff --git a/source/libs/executor/src/scanoperator.c b/source/libs/executor/src/scanoperator.c index 9a50d3987f..c98f716ef2 100644 --- a/source/libs/executor/src/scanoperator.c +++ b/source/libs/executor/src/scanoperator.c @@ -1466,7 +1466,10 @@ _error: destroyTableScanOperatorInfo(pInfo); } - destroyOperator(pOperator); + if (pOperator != NULL) { + pOperator->info = NULL; + destroyOperator(pOperator); + } pTaskInfo->code = code; return code; } @@ -3935,7 +3938,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) { @@ -4306,7 +4309,10 @@ _error: destroyStreamScanOperatorInfo(pInfo); } - destroyOperator(pOperator); + if (pOperator != NULL) { + pOperator->info = NULL; + destroyOperator(pOperator); + } pTaskInfo->code = code; return code; } @@ -4472,11 +4478,12 @@ static int32_t tagScanFilterByTagCond(SArray* aUidTags, SNode* pTagCond, SArray* int32_t code = TSDB_CODE_SUCCESS; int32_t lino = 0; int32_t numOfTables = taosArrayGetSize(aUidTags); + SArray* pBlockList = NULL; SSDataBlock* pResBlock = createTagValBlockForFilter(pInfo->filterCtx.cInfoList, numOfTables, aUidTags, pVnode, pAPI); QUERY_CHECK_NULL(pResBlock, code, lino, _end, terrno); - SArray* pBlockList = taosArrayInit(1, POINTER_BYTES); + pBlockList = taosArrayInit(1, POINTER_BYTES); QUERY_CHECK_NULL(pBlockList, code, lino, _end, terrno); void* tmp = taosArrayPush(pBlockList, &pResBlock); @@ -4766,7 +4773,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); @@ -4863,7 +4870,10 @@ _error: } if (pInfo != NULL) destroyTagScanOperatorInfo(pInfo); - destroyOperator(pOperator); + if (pOperator != NULL) { + pOperator->info = NULL; + destroyOperator(pOperator); + } return code; } @@ -5928,8 +5938,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) { @@ -5984,7 +5996,8 @@ int32_t createTableMergeScanOperatorInfo(STableScanPhysiNode* pTableScanNode, SR SOperatorInfo** pOptrInfo) { QRY_OPTR_CHECK(pOptrInfo); - int32_t code = 0; + int32_t code = TSDB_CODE_SUCCESS; + int32_t lino = 0; STableMergeScanInfo* pInfo = taosMemoryCalloc(1, sizeof(STableMergeScanInfo)); SOperatorInfo* pOperator = taosMemoryCalloc(1, sizeof(SOperatorInfo)); if (pInfo == NULL || pOperator == NULL) { @@ -5997,16 +6010,10 @@ int32_t createTableMergeScanOperatorInfo(STableScanPhysiNode* pTableScanNode, SR int32_t numOfCols = 0; code = extractColMatchInfo(pTableScanNode->scan.pScanCols, pDescNode, &numOfCols, COL_MATCH_FROM_COL_ID, &pInfo->base.matchInfo); - int32_t lino = 0; - if (code != TSDB_CODE_SUCCESS) { - goto _error; - } + QUERY_CHECK_CODE(code, lino, _error); code = initQueryTableDataCond(&pInfo->base.cond, pTableScanNode, readHandle); - if (code != TSDB_CODE_SUCCESS) { - taosArrayDestroy(pInfo->base.matchInfo.pList); - goto _error; - } + QUERY_CHECK_CODE(code, lino, _error); if (pTableScanNode->scan.pScanPseudoCols != NULL) { SExprSupp* pSup = &pInfo->base.pseudoSup; @@ -6021,10 +6028,7 @@ int32_t createTableMergeScanOperatorInfo(STableScanPhysiNode* pTableScanNode, SR pInfo->scanInfo = (SScanInfo){.numOfAsc = pTableScanNode->scanSeq[0], .numOfDesc = pTableScanNode->scanSeq[1]}; pInfo->base.metaCache.pTableMetaEntryCache = taosLRUCacheInit(1024 * 128, -1, .5); - if (pInfo->base.metaCache.pTableMetaEntryCache == NULL) { - code = terrno; - goto _error; - } + QUERY_CHECK_NULL(pInfo->base.metaCache.pTableMetaEntryCache, code, lino, _error, terrno); pInfo->base.readerAPI = pTaskInfo->storageAPI.tsdReader; pInfo->base.dataBlockLoadFlag = FUNC_DATA_REQUIRED_DATA_LOAD; @@ -6041,9 +6045,7 @@ int32_t createTableMergeScanOperatorInfo(STableScanPhysiNode* pTableScanNode, SR pInfo->sample.seed = taosGetTimestampSec(); code = filterInitFromNode((SNode*)pTableScanNode->scan.node.pConditions, &pOperator->exprSupp.pFilterInfo, 0); - if (code != TSDB_CODE_SUCCESS) { - goto _error; - } + QUERY_CHECK_CODE(code, lino, _error); initLimitInfo(pTableScanNode->scan.node.pLimit, pTableScanNode->scan.node.pSlimit, &pInfo->limitInfo); @@ -6105,10 +6107,16 @@ int32_t createTableMergeScanOperatorInfo(STableScanPhysiNode* pTableScanNode, SR return code; _error: + if (code != TSDB_CODE_SUCCESS) { + qError("%s failed at line %d since %s", __func__, lino, tstrerror(code)); + } pTaskInfo->code = code; pInfo->base.pTableListInfo = NULL; if (pInfo != NULL) destroyTableMergeScanOperatorInfo(pInfo); - destroyOperator(pOperator); + if (pOperator != NULL) { + pOperator->info = NULL; + destroyOperator(pOperator); + } return code; } @@ -6265,7 +6273,10 @@ _error: if (pInfo != NULL) { destoryTableCountScanOperator(pInfo); } - destroyOperator(pOperator); + if (pOperator != NULL) { + pOperator->info = NULL; + destroyOperator(pOperator); + } pTaskInfo->code = code; return code; } diff --git a/source/libs/executor/src/sortoperator.c b/source/libs/executor/src/sortoperator.c index 2a1b4f3e23..59b4e1cbbb 100644 --- a/source/libs/executor/src/sortoperator.c +++ b/source/libs/executor/src/sortoperator.c @@ -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; } diff --git a/source/libs/executor/src/streamcountwindowoperator.c b/source/libs/executor/src/streamcountwindowoperator.c index 6a22269266..bbaf84a4cb 100644 --- a/source/libs/executor/src/streamcountwindowoperator.c +++ b/source/libs/executor/src/streamcountwindowoperator.c @@ -927,7 +927,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; diff --git a/source/libs/executor/src/streameventwindowoperator.c b/source/libs/executor/src/streameventwindowoperator.c index c31047757e..3e4ffdda6e 100644 --- a/source/libs/executor/src/streameventwindowoperator.c +++ b/source/libs/executor/src/streameventwindowoperator.c @@ -982,7 +982,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; diff --git a/source/libs/executor/src/streamfilloperator.c b/source/libs/executor/src/streamfilloperator.c index 4cfacb03b4..29f96849ac 100644 --- a/source/libs/executor/src/streamfilloperator.c +++ b/source/libs/executor/src/streamfilloperator.c @@ -1458,7 +1458,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; } diff --git a/source/libs/executor/src/streamtimewindowoperator.c b/source/libs/executor/src/streamtimewindowoperator.c index f328aa15b9..6f5e17f5ab 100644 --- a/source/libs/executor/src/streamtimewindowoperator.c +++ b/source/libs/executor/src/streamtimewindowoperator.c @@ -2025,7 +2025,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; } @@ -3851,7 +3854,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; @@ -4107,7 +4113,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)); @@ -4998,7 +5007,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; @@ -5211,6 +5223,8 @@ int32_t createStreamIntervalOperatorInfo(SOperatorInfo* downstream, SPhysiNode* SSDataBlock* pResBlock = createDataBlockFromDescNode(pPhyNode->pOutputDataBlockDesc); QUERY_CHECK_NULL(pResBlock, code, lino, _error, terrno); + initBasicInfo(&pInfo->binfo, pResBlock); + pInfo->interval = (SInterval){ .interval = pIntervalPhyNode->interval, .sliding = pIntervalPhyNode->sliding, @@ -5238,7 +5252,6 @@ int32_t createStreamIntervalOperatorInfo(SOperatorInfo* downstream, SPhysiNode* SExprSupp* pSup = &pOperator->exprSupp; pSup->hasWindowOrGroup = true; - initBasicInfo(&pInfo->binfo, pResBlock); code = initExecTimeWindowInfo(&pInfo->twAggSup.timeWindowData, &pTaskInfo->window); QUERY_CHECK_CODE(code, lino, _error); @@ -5333,7 +5346,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; } diff --git a/source/libs/executor/src/sysscanoperator.c b/source/libs/executor/src/sysscanoperator.c index cdd22c2adc..e11ee6b0dc 100644 --- a/source/libs/executor/src/sysscanoperator.c +++ b/source/libs/executor/src/sysscanoperator.c @@ -568,7 +568,7 @@ static SSDataBlock* sysTableScanUserCols(SOperatorInfo* pOperator) { if (pInfo->pCur == NULL) { pInfo->pCur = pAPI->metaFn.openTableMetaCursor(pInfo->readHandle.vnode); } else { - pAPI->metaFn.resumeTableMetaCursor(pInfo->pCur, 0, 0); + (void)pAPI->metaFn.resumeTableMetaCursor(pInfo->pCur, 0, 0); } if (pInfo->pSchema == NULL) { @@ -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); @@ -777,8 +780,9 @@ static SSDataBlock* sysTableScanUserTags(SOperatorInfo* pOperator) { int32_t ret = 0; if (pInfo->pCur == NULL) { pInfo->pCur = pAPI->metaFn.openTableMetaCursor(pInfo->readHandle.vnode); + QUERY_CHECK_NULL(pInfo->pCur, code, lino, _end, terrno); } else { - pAPI->metaFn.resumeTableMetaCursor(pInfo->pCur, 0, 0); + (void)pAPI->metaFn.resumeTableMetaCursor(pInfo->pCur, 0, 0); } while ((ret = pAPI->metaFn.cursorNext(pInfo->pCur, TSDB_SUPER_TABLE)) == 0) { @@ -826,6 +830,7 @@ static SSDataBlock* sysTableScanUserTags(SOperatorInfo* pOperator) { } blockDataDestroy(dataBlock); + dataBlock = NULL; if (ret != 0) { pAPI->metaFn.closeTableMetaCursor(pInfo->pCur); pInfo->pCur = NULL; @@ -837,6 +842,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; @@ -1196,7 +1202,7 @@ static SSDataBlock* buildInfoSchemaTableMetaBlock(char* tableName) { } SSDataBlock* pBlock = NULL; - int32_t code = createDataBlock(&pBlock); + int32_t code = createDataBlock(&pBlock); if (code) { terrno = code; return NULL; @@ -1310,9 +1316,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 +1333,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 +1353,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); @@ -1366,7 +1375,7 @@ static SSDataBlock* sysTableBuildUserTablesByUids(SOperatorInfo* pOperator) { // table name SColumnInfoData* pColInfoData = taosArrayGet(p->pDataBlock, 0); QUERY_CHECK_NULL(pColInfoData, code, lino, _end, terrno); - + code = colDataSetVal(pColInfoData, numOfRows, n, false); QUERY_CHECK_CODE(code, lino, _end); @@ -1545,12 +1554,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,14 +1574,16 @@ 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) { pInfo->pCur = pAPI->metaFn.openTableMetaCursor(pInfo->readHandle.vnode); + QUERY_CHECK_NULL(pInfo->pCur, code, lino, _end, terrno); firstMetaCursor = 1; } if (!firstMetaCursor) { - pAPI->metaFn.resumeTableMetaCursor(pInfo->pCur, 0, 1); + (void)pAPI->metaFn.resumeTableMetaCursor(pInfo->pCur, 0, 1); } blockDataCleanup(pInfo->pRes); @@ -1590,7 +1603,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 +1796,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 +1810,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); } @@ -2021,7 +2036,7 @@ static void sysTableScanFillTbName(SOperatorInfo* pOperator, const SSysTableScan if (pInfo->tbnameSlotId != -1) { SColumnInfoData* pColumnInfoData = (SColumnInfoData*)taosArrayGet(pBlock->pDataBlock, pInfo->tbnameSlotId); QUERY_CHECK_NULL(pColumnInfoData, code, lino, _end, terrno); - char varTbName[TSDB_TABLE_FNAME_LEN - 1 + VARSTR_HEADER_SIZE] = {0}; + char varTbName[TSDB_TABLE_FNAME_LEN - 1 + VARSTR_HEADER_SIZE] = {0}; STR_TO_VARSTR(varTbName, name); code = colDataSetNItems(pColumnInfoData, 0, varTbName, pBlock->info.rows, true); @@ -2138,8 +2153,8 @@ static SSDataBlock* sysTableScanFromMNode(SOperatorInfo* pOperator, SSysTableSca } } -int32_t createSysTableScanOperatorInfo(void* readHandle, SSystemTableScanPhysiNode* pScanPhyNode, - const char* pUser, SExecTaskInfo* pTaskInfo, SOperatorInfo** pOptrInfo) { +int32_t createSysTableScanOperatorInfo(void* readHandle, SSystemTableScanPhysiNode* pScanPhyNode, const char* pUser, + SExecTaskInfo* pTaskInfo, SOperatorInfo** pOptrInfo) { QRY_OPTR_CHECK(pOptrInfo); int32_t code = TSDB_CODE_SUCCESS; @@ -2148,7 +2163,7 @@ int32_t createSysTableScanOperatorInfo(void* readHandle, SSystemTableScanPhysiNo SOperatorInfo* pOperator = taosMemoryCalloc(1, sizeof(SOperatorInfo)); if (pInfo == NULL || pOperator == NULL) { code = TSDB_CODE_OUT_OF_MEMORY; - lino = __LINE__; + lino = __LINE__; goto _error; } @@ -2209,7 +2224,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 +2262,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); } @@ -2437,10 +2455,10 @@ static FORCE_INLINE int optSysBinarySearch(SArray* arr, int s, int e, uint64_t k } int32_t optSysIntersection(SArray* in, SArray* out) { - int32_t code = TSDB_CODE_SUCCESS; - int32_t lino = 0; + int32_t code = TSDB_CODE_SUCCESS; + int32_t lino = 0; MergeIndex* mi = NULL; - int32_t sz = (int32_t)taosArrayGetSize(in); + int32_t sz = (int32_t)taosArrayGetSize(in); if (sz <= 0) { goto _end; } @@ -2678,7 +2696,6 @@ static int32_t doBlockInfoScanNext(SOperatorInfo* pOperator, SSDataBlock** ppRes int32_t slotId = pOperator->exprSupp.pExprInfo->base.resSchema.slotId; SColumnInfoData* pColInfo = taosArrayGet(pBlock->pDataBlock, slotId); QUERY_CHECK_NULL(pColInfo, code, lino, _end, terrno); - int32_t len = tSerializeBlockDistInfo(NULL, 0, &blockDistInfo); char* p = taosMemoryCalloc(1, len + VARSTR_HEADER_SIZE); @@ -2700,7 +2717,7 @@ static int32_t doBlockInfoScanNext(SOperatorInfo* pOperator, SSDataBlock** ppRes if (slotId != 0) { SColumnInfoData* p1 = taosArrayGet(pBlock->pDataBlock, 0); QUERY_CHECK_NULL(p1, code, lino, _end, terrno); - int64_t v = 0; + int64_t v = 0; colDataSetInt64(p1, 0, &v); } @@ -2726,7 +2743,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); } @@ -2760,11 +2779,12 @@ static int32_t initTableblockDistQueryCond(uint64_t uid, SQueryTableDataCond* pC } int32_t createDataBlockInfoScanOperator(SReadHandle* readHandle, SBlockDistScanPhysiNode* pBlockScanNode, - STableListInfo* pTableListInfo, SExecTaskInfo* pTaskInfo, SOperatorInfo** pOptrInfo) { + STableListInfo* pTableListInfo, SExecTaskInfo* pTaskInfo, + SOperatorInfo** pOptrInfo) { QRY_OPTR_CHECK(pOptrInfo); - int32_t code = 0; - int32_t lino = 0; + int32_t code = 0; + int32_t lino = 0; SBlockDistInfo* pInfo = taosMemoryCalloc(1, sizeof(SBlockDistInfo)); SOperatorInfo* pOperator = taosMemoryCalloc(1, sizeof(SOperatorInfo)); if (pInfo == NULL || pOperator == NULL) { @@ -2815,6 +2835,9 @@ _error: pInfo->pTableListInfo = NULL; destroyBlockDistScanOperatorInfo(pInfo); } - destroyOperator(pOperator); + if (pOperator != NULL) { + pOperator->info = NULL; + destroyOperator(pOperator); + } return code; } diff --git a/source/libs/executor/src/timesliceoperator.c b/source/libs/executor/src/timesliceoperator.c index d3d7a51cbe..30569db738 100644 --- a/source/libs/executor/src/timesliceoperator.c +++ b/source/libs/executor/src/timesliceoperator.c @@ -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; } diff --git a/source/libs/executor/src/timewindowoperator.c b/source/libs/executor/src/timewindowoperator.c index 99fa941071..ca6b89f7c5 100644 --- a/source/libs/executor/src/timewindowoperator.c +++ b/source/libs/executor/src/timewindowoperator.c @@ -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; } diff --git a/source/libs/executor/src/tsort.c b/source/libs/executor/src/tsort.c index 9e902140f4..cedc23ed2d 100644 --- a/source/libs/executor/src/tsort.c +++ b/source/libs/executor/src/tsort.c @@ -152,8 +152,10 @@ static void destoryAllocatedTuple(void* t) { taosMemoryFree(t); } * @param colIndex the columnIndex, for setting null bitmap * @return the next offset to add field * */ -static inline size_t tupleAddField(char** t, uint32_t colNum, uint32_t offset, uint32_t colIdx, void* data, - size_t length, bool isNull, uint32_t tupleLen) { +static inline int32_t tupleAddField(char** t, uint32_t colNum, uint32_t offset, uint32_t colIdx, void* data, + size_t length, bool isNull, uint32_t tupleLen, uint32_t* pOffset) { + int32_t code = TSDB_CODE_SUCCESS; + int32_t lino = 0; tupleSetOffset(*t, colIdx, offset); if (isNull) { @@ -161,16 +163,20 @@ static inline size_t tupleAddField(char** t, uint32_t colNum, uint32_t offset, u } else { if (offset + length > tupleLen + tupleGetDataStartOffset(colNum)) { void* px = taosMemoryRealloc(*t, offset + length); - if (px == NULL) { - return terrno; - } + QUERY_CHECK_NULL(px, code, lino, _end, terrno); *t = px; } tupleSetData(*t, offset, data, length); } - return offset + length; + (*pOffset) = offset + length; + +_end: + if (code != TSDB_CODE_SUCCESS) { + qError("%s failed at line %d since %s", __func__, lino, tstrerror(code)); + } + return code; } static void* tupleGetField(char* t, uint32_t colIdx, uint32_t colNum) { @@ -200,6 +206,7 @@ typedef struct ReferencedTuple { } ReferencedTuple; static int32_t createAllocatedTuple(SSDataBlock* pBlock, size_t colNum, uint32_t tupleLen, size_t rowIdx, TupleDesc** pDesc) { + int32_t code = TSDB_CODE_SUCCESS; TupleDesc* t = taosMemoryCalloc(1, sizeof(TupleDesc)); if (t == NULL) { return terrno; @@ -216,15 +223,20 @@ static int32_t createAllocatedTuple(SSDataBlock* pBlock, size_t colNum, uint32_t for (size_t colIdx = 0; colIdx < colNum; ++colIdx) { SColumnInfoData* pCol = taosArrayGet(pBlock->pDataBlock, colIdx); if (pCol == NULL) { + qError("%s failed at line %d since %s", __func__, __LINE__, tstrerror(terrno)); return terrno; } if (colDataIsNull_s(pCol, rowIdx)) { - offset = tupleAddField((char**)&pTuple, colNum, offset, colIdx, 0, 0, true, tupleLen); + code = tupleAddField((char**)&pTuple, colNum, offset, colIdx, 0, 0, true, tupleLen, &offset); } else { colLen = colDataGetRowLength(pCol, rowIdx); - offset = - tupleAddField((char**)&pTuple, colNum, offset, colIdx, colDataGetData(pCol, rowIdx), colLen, false, tupleLen); + code = + tupleAddField((char**)&pTuple, colNum, offset, colIdx, colDataGetData(pCol, rowIdx), colLen, false, tupleLen, &offset); + } + if (code != TSDB_CODE_SUCCESS) { + qError("%s failed at line %d since %s", __func__, __LINE__, tstrerror(code)); + return code; } } @@ -232,7 +244,7 @@ static int32_t createAllocatedTuple(SSDataBlock* pBlock, size_t colNum, uint32_t t->data = pTuple; *pDesc = t; - return 0; + return code; } int32_t tupleDescGetField(const TupleDesc* pDesc, int32_t colIdx, uint32_t colNum, void** pResult) { @@ -259,7 +271,7 @@ int32_t tupleDescGetField(const TupleDesc* pDesc, int32_t colIdx, uint32_t colNu void destroyTuple(void* t) { TupleDesc* pDesc = t; - if (pDesc->type == AllocatedTupleType) { + if (pDesc != NULL && pDesc->type == AllocatedTupleType) { destoryAllocatedTuple(pDesc->data); taosMemoryFree(pDesc); } @@ -1686,6 +1698,7 @@ static int32_t initRowIdSort(SSortHandle* pHandle) { biTs.compFn = getKeyComparFunc(TSDB_DATA_TYPE_TIMESTAMP, biTs.order); void* p = taosArrayPush(pOrderInfoList, &biTs); if (p == NULL) { + taosArrayDestroy(pOrderInfoList); return terrno; } @@ -1698,6 +1711,7 @@ static int32_t initRowIdSort(SSortHandle* pHandle) { void* px = taosArrayPush(pOrderInfoList, &biPk); if (px == NULL) { + taosArrayDestroy(pOrderInfoList); return terrno; } } diff --git a/source/libs/function/src/tudf.c b/source/libs/function/src/tudf.c index ad9e5ce7d4..9a751db801 100644 --- a/source/libs/function/src/tudf.c +++ b/source/libs/function/src/tudf.c @@ -162,7 +162,7 @@ static int32_t udfSpawnUdfd(SUdfdData *pData) { fnInfo("[UDFD]Succsess to set TAOS_FQDN:%s", taosFqdn); } else { fnError("[UDFD]Failed to allocate memory for TAOS_FQDN"); - return TSDB_CODE_OUT_OF_MEMORY; + return terrno; } } @@ -837,10 +837,13 @@ int32_t convertDataBlockToUdfDataBlock(SSDataBlock *block, SUdfDataBlock *udfBlo udfBlock->numOfRows = block->info.rows; udfBlock->numOfCols = taosArrayGetSize(block->pDataBlock); udfBlock->udfCols = taosMemoryCalloc(taosArrayGetSize(block->pDataBlock), sizeof(SUdfColumn *)); + if((udfBlock->udfCols) == NULL) { + return terrno; + } for (int32_t i = 0; i < udfBlock->numOfCols; ++i) { udfBlock->udfCols[i] = taosMemoryCalloc(1, sizeof(SUdfColumn)); if(udfBlock->udfCols[i] == NULL) { - return TSDB_CODE_OUT_OF_MEMORY; + return terrno; } SColumnInfoData *col = (SColumnInfoData *)taosArrayGet(block->pDataBlock, i); SUdfColumn *udfCol = udfBlock->udfCols[i]; @@ -854,13 +857,13 @@ int32_t convertDataBlockToUdfDataBlock(SSDataBlock *block, SUdfDataBlock *udfBlo udfCol->colData.varLenCol.varOffsetsLen = sizeof(int32_t) * udfBlock->numOfRows; udfCol->colData.varLenCol.varOffsets = taosMemoryMalloc(udfCol->colData.varLenCol.varOffsetsLen); if(udfCol->colData.varLenCol.varOffsets == NULL) { - return TSDB_CODE_OUT_OF_MEMORY; + return terrno; } memcpy(udfCol->colData.varLenCol.varOffsets, col->varmeta.offset, udfCol->colData.varLenCol.varOffsetsLen); udfCol->colData.varLenCol.payloadLen = colDataGetLength(col, udfBlock->numOfRows); udfCol->colData.varLenCol.payload = taosMemoryMalloc(udfCol->colData.varLenCol.payloadLen); if(udfCol->colData.varLenCol.payload == NULL) { - return TSDB_CODE_OUT_OF_MEMORY; + return terrno; } if (col->reassigned) { for (int32_t row = 0; row < udfCol->colData.numOfRows; ++row) { @@ -882,7 +885,7 @@ int32_t convertDataBlockToUdfDataBlock(SSDataBlock *block, SUdfDataBlock *udfBlo int32_t bitmapLen = udfCol->colData.fixLenCol.nullBitmapLen; udfCol->colData.fixLenCol.nullBitmap = taosMemoryMalloc(udfCol->colData.fixLenCol.nullBitmapLen); if(udfCol->colData.fixLenCol.nullBitmap == NULL) { - return TSDB_CODE_OUT_OF_MEMORY; + return terrno; } char *bitmap = udfCol->colData.fixLenCol.nullBitmap; memcpy(bitmap, col->nullbitmap, bitmapLen); @@ -985,7 +988,7 @@ int32_t convertDataBlockToScalarParm(SSDataBlock *input, SScalarParam *output) { output->columnData = taosMemoryMalloc(sizeof(SColumnInfoData)); if(output->columnData == NULL) { - return TSDB_CODE_OUT_OF_MEMORY; + return terrno; } memcpy(output->columnData, taosArrayGet(input->pDataBlock, 0), sizeof(SColumnInfoData)); output->colAlloced = true; @@ -1724,7 +1727,7 @@ int32_t udfcStartUvTask(SClientUvTaskNode *uvTask) { if(conn == NULL) { fnError("udfc event loop start connect task malloc conn failed."); taosMemoryFree(pipe); - return TSDB_CODE_OUT_OF_MEMORY; + return terrno; } conn->pipe = pipe; conn->readBuf.len = 0; @@ -1954,7 +1957,7 @@ int32_t udfcRunUdfUvTask(SClientUdfTask *task, int8_t uvTaskType) { SClientUvTaskNode *uvTask = taosMemoryCalloc(1, sizeof(SClientUvTaskNode)); if(uvTask == NULL) { fnError("udfc client task: %p failed to allocate memory for uvTask", task); - return TSDB_CODE_OUT_OF_MEMORY; + return terrno; } fnDebug("udfc client task: %p created uvTask: %p. pipe: %p", task, uvTask, task->session->udfUvPipe); @@ -1986,13 +1989,13 @@ int32_t doSetupUdf(char udfName[], UdfcFuncHandle *funcHandle) { SClientUdfTask *task = taosMemoryCalloc(1, sizeof(SClientUdfTask)); if(task == NULL) { fnError("doSetupUdf, failed to allocate memory for task"); - return TSDB_CODE_OUT_OF_MEMORY; + return terrno; } task->session = taosMemoryCalloc(1, sizeof(SUdfcUvSession)); if(task->session == NULL) { fnError("doSetupUdf, failed to allocate memory for session"); taosMemoryFree(task); - return TSDB_CODE_OUT_OF_MEMORY; + return terrno; } task->session->udfc = &gUdfcProxy; task->type = UDF_TASK_SETUP; @@ -2037,7 +2040,7 @@ int32_t callUdf(UdfcFuncHandle handle, int8_t callType, SSDataBlock *input, SUdf SClientUdfTask *task = taosMemoryCalloc(1, sizeof(SClientUdfTask)); if(task == NULL) { fnError("udfc call udf. failed to allocate memory for task"); - return TSDB_CODE_OUT_OF_MEMORY; + return terrno; } task->session = (SUdfcUvSession *)handle; task->type = UDF_TASK_CALL; @@ -2169,7 +2172,7 @@ int32_t doTeardownUdf(UdfcFuncHandle handle) { if(task == NULL) { fnError("doTeardownUdf, failed to allocate memory for task"); taosMemoryFree(session); - return TSDB_CODE_OUT_OF_MEMORY; + return terrno; } task->session = session; task->type = UDF_TASK_TEARDOWN; diff --git a/source/libs/function/src/udfd.c b/source/libs/function/src/udfd.c index 7339f115a3..2d8a926c72 100644 --- a/source/libs/function/src/udfd.c +++ b/source/libs/function/src/udfd.c @@ -409,6 +409,10 @@ int32_t udfdInitializePythonPlugin(SUdfScriptPlugin *plugin) { int16_t lenPythonPath = strlen(tsUdfdLdLibPath) + strlen(global.udfDataDir) + 1 + 1; // global.udfDataDir:tsUdfdLdLibPath char *pythonPath = taosMemoryMalloc(lenPythonPath); + if(pythonPath == NULL) { + uv_dlclose(&plugin->lib); + return terrno; + } #ifdef WINDOWS snprintf(pythonPath, lenPythonPath, "%s;%s", global.udfDataDir, tsUdfdLdLibPath); #else @@ -705,6 +709,10 @@ void udfdProcessSetupRequest(SUvUdfWork *uvUdf, SUdfRequest *request) { uv_mutex_unlock(&udf->lock); } SUdfcFuncHandle *handle = taosMemoryMalloc(sizeof(SUdfcFuncHandle)); + if(handle == NULL) { + fnError("udfdProcessSetupRequest: malloc failed."); + code = terrno; + } handle->udf = udf; _send: @@ -775,7 +783,7 @@ void udfdProcessCallRequest(SUvUdfWork *uvUdf, SUdfRequest *request) { if (outBuf.buf != NULL) { code = udf->scriptPlugin->udfAggStartFunc(&outBuf, udf->scriptUdfCtx); } else { - code = TSDB_CODE_OUT_OF_MEMORY; + code = terrno; } subRsp->resultBuf = outBuf; break; @@ -784,9 +792,13 @@ void udfdProcessCallRequest(SUvUdfWork *uvUdf, SUdfRequest *request) { SUdfDataBlock input = {0}; if (convertDataBlockToUdfDataBlock(&call->block, &input) == TSDB_CODE_SUCCESS) { SUdfInterBuf outBuf = {.buf = taosMemoryMalloc(udf->bufSize), .bufLen = udf->bufSize, .numOfResult = 0}; - code = udf->scriptPlugin->udfAggProcFunc(&input, &call->interBuf, &outBuf, udf->scriptUdfCtx); - freeUdfInterBuf(&call->interBuf); - subRsp->resultBuf = outBuf; + if (outBuf.buf != NULL) { + code = udf->scriptPlugin->udfAggProcFunc(&input, &call->interBuf, &outBuf, udf->scriptUdfCtx); + freeUdfInterBuf(&call->interBuf); + subRsp->resultBuf = outBuf; + } else { + code = terrno; + } } freeUdfDataDataBlock(&input); @@ -794,18 +806,27 @@ void udfdProcessCallRequest(SUvUdfWork *uvUdf, SUdfRequest *request) { } case TSDB_UDF_CALL_AGG_MERGE: { SUdfInterBuf outBuf = {.buf = taosMemoryMalloc(udf->bufSize), .bufLen = udf->bufSize, .numOfResult = 0}; - code = udf->scriptPlugin->udfAggMergeFunc(&call->interBuf, &call->interBuf2, &outBuf, udf->scriptUdfCtx); - freeUdfInterBuf(&call->interBuf); - freeUdfInterBuf(&call->interBuf2); - subRsp->resultBuf = outBuf; + if (outBuf.buf != NULL) { + code = udf->scriptPlugin->udfAggMergeFunc(&call->interBuf, &call->interBuf2, &outBuf, udf->scriptUdfCtx); + freeUdfInterBuf(&call->interBuf); + freeUdfInterBuf(&call->interBuf2); + subRsp->resultBuf = outBuf; + } else { + code = terrno; + } break; } case TSDB_UDF_CALL_AGG_FIN: { SUdfInterBuf outBuf = {.buf = taosMemoryMalloc(udf->bufSize), .bufLen = udf->bufSize, .numOfResult = 0}; - code = udf->scriptPlugin->udfAggFinishFunc(&call->interBuf, &outBuf, udf->scriptUdfCtx); - freeUdfInterBuf(&call->interBuf); - subRsp->resultBuf = outBuf; + if (outBuf.buf != NULL) { + code = udf->scriptPlugin->udfAggFinishFunc(&call->interBuf, &outBuf, udf->scriptUdfCtx); + freeUdfInterBuf(&call->interBuf); + subRsp->resultBuf = outBuf; + } else { + code = terrno; + } + break; } default: @@ -820,19 +841,24 @@ void udfdProcessCallRequest(SUvUdfWork *uvUdf, SUdfRequest *request) { int32_t len = encodeUdfResponse(NULL, rsp); if(len < 0) { fnError("udfdProcessCallRequest: encode udf response failed. len %d", len); - return; + goto _exit; } rsp->msgLen = len; void *bufBegin = taosMemoryMalloc(len); + if (bufBegin == NULL) { + fnError("udfdProcessCallRequest: malloc failed. len %d", len); + goto _exit; + } void *buf = bufBegin; if(encodeUdfResponse(&buf, rsp) < 0) { fnError("udfdProcessCallRequest: encode udf response failed. len %d", len); taosMemoryFree(bufBegin); - return; + goto _exit; } uvUdf->output = uv_buf_init(bufBegin, len); +_exit: switch (call->callType) { case TSDB_UDF_CALL_SCALA_PROC: { blockDataFreeRes(&call->block); @@ -906,6 +932,10 @@ _send: } rsp->msgLen = len; void *bufBegin = taosMemoryMalloc(len); + if(bufBegin == NULL) { + fnError("udfdProcessTeardownRequest: malloc failed. len %d", len); + return; + } void *buf = bufBegin; if (encodeUdfResponse(&buf, rsp) < 0) { fnError("udfdProcessTeardownRequest: encode udf response failed. len %d", len); @@ -1173,7 +1203,7 @@ int32_t udfdOpenClientRpc() { global.clientRpc = rpcOpen(&rpcInit); if (global.clientRpc == NULL) { fnError("failed to init dnode rpc client"); - return -1; + return terrno; } return 0; } @@ -1210,6 +1240,11 @@ void udfdSendResponse(uv_work_t *work, int status) { if (udfWork->conn != NULL) { uv_write_t *write_req = taosMemoryMalloc(sizeof(uv_write_t)); + if(write_req == NULL) { + fnError("udfd send response error, malloc failed"); + taosMemoryFree(work); + return; + } write_req->data = udfWork; int32_t code = uv_write(write_req, udfWork->conn->client, &udfWork->output, 1, udfdOnWrite); if (code != 0) { @@ -1269,7 +1304,16 @@ void udfdHandleRequest(SUdfdUvConn *conn) { int32_t inputLen = conn->inputLen; uv_work_t *work = taosMemoryMalloc(sizeof(uv_work_t)); + if(work == NULL) { + fnError("udfd malloc work failed"); + return; + } SUvUdfWork *udfWork = taosMemoryMalloc(sizeof(SUvUdfWork)); + if(udfWork == NULL) { + fnError("udfd malloc udf work failed"); + taosMemoryFree(work); + return; + } udfWork->conn = conn; udfWork->pWorkNext = conn->pWorkList; conn->pWorkList = udfWork; @@ -1334,6 +1378,10 @@ void udfdOnNewConnection(uv_stream_t *server, int status) { int32_t code = 0; uv_pipe_t *client = (uv_pipe_t *)taosMemoryMalloc(sizeof(uv_pipe_t)); + if(client == NULL) { + fnError("udfd pipe malloc failed"); + return; + } code = uv_pipe_init(global.loop, client, 0); if (code) { fnError("udfd pipe init error %s", uv_strerror(code)); @@ -1342,6 +1390,10 @@ void udfdOnNewConnection(uv_stream_t *server, int status) { } if (uv_accept(server, (uv_stream_t *)client) == 0) { SUdfdUvConn *ctx = taosMemoryMalloc(sizeof(SUdfdUvConn)); + if(ctx == NULL) { + fnError("udfd conn malloc failed"); + goto _exit; + } ctx->pWorkList = NULL; ctx->client = (uv_stream_t *)client; ctx->inputBuf = 0; @@ -1356,9 +1408,11 @@ void udfdOnNewConnection(uv_stream_t *server, int status) { taosMemoryFree(ctx); taosMemoryFree(client); } - } else { - uv_close((uv_handle_t *)client, NULL); + return; } +_exit: + uv_close((uv_handle_t *)client, NULL); + taosMemoryFree(client); } void udfdIntrSignalHandler(uv_signal_t *handle, int signum) { @@ -1411,6 +1465,10 @@ static int32_t udfdInitLog() { void udfdCtrlAllocBufCb(uv_handle_t *handle, size_t suggested_size, uv_buf_t *buf) { buf->base = taosMemoryMalloc(suggested_size); + if (buf->base == NULL) { + fnError("udfd ctrl pipe alloc buffer failed"); + return; + } buf->len = suggested_size; } @@ -1477,13 +1535,13 @@ static int32_t udfdGlobalDataInit() { uv_loop_t *loop = taosMemoryMalloc(sizeof(uv_loop_t)); if (loop == NULL) { fnError("udfd init uv loop failed, mem overflow"); - return -1; + return terrno; } global.loop = loop; if (uv_mutex_init(&global.scriptPluginsMutex) != 0) { fnError("udfd init script plugins mutex failed"); - return -1; + return TSDB_CODE_UDF_UV_EXEC_FAILURE; } global.udfsHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), true, HASH_NO_LOCK); @@ -1494,7 +1552,7 @@ static int32_t udfdGlobalDataInit() { if (uv_mutex_init(&global.udfsMutex) != 0) { fnError("udfd init udfs mutex failed"); - return -2; + return TSDB_CODE_UDF_UV_EXEC_FAILURE; } return 0; diff --git a/source/libs/qcom/src/querymsg.c b/source/libs/qcom/src/querymsg.c index e8deed1df9..207bd91bd9 100644 --- a/source/libs/qcom/src/querymsg.c +++ b/source/libs/qcom/src/querymsg.c @@ -34,7 +34,7 @@ int32_t queryBuildUseDbOutput(SUseDbOutput *pOut, SUseDbRsp *usedbRsp) { pOut->dbVgroup = taosMemoryCalloc(1, sizeof(SDBVgInfo)); if (NULL == pOut->dbVgroup) { - return TSDB_CODE_OUT_OF_MEMORY; + return terrno; } pOut->dbVgroup->vgVersion = usedbRsp->vgVersion; @@ -509,7 +509,7 @@ int32_t queryCreateTableMetaFromMsg(STableMetaRsp *msg, bool isStb, STableMeta * STableMeta *pTableMeta = taosMemoryCalloc(1, metaSize + schemaExtSize); if (NULL == pTableMeta) { qError("calloc size[%d] failed", metaSize); - return TSDB_CODE_OUT_OF_MEMORY; + return terrno; } SSchemaExt *pSchemaExt = (SSchemaExt *)((char *)pTableMeta + metaSize); @@ -764,7 +764,7 @@ int32_t queryProcessGetTbCfgRsp(void *output, char *msg, int32_t msgSize) { STableCfgRsp *out = taosMemoryCalloc(1, sizeof(STableCfgRsp)); if(out == NULL) { - return TSDB_CODE_OUT_OF_MEMORY; + return terrno; } if (tDeserializeSTableCfgRsp(msg, msgSize, out) != 0) { qError("tDeserializeSTableCfgRsp failed, msgSize:%d", msgSize); @@ -785,7 +785,7 @@ int32_t queryProcessGetViewMetaRsp(void *output, char *msg, int32_t msgSize) { SViewMetaRsp *out = taosMemoryCalloc(1, sizeof(SViewMetaRsp)); if (out == NULL) { - return TSDB_CODE_OUT_OF_MEMORY; + return terrno; } if (tDeserializeSViewMetaRsp(msg, msgSize, out) != 0) { qError("tDeserializeSViewMetaRsp failed, msgSize:%d", msgSize); diff --git a/source/libs/scalar/src/filter.c b/source/libs/scalar/src/filter.c index 5226668f82..e5d0fe594a 100644 --- a/source/libs/scalar/src/filter.c +++ b/source/libs/scalar/src/filter.c @@ -2343,7 +2343,7 @@ _return: (void)filterFreeRangeCtx(ctx); // No need to handle the return value. - return TSDB_CODE_SUCCESS; + return code; } int32_t filterMergeGroupUnits(SFilterInfo *info, SFilterGroupCtx **gRes, int32_t *gResNum) { @@ -2671,7 +2671,7 @@ _return: (void)filterFreeRangeCtx(ctx); // No need to handle the return value. - return TSDB_CODE_SUCCESS; + return code; } int32_t filterMergeGroups(SFilterInfo *info, SFilterGroupCtx **gRes, int32_t *gResNum) { @@ -2758,7 +2758,7 @@ _return: FILTER_SET_FLAG(info->status, FI_STATUS_ALL); - return TSDB_CODE_SUCCESS; + return code; } int32_t filterConvertGroupFromArray(SFilterInfo *info, SArray *group) { @@ -2958,7 +2958,7 @@ _return: taosMemoryFreeClear(idxNum); taosMemoryFreeClear(idxs); - return TSDB_CODE_SUCCESS; + return code; } int32_t filterPostProcessRange(SFilterInfo *info) { @@ -3601,12 +3601,12 @@ int32_t filterPreprocess(SFilterInfo *info) { if (FILTER_GET_FLAG(info->status, FI_STATUS_ALL)) { fltInfo("Final - FilterInfo: [ALL]"); - goto _return; + goto _return1; } if (FILTER_GET_FLAG(info->status, FI_STATUS_EMPTY)) { fltInfo("Final - FilterInfo: [EMPTY]"); - goto _return; + goto _return1; } FLT_ERR_JRET(filterGenerateColRange(info, gRes, gResNum)); @@ -3619,10 +3619,10 @@ int32_t filterPreprocess(SFilterInfo *info) { FLT_ERR_JRET(filterGenerateComInfo(info)); +_return1: + FLT_ERR_JRET(filterSetExecFunc(info)); + _return: - - FLT_ERR_RET(filterSetExecFunc(info)); - for (int32_t i = 0; i < gResNum; ++i) { filterFreeGroupCtx(gRes[i]); } @@ -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)) { @@ -4993,7 +5003,7 @@ int32_t fltOptimizeNodes(SFilterInfo *pInfo, SNode **pNode, SFltTreeStat *pStat) } _return: taosArrayDestroy(sclOpList); - return TSDB_CODE_SUCCESS; + return code; } int32_t fltGetDataFromColId(void *param, int32_t id, void **data) { diff --git a/source/libs/scalar/src/scalar.c b/source/libs/scalar/src/scalar.c index d08f358ce0..9428f051aa 100644 --- a/source/libs/scalar/src/scalar.c +++ b/source/libs/scalar/src/scalar.c @@ -904,9 +904,8 @@ int32_t sclExecOperator(SOperatorNode *node, SScalarCtx *ctx, SScalarParam *outp terrno = TSDB_CODE_SUCCESS; SCL_ERR_JRET(OperatorFn(pLeft, pRight, output, TSDB_ORDER_ASC)); - SCL_ERR_JRET(terrno); -_return: +_return: sclFreeParamList(params, paramNum); SCL_RET(code); } diff --git a/source/libs/scalar/src/sclfunc.c b/source/libs/scalar/src/sclfunc.c index cd67b89208..5db7aebeee 100644 --- a/source/libs/scalar/src/sclfunc.c +++ b/source/libs/scalar/src/sclfunc.c @@ -2913,7 +2913,7 @@ int32_t histogramScalarFunction(SScalarParam *pInput, int32_t inputNum, SScalarP _return: taosMemoryFree(bins); - return TSDB_CODE_SUCCESS; + return code; } int32_t selectScalarFunction(SScalarParam *pInput, int32_t inputNum, SScalarParam *pOutput) { diff --git a/source/libs/sync/test/sync_test_lib/src/syncIO.c b/source/libs/sync/test/sync_test_lib/src/syncIO.c index 11894f7853..f5a32b98d9 100644 --- a/source/libs/sync/test/sync_test_lib/src/syncIO.c +++ b/source/libs/sync/test/sync_test_lib/src/syncIO.c @@ -193,7 +193,7 @@ static int32_t syncIOStartInternal(SSyncIO *io) { io->clientRpc = rpcOpen(&rpcInit); if (io->clientRpc == NULL) { sError("failed to initialize RPC"); - return -1; + return terrno; } } @@ -214,7 +214,7 @@ static int32_t syncIOStartInternal(SSyncIO *io) { void *pRpc = rpcOpen(&rpcInit); if (pRpc == NULL) { sError("failed to start RPC server"); - return -1; + return terrno; } } diff --git a/source/libs/tdb/src/db/tdbBtree.c b/source/libs/tdb/src/db/tdbBtree.c index 87ea12dd81..59b7f4af2e 100644 --- a/source/libs/tdb/src/db/tdbBtree.c +++ b/source/libs/tdb/src/db/tdbBtree.c @@ -194,7 +194,11 @@ int tdbBtreeInsert(SBTree *pBt, const void *pKey, int kLen, const void *pVal, in int idx; int c; - (void)tdbBtcOpen(&btc, pBt, pTxn); + ret = tdbBtcOpen(&btc, pBt, pTxn); + if (ret) { + tdbError("tdb/btree-insert: btc open failed with ret: %d.", ret); + return ret; + } tdbTrace("tdb insert, btc: %p, pTxn: %p", &btc, pTxn); @@ -235,7 +239,11 @@ int tdbBtreeDelete(SBTree *pBt, const void *pKey, int kLen, TXN *pTxn) { int c; int ret; - (void)tdbBtcOpen(&btc, pBt, pTxn); + ret = tdbBtcOpen(&btc, pBt, pTxn); + if (ret) { + tdbError("tdb/btree-delete: btc open failed with ret: %d.", ret); + return ret; + } /* btc.coder.ofps = taosArrayInit(8, sizeof(SPage *)); // btc.coder.ofps = taosArrayInit(8, sizeof(SPgno)); @@ -337,7 +345,11 @@ int tdbBtreePGet(SBTree *pBt, const void *pKey, int kLen, void **ppKey, int *pkL void *pTVal = NULL; SCellDecoder cd = {0}; - (void)tdbBtcOpen(&btc, pBt, NULL); + ret = tdbBtcOpen(&btc, pBt, NULL); + if (ret) { + tdbError("tdb/btree-pget: btc open failed with ret: %d.", ret); + return ret; + } tdbTrace("tdb pget, btc: %p", &btc); diff --git a/source/libs/transport/test/cliBench.c b/source/libs/transport/test/cliBench.c index 8a5276b814..ec08f1baf0 100644 --- a/source/libs/transport/test/cliBench.c +++ b/source/libs/transport/test/cliBench.c @@ -160,7 +160,7 @@ int main(int argc, char *argv[]) { void *pRpc = rpcOpen(&rpcInit); if (pRpc == NULL) { tError("failed to initialize RPC"); - return -1; + return terrno; } tInfo("client is initialized"); diff --git a/source/util/src/tcompare.c b/source/util/src/tcompare.c index 4cb48bffe5..670a70a309 100644 --- a/source/util/src/tcompare.c +++ b/source/util/src/tcompare.c @@ -1208,20 +1208,28 @@ typedef struct UsingRegex { regex_t pRegex; int32_t lastUsedTime; } UsingRegex; +typedef UsingRegex* HashRegexPtr; typedef struct RegexCache { SHashObj *regexHash; void *regexCacheTmr; void *timer; + SRWLatch mutex; + bool exit; } RegexCache; static RegexCache sRegexCache; #define MAX_REGEX_CACHE_SIZE 20 #define REGEX_CACHE_CLEAR_TIME 30 static void checkRegexCache(void* param, void* tmrId) { + int32_t code = 0; + taosRLockLatch(&sRegexCache.mutex); + if(sRegexCache.exit) { + goto _exit; + } (void)taosTmrReset(checkRegexCache, REGEX_CACHE_CLEAR_TIME * 1000, param, sRegexCache.regexCacheTmr, &tmrId); if (taosHashGetSize(sRegexCache.regexHash) < MAX_REGEX_CACHE_SIZE) { - return; + goto _exit; } if (taosHashGetSize(sRegexCache.regexHash) >= MAX_REGEX_CACHE_SIZE) { @@ -1235,6 +1243,8 @@ static void checkRegexCache(void* param, void* tmrId) { ppUsingRegex = taosHashIterate(sRegexCache.regexHash, ppUsingRegex); } } +_exit: + taosRUnLockLatch(&sRegexCache.mutex); } void regexCacheFree(void *ppUsingRegex) { @@ -1246,30 +1256,35 @@ int32_t InitRegexCache() { sRegexCache.regexHash = taosHashInit(64, taosGetDefaultHashFunction(TSDB_DATA_TYPE_BINARY), false, HASH_ENTRY_LOCK); if (sRegexCache.regexHash == NULL) { uError("failed to create RegexCache"); - return -1; + return terrno; } taosHashSetFreeFp(sRegexCache.regexHash, regexCacheFree); sRegexCache.regexCacheTmr = taosTmrInit(0, 0, 0, "REGEXCACHE"); if (sRegexCache.regexCacheTmr == NULL) { uError("failed to create regex cache check timer"); - terrno = TSDB_CODE_OUT_OF_MEMORY; - return -1; + return terrno; } + sRegexCache.exit = false; + taosInitRWLatch(&sRegexCache.mutex); sRegexCache.timer = taosTmrStart(checkRegexCache, REGEX_CACHE_CLEAR_TIME * 1000, NULL, sRegexCache.regexCacheTmr); if (sRegexCache.timer == NULL) { uError("failed to start regex cache timer"); - return -1; + return terrno; } - return 0; + return TSDB_CODE_SUCCESS; } void DestroyRegexCache(){ + int32_t code = 0; uInfo("[regex cache] destory regex cache"); (void)taosTmrStopA(&sRegexCache.timer); + taosWLockLatch(&sRegexCache.mutex); + sRegexCache.exit = true; taosHashCleanup(sRegexCache.regexHash); taosTmrCleanUp(sRegexCache.regexCacheTmr); + taosWUnLockLatch(&sRegexCache.mutex); } int32_t checkRegexPattern(const char *pPattern) { @@ -1290,18 +1305,17 @@ int32_t checkRegexPattern(const char *pPattern) { return TSDB_CODE_SUCCESS; } -static UsingRegex **getRegComp(const char *pPattern) { - UsingRegex **ppUsingRegex = (UsingRegex **)taosHashAcquire(sRegexCache.regexHash, pPattern, strlen(pPattern)); +int32_t getRegComp(const char *pPattern, HashRegexPtr **regexRet) { + HashRegexPtr* ppUsingRegex = (HashRegexPtr*)taosHashAcquire(sRegexCache.regexHash, pPattern, strlen(pPattern)); if (ppUsingRegex != NULL) { (*ppUsingRegex)->lastUsedTime = taosGetTimestampSec(); - return ppUsingRegex; + *regexRet = ppUsingRegex; + return TSDB_CODE_SUCCESS; } - UsingRegex *pUsingRegex = taosMemoryMalloc(sizeof(UsingRegex)); if (pUsingRegex == NULL) { - terrno = TSDB_CODE_OUT_OF_MEMORY; uError("Failed to Malloc when compile regex pattern %s.", pPattern); - return NULL; + return terrno; } int32_t cflags = REG_EXTENDED; int32_t ret = regcomp(&pUsingRegex->pRegex, pPattern, cflags); @@ -1310,8 +1324,7 @@ static UsingRegex **getRegComp(const char *pPattern) { (void)regerror(ret, &pUsingRegex->pRegex, msgbuf, tListLen(msgbuf)); uError("Failed to compile regex pattern %s. reason %s", pPattern, msgbuf); taosMemoryFree(pUsingRegex); - terrno = TSDB_CODE_PAR_REGULAR_EXPRESSION_ERROR; - return NULL; + return TSDB_CODE_PAR_REGULAR_EXPRESSION_ERROR; } while (true) { @@ -1319,8 +1332,9 @@ static UsingRegex **getRegComp(const char *pPattern) { if (code != 0 && code != TSDB_CODE_DUP_KEY) { regexCacheFree(&pUsingRegex); uError("Failed to put regex pattern %s into cache, exception internal error.", pPattern); - terrno = code; - return NULL; + return code; + } else if (code == TSDB_CODE_DUP_KEY) { + terrno = 0; } ppUsingRegex = (UsingRegex **)taosHashAcquire(sRegexCache.regexHash, pPattern, strlen(pPattern)); if (ppUsingRegex) { @@ -1334,27 +1348,68 @@ static UsingRegex **getRegComp(const char *pPattern) { } } pUsingRegex->lastUsedTime = taosGetTimestampSec(); - return ppUsingRegex; + *regexRet = ppUsingRegex; + return TSDB_CODE_SUCCESS; } void releaseRegComp(UsingRegex **regex){ taosHashRelease(sRegexCache.regexHash, regex); } +static threadlocal UsingRegex ** ppUsingRegex; +static threadlocal regex_t * pRegex; +static threadlocal char *pOldPattern = NULL; +void DestoryThreadLocalRegComp() { + if (NULL != pOldPattern) { + releaseRegComp(ppUsingRegex); + taosMemoryFree(pOldPattern); + ppUsingRegex = NULL; + pRegex = NULL; + pOldPattern = NULL; + } +} + +int32_t threadGetRegComp(regex_t **regex, const char *pPattern) { + if (NULL != pOldPattern) { + if (strcmp(pOldPattern, pPattern) == 0) { + *regex = pRegex; + return 0; + } else { + DestoryThreadLocalRegComp(); + } + } + + HashRegexPtr *ppRegex = NULL; + int32_t code = getRegComp(pPattern, &ppRegex); + if (code != TSDB_CODE_SUCCESS) { + return code; + } + pOldPattern = taosStrdup(pPattern); + if (NULL == pOldPattern) { + uError("Failed to Malloc when compile regex pattern %s.", pPattern); + return terrno; + } + ppUsingRegex = ppRegex; + pRegex = &((*ppUsingRegex)->pRegex); + *regex = &(*ppRegex)->pRegex; + return 0; +} + static int32_t doExecRegexMatch(const char *pString, const char *pPattern) { int32_t ret = 0; char msgbuf[256] = {0}; - UsingRegex **pUsingRegex = getRegComp(pPattern); - if (pUsingRegex == NULL) { - return 1; + + regex_t *regex = NULL; + ret = threadGetRegComp(®ex, pPattern); + if (ret != 0) { + return ret; } regmatch_t pmatch[1]; - ret = regexec(&(*pUsingRegex)->pRegex, pString, 1, pmatch, 0); - releaseRegComp(pUsingRegex); + ret = regexec(regex, pString, 1, pmatch, 0); if (ret != 0 && ret != REG_NOMATCH) { terrno = TSDB_CODE_PAR_REGULAR_EXPRESSION_ERROR; - (void)regerror(ret, &(*pUsingRegex)->pRegex, msgbuf, sizeof(msgbuf)); + (void)regerror(ret, regex, msgbuf, sizeof(msgbuf)); uDebug("Failed to match %s with pattern %s, reason %s", pString, pPattern, msgbuf) } @@ -1365,8 +1420,7 @@ int32_t comparestrRegexMatch(const void *pLeft, const void *pRight) { size_t sz = varDataLen(pRight); char *pattern = taosMemoryMalloc(sz + 1); if (NULL == pattern) { - terrno = TSDB_CODE_OUT_OF_MEMORY; - return 1; + return 1; // terrno has been set } (void)memcpy(pattern, varDataVal(pRight), varDataLen(pRight)); @@ -1376,8 +1430,7 @@ int32_t comparestrRegexMatch(const void *pLeft, const void *pRight) { char *str = taosMemoryMalloc(sz + 1); if (NULL == str) { taosMemoryFree(pattern); - terrno = TSDB_CODE_OUT_OF_MEMORY; - return 1; + return 1; // terrno has been set } (void)memcpy(str, varDataVal(pLeft), sz); @@ -1395,14 +1448,13 @@ int32_t comparewcsRegexMatch(const void *pString, const void *pPattern) { size_t len = varDataLen(pPattern); char *pattern = taosMemoryMalloc(len + 1); if (NULL == pattern) { - terrno = TSDB_CODE_OUT_OF_MEMORY; - return 1; + return 1; // terrno has been set } int convertLen = taosUcs4ToMbs((TdUcs4 *)varDataVal(pPattern), len, pattern); if (convertLen < 0) { taosMemoryFree(pattern); - return (terrno = TSDB_CODE_APP_ERROR); + return 1; // terrno has been set } pattern[convertLen] = 0; @@ -1411,15 +1463,14 @@ int32_t comparewcsRegexMatch(const void *pString, const void *pPattern) { char *str = taosMemoryMalloc(len + 1); if (NULL == str) { taosMemoryFree(pattern); - terrno = TSDB_CODE_OUT_OF_MEMORY; - return 1; + return 1; // terrno has been set } convertLen = taosUcs4ToMbs((TdUcs4 *)varDataVal(pString), len, str); if (convertLen < 0) { taosMemoryFree(str); taosMemoryFree(pattern); - return (terrno = TSDB_CODE_APP_ERROR); + return 1; // terrno has been set } str[convertLen] = 0; diff --git a/source/util/src/tlog.c b/source/util/src/tlog.c index 1946a0a274..86dc767adc 100644 --- a/source/util/src/tlog.c +++ b/source/util/src/tlog.c @@ -567,7 +567,7 @@ static inline void taosPrintLogImp(ELogLevel level, int32_t dflag, const char *b } } -void taosPrintLog(const char *flags, ELogLevel level, int32_t dflag, const char *format, ...) { +void taosPrintLog(const char *flags, int32_t level, int32_t dflag, const char *format, ...) { if (!(dflag & DEBUG_FILE) && !(dflag & DEBUG_SCREEN)) return; char buffer[LOG_MAX_LINE_BUFFER_SIZE]; @@ -590,7 +590,7 @@ void taosPrintLog(const char *flags, ELogLevel level, int32_t dflag, const char } } -void taosPrintLongString(const char *flags, ELogLevel level, int32_t dflag, const char *format, ...) { +void taosPrintLongString(const char *flags, int32_t level, int32_t dflag, const char *format, ...) { if (!osLogSpaceAvailable()) return; if (!(dflag & DEBUG_FILE) && !(dflag & DEBUG_SCREEN)) return; diff --git a/source/util/src/tworker.c b/source/util/src/tworker.c index 258d53c335..edf5b0b970 100644 --- a/source/util/src/tworker.c +++ b/source/util/src/tworker.c @@ -106,6 +106,7 @@ static void *tQWorkerThreadFp(SQueueWorker *worker) { } destroyThreadLocalGeosCtx(); + DestoryThreadLocalRegComp(); return NULL; } @@ -237,6 +238,7 @@ static void *tAutoQWorkerThreadFp(SQueueWorker *worker) { taosUpdateItemSize(qinfo.queue, 1); } + DestoryThreadLocalRegComp(); return NULL; } @@ -664,6 +666,7 @@ static void *tQueryAutoQWorkerThreadFp(SQueryAutoQWorker *worker) { } destroyThreadLocalGeosCtx(); + DestoryThreadLocalRegComp(); return NULL; } diff --git a/source/util/test/CMakeLists.txt b/source/util/test/CMakeLists.txt index e8aabfe338..0d8774ba41 100644 --- a/source/util/test/CMakeLists.txt +++ b/source/util/test/CMakeLists.txt @@ -119,6 +119,13 @@ add_test( COMMAND bufferTest ) +add_executable(regexTest "regexTest.cpp") +target_link_libraries(regexTest os util gtest_main ) +add_test( + NAME regexTest + COMMAND regexTest +) + #add_executable(decompressTest "decompressTest.cpp") #target_link_libraries(decompressTest os util common gtest_main) #add_test( diff --git a/source/util/test/regexTest.cpp b/source/util/test/regexTest.cpp new file mode 100644 index 0000000000..5fe3701700 --- /dev/null +++ b/source/util/test/regexTest.cpp @@ -0,0 +1,344 @@ + +#include +#include +#include +#include +#include +#include "os.h" +#include "tutil.h" +#include "regex.h" +#include "osDef.h" +#include "tcompare.h" + +extern "C" { + typedef struct UsingRegex UsingRegex; + typedef struct HashRegexPtr HashRegexPtr; + int32_t getRegComp(const char *pPattern, HashRegexPtr **regexRet); + int32_t threadGetRegComp(regex_t **regex, const char *pPattern); +} + +class regexTest { + public: + regexTest() { (void)InitRegexCache(); } + ~regexTest() { (void)DestroyRegexCache(); } +}; +static regexTest test; + +static threadlocal regex_t pRegex; +static threadlocal char *pOldPattern = NULL; + +void DestoryThreadLocalRegComp1() { + if (NULL != pOldPattern) { + regfree(&pRegex); + taosMemoryFree(pOldPattern); + pOldPattern = NULL; + } +} + +static regex_t *threadGetRegComp1(const char *pPattern) { + if (NULL != pOldPattern) { + if( strcmp(pOldPattern, pPattern) == 0) { + return &pRegex; + } else { + DestoryThreadLocalRegComp1(); + } + } + pOldPattern = (char*)taosMemoryMalloc(strlen(pPattern) + 1); + if (NULL == pOldPattern) { + uError("Failed to Malloc when compile regex pattern %s.", pPattern); + return NULL; + } + strcpy(pOldPattern, pPattern); + int32_t cflags = REG_EXTENDED; + int32_t ret = regcomp(&pRegex, pPattern, cflags); + if (ret != 0) { + char msgbuf[256] = {0}; + regerror(ret, &pRegex, msgbuf, tListLen(msgbuf)); + uError("Failed to compile regex pattern %s. reason %s", pPattern, msgbuf); + DestoryThreadLocalRegComp1(); + return NULL; + } + return &pRegex; +} + +TEST(testCase, regexCacheTest1) { + int times = 100000; + char s1[] = "abc"; + auto start = std::chrono::high_resolution_clock::now(); + + uint64_t t0 = taosGetTimestampUs(); + for (int i = 0; i < times; i++) { + HashRegexPtr* ret = NULL; + int32_t code = getRegComp(s1, &ret); + if (code != 0) { + FAIL() << "Failed to compile regex pattern " << s1; + } + } + uint64_t t1 = taosGetTimestampUs(); + + printf("%s regex(current) %d times:%" PRIu64 " us.\n", s1, times, t1 - t0); + + uint64_t t2 = taosGetTimestampUs(); + for(int i = 0; i < times; i++) { + regex_t* rex = threadGetRegComp1(s1); + } + uint64_t t3 = taosGetTimestampUs(); + + printf("%s regex(before) %d times:%" PRIu64 " us.\n", s1, times, t3 - t2); + + t2 = taosGetTimestampUs(); + for(int i = 0; i < times; i++) { + regex_t* rex = NULL; + (void)threadGetRegComp(&rex, s1); + } + t3 = taosGetTimestampUs(); + + printf("%s regex(new) %d times:%" PRIu64 " us.\n", s1, times, t3 - t2); +} + +TEST(testCase, regexCacheTest2) { + int times = 100000; + char s1[] = "abc%*"; + auto start = std::chrono::high_resolution_clock::now(); + + uint64_t t0 = taosGetTimestampUs(); + for (int i = 0; i < times; i++) { + HashRegexPtr* ret = NULL; + int32_t code = getRegComp(s1, &ret); + if (code != 0) { + FAIL() << "Failed to compile regex pattern " << s1; + } + } + uint64_t t1 = taosGetTimestampUs(); + + printf("%s regex(current) %d times:%" PRIu64 " us.\n", s1, times, t1 - t0); + + uint64_t t2 = taosGetTimestampUs(); + for(int i = 0; i < times; i++) { + regex_t* rex = threadGetRegComp1(s1); + } + uint64_t t3 = taosGetTimestampUs(); + + printf("%s regex(before) %d times:%" PRIu64 " us.\n", s1, times, t3 - t2); + + t2 = taosGetTimestampUs(); + for(int i = 0; i < times; i++) { + regex_t* rex = NULL; + (void)threadGetRegComp(&rex, s1); + } + t3 = taosGetTimestampUs(); + + printf("%s regex(new) %d times:%" PRIu64 " us.\n", s1, times, t3 - t2); +} + +TEST(testCase, regexCacheTest3) { + int times = 100000; + char s1[] = "abc%*"; + char s2[] = "abc"; + auto start = std::chrono::high_resolution_clock::now(); + + uint64_t t0 = taosGetTimestampUs(); + for (int i = 0; i < times; i++) { + HashRegexPtr* ret = NULL; + int32_t code = getRegComp(s1, &ret); + if (code != 0) { + FAIL() << "Failed to compile regex pattern " << s1; + } + } + uint64_t t1 = taosGetTimestampUs(); + + printf("'%s' and '%s' take place by turn regex(current) %d times:%" PRIu64 " us.\n", s1, s2, times, t1 - t0); + + uint64_t t2 = taosGetTimestampUs(); + for(int i = 0; i < times; i++) { + regex_t* rex = threadGetRegComp1(s1); + rex = threadGetRegComp1(s2); + } + uint64_t t3 = taosGetTimestampUs(); + + printf("'%s' and '%s' take place by turn regex(before) %d times:%" PRIu64 " us.\n", s1, s2, times, t3 - t2); + + t2 = taosGetTimestampUs(); + for(int i = 0; i < times; i++) { + regex_t* rex = NULL; + (void)threadGetRegComp(&rex, s1); + (void)threadGetRegComp(&rex, s2); + } + t3 = taosGetTimestampUs(); + + printf("'%s' and '%s' take place by turn regex(new) %d times:%" PRIu64 " us.\n", s1, s2, times, t3 - t2); +} + +TEST(testCase, regexCacheTest4) { + int times = 100; + int count = 1000; + char s1[] = "abc%*"; + char s2[] = "abc"; + auto start = std::chrono::high_resolution_clock::now(); + + uint64_t t0 = taosGetTimestampUs(); + for (int i = 0; i < times; i++) { + for (int j = 0; j < count; ++j) { + HashRegexPtr* ret = NULL; + int32_t code = getRegComp(s1, &ret); + if (code != 0) { + FAIL() << "Failed to compile regex pattern " << s1; + } + } + for (int j = 0; j < count; ++j) { + HashRegexPtr* ret = NULL; + int32_t code = getRegComp(s2, &ret); + if (code != 0) { + FAIL() << "Failed to compile regex pattern " << s2; + } + } + } + uint64_t t1 = taosGetTimestampUs(); + + printf("'%s' and '%s' take place by turn(per %d count) regex(current) %d times:%" PRIu64 " us.\n", s1, s2, count, times, t1 - t0); + + uint64_t t2 = taosGetTimestampUs(); + for (int i = 0; i < times; i++) { + for (int j = 0; j < count; ++j) { + regex_t* rex = threadGetRegComp1(s1); + } + for (int j = 0; j < count; ++j) { + regex_t* rex = threadGetRegComp1(s2); + } + } + uint64_t t3 = taosGetTimestampUs(); + + printf("'%s' and '%s' take place by turn(per %d count) regex(before) %d times:%" PRIu64 " us.\n", s1, s2, count, times, t3 - t2); + + t2 = taosGetTimestampUs(); + for (int i = 0; i < times; i++) { + for (int j = 0; j < count; ++j) { + regex_t* rex = NULL; + (void)threadGetRegComp(&rex, s1); + } + for (int j = 0; j < count; ++j) { + regex_t* rex = NULL; + (void)threadGetRegComp(&rex, s2); + } + } + t3 = taosGetTimestampUs(); + + printf("'%s' and '%s' take place by turn(per %d count) regex(new) %d times:%" PRIu64 " us.\n", s1, s2, count, times, t3 - t2); +} + +// It is not a good idea to test this case, because it will take a long time. +/* +TEST(testCase, regexCacheTest5) { + int times = 10000; + int count = 10000; + char s1[] = "abc%*"; + char s2[] = "abc"; + auto start = std::chrono::high_resolution_clock::now(); + + uint64_t t0 = taosGetTimestampUs(); + for (int i = 0; i < times; i++) { + for (int j = 0; j < count; ++j) { + HashRegexPtr* ret = NULL; + int32_t code = getRegComp(s1, &ret); + if (code != 0) { + FAIL() << "Failed to compile regex pattern " << s1; + } + } + for (int j = 0; j < count; ++j) { + HashRegexPtr* ret = NULL; + int32_t code = getRegComp(s2, &ret); + if (code != 0) { + FAIL() << "Failed to compile regex pattern " << s2; + } + } + } + uint64_t t1 = taosGetTimestampUs(); + + printf("'%s' and '%s' take place by turn(per %d count) regex(current) %d times:%" PRIu64 " us.\n", s1, s2, count, times, t1 - t0); + + uint64_t t2 = taosGetTimestampUs(); + for (int i = 0; i < times; i++) { + for (int j = 0; j < count; ++j) { + regex_t* rex = threadGetRegComp1(s1); + } + for (int j = 0; j < count; ++j) { + regex_t* rex = threadGetRegComp1(s2); + } + } + uint64_t t3 = taosGetTimestampUs(); + + printf("'%s' and '%s' take place by turn(per %d count) regex(before) %d times:%" PRIu64 " us.\n", s1, s2, count, times, t3 - t2); + + t2 = taosGetTimestampUs(); + for (int i = 0; i < times; i++) { + for (int j = 0; j < count; ++j) { + regex_t* rex = NULL; + (void)threadGetRegComp(&rex, s1); + } + for (int j = 0; j < count; ++j) { + regex_t* rex = NULL; + (void)threadGetRegComp(&rex, s2); + } + } + t3 = taosGetTimestampUs(); + + printf("'%s' and '%s' take place by turn(per %d count) regex(new) %d times:%" PRIu64 " us.\n", s1, s2, count, times, t3 - t2); +} + +TEST(testCase, regexCacheTest6) { + int times = 10000; + int count = 1000; + char s1[] = "abc%*"; + char s2[] = "abc"; + auto start = std::chrono::high_resolution_clock::now(); + + uint64_t t0 = taosGetTimestampUs(); + for (int i = 0; i < times; i++) { + for (int j = 0; j < count; ++j) { + HashRegexPtr* ret = NULL; + int32_t code = getRegComp(s1, &ret); + if (code != 0) { + FAIL() << "Failed to compile regex pattern " << s1; + } + } + for (int j = 0; j < count; ++j) { + HashRegexPtr* ret = NULL; + int32_t code = getRegComp(s2, &ret); + if (code != 0) { + FAIL() << "Failed to compile regex pattern " << s2; + } + } + } + uint64_t t1 = taosGetTimestampUs(); + + printf("'%s' and '%s' take place by turn(per %d count) regex(current) %d times:%" PRIu64 " us.\n", s1, s2, count, times, t1 - t0); + + uint64_t t2 = taosGetTimestampUs(); + for (int i = 0; i < times; i++) { + for (int j = 0; j < count; ++j) { + regex_t* rex = threadGetRegComp1(s1); + } + for (int j = 0; j < count; ++j) { + regex_t* rex = threadGetRegComp1(s2); + } + } + uint64_t t3 = taosGetTimestampUs(); + + printf("'%s' and '%s' take place by turn(per %d count) regex(before) %d times:%" PRIu64 " us.\n", s1, s2, count, times, t3 - t2); + + t2 = taosGetTimestampUs(); + for (int i = 0; i < times; i++) { + for (int j = 0; j < count; ++j) { + regex_t* rex = NULL; + (void)threadGetRegComp(&rex, s1); + } + for (int j = 0; j < count; ++j) { + regex_t* rex = NULL; + (void)threadGetRegComp(&rex, s2); + } + } + t3 = taosGetTimestampUs(); + + printf("'%s' and '%s' take place by turn(per %d count) regex(new) %d times:%" PRIu64 " us.\n", s1, s2, count, times, t3 - t2); +} +*/ diff --git a/tests/script/sh/bit_and.c b/tests/script/sh/bit_and.c index f3bf71ce94..2cf2157e1c 100644 --- a/tests/script/sh/bit_and.c +++ b/tests/script/sh/bit_and.c @@ -8,13 +8,17 @@ DLL_EXPORT int32_t bit_and_init() { return 0; } DLL_EXPORT int32_t bit_and_destroy() { return 0; } DLL_EXPORT int32_t bit_and(SUdfDataBlock* block, SUdfColumn* resultCol) { + udfTrace("block:%p, processing begins, rows:%d cols:%d", block, block->numOfRows, block->numOfCols); + if (block->numOfCols < 2) { + udfError("block:%p, cols:%d needs to be greater than 2", block, block->numOfCols); return TSDB_CODE_UDF_INVALID_INPUT; } for (int32_t i = 0; i < block->numOfCols; ++i) { SUdfColumn* col = block->udfCols[i]; - if (!(col->colMeta.type == TSDB_DATA_TYPE_INT)) { + if (col->colMeta.type != TSDB_DATA_TYPE_INT) { + udfError("block:%p, col:%d type:%d should be int(%d)", block, i, col->colMeta.type, TSDB_DATA_TYPE_INT); return TSDB_CODE_UDF_INVALID_INPUT; } } @@ -23,25 +27,35 @@ DLL_EXPORT int32_t bit_and(SUdfDataBlock* block, SUdfColumn* resultCol) { for (int32_t i = 0; i < block->numOfRows; ++i) { if (udfColDataIsNull(block->udfCols[0], i)) { + udfTrace("block:%p, row:%d result is null since col:0 is null", block, i); udfColDataSetNull(resultCol, i); continue; } + int32_t result = *(int32_t*)udfColDataGetData(block->udfCols[0], i); - int j = 1; + udfTrace("block:%p, row:%d col:0 data:%d", block, i, result); + + int32_t j = 1; for (; j < block->numOfCols; ++j) { if (udfColDataIsNull(block->udfCols[j], i)) { + udfTrace("block:%p, row:%d result is null since col:%d is null", block, i, j); udfColDataSetNull(resultCol, i); break; } char* colData = udfColDataGetData(block->udfCols[j], i); result &= *(int32_t*)colData; + udfTrace("block:%p, row:%d col:%d data:%d", block, i, j, *(int32_t*)colData); } + if (j == block->numOfCols) { udfColDataSet(resultCol, i, (char*)&result, false); + udfTrace("block:%p, row:%d result is %d", block, i, result); } } + resultData->numOfRows = block->numOfRows; + udfTrace("block:%p, processing completed, rows:%d, cols:%d,", block, block->numOfRows, block->numOfCols); return TSDB_CODE_SUCCESS; } diff --git a/tests/system-test/7-tmq/tmqParamsTest.py b/tests/system-test/7-tmq/tmqParamsTest.py index a323dff19e..c14c3fc7d1 100644 --- a/tests/system-test/7-tmq/tmqParamsTest.py +++ b/tests/system-test/7-tmq/tmqParamsTest.py @@ -104,7 +104,7 @@ class TDTestCase: stop_flag = 0 try: while True: - res = consumer.poll(1) + res = consumer.poll(3) tdSql.query('show consumers;') consumer_info = tdSql.queryResult[0][-1] if offset_value == "latest":