Merge branch '3.0' into fix/3_liaohj
This commit is contained in:
commit
82d431d73e
|
@ -4,9 +4,9 @@ sidebar_label: 文档首页
|
|||
slug: /
|
||||
---
|
||||
|
||||
TDengine 是一款[开源](https://www.taosdata.com/tdengine/open_source_time-series_database)、[高性能](https://www.taosdata.com/fast)、[云原生](https://www.taosdata.com/tdengine/cloud_native_time-series_database)的<a href="https://www.taosdata.com/" data-internallinksmanager029f6b8e52c="2" title="时序数据库" target="_blank" rel="noopener">时序数据库</a>(<a href="https://www.taosdata.com/time-series-database" data-internallinksmanager029f6b8e52c="9" title="Time Series DataBase" target="_blank" rel="noopener">Time Series Database</a>, <a href="https://www.taosdata.com/tsdb" data-internallinksmanager029f6b8e52c="8" title="TSDB" target="_blank" rel="noopener">TSDB</a>), 它专为物联网、车联网、工业互联网、金融、IT 运维等场景优化设计。同时它还带有内建的缓存、流式计算、数据订阅等系统功能,能大幅减少系统设计的复杂度,降低研发和运营成本,是一款极简的时序数据处理平台。本文档是 TDengine 的用户手册,主要是介绍 TDengine 的基本概念、安装、使用、功能、开发接口、运营维护、TDengine 内核设计等等,它主要是面向架构师、开发工程师与系统管理员的。
|
||||
TDengine 是一款[开源](https://www.taosdata.com/tdengine/open_source_time-series_database)、[高性能](https://www.taosdata.com/fast)、[云原生](https://www.taosdata.com/tdengine/cloud_native_time-series_database)的<a href="https://www.taosdata.com/" data-internallinksmanager029f6b8e52c="2" title="时序数据库" target="_blank" rel="noopener">时序数据库</a>(<a href="https://www.taosdata.com/time-series-database" data-internallinksmanager029f6b8e52c="9" title="Time Series DataBase" target="_blank" rel="noopener">Time Series Database</a>, <a href="https://www.taosdata.com/tsdb" data-internallinksmanager029f6b8e52c="8" title="TSDB" target="_blank" rel="noopener">TSDB</a>), 它专为物联网、车联网、工业互联网、金融、IT 运维等场景优化设计。同时它还带有内建的缓存、流式计算、数据订阅等系统功能,能大幅减少系统设计的复杂度,降低研发和运营成本,是一款极简的时序数据处理平台。本文档是 TDengine 的用户手册,主要是介绍 TDengine 的基本概念、安装、使用、功能、开发接口、运营维护、TDengine 内核设计等等,它主要是面向架构师、开发工程师与系统管理员的。如果你对时序数据的基本概念、价值以及其所能带来的业务价值尚不了解,请参考[时序数据基础](./concept)
|
||||
|
||||
TDengine 充分利用了时序数据的特点,提出了“一个数据采集点一张表”与“超级表”的概念,设计了创新的存储引擎,让数据的写入、查询和存储效率都得到极大的提升。为正确理解并使用 TDengine,无论如何,请您仔细阅读[基本概念](./concept)一章。
|
||||
TDengine 充分利用了时序数据的特点,提出了“一个数据采集点一张表”与“超级表”的概念,设计了创新的存储引擎,让数据的写入、查询和存储效率都得到极大的提升。为正确理解并使用 TDengine,无论如何,请您仔细阅读[快速入门](./basic)一章。
|
||||
|
||||
如果你是开发工程师,请一定仔细阅读[开发指南](./develop)一章,该部分对数据库连接、建模、插入数据、查询、流式计算、缓存、数据订阅、用户自定义函数等功能都做了详细介绍,并配有各种编程语言的示例代码。大部分情况下,你只要复制粘贴示例代码,针对自己的应用稍作改动,就能跑起来。
|
||||
|
||||
|
|
|
@ -40,7 +40,7 @@ TDengine 经过特别优化,以适应时间序列数据的独特需求,引
|
|||
|
||||
9. 编程连接器:TDengine 提供不同语言的连接器,包括 C/C++、Java、Go、Node.js、Rust、Python、C#、R、PHP 等。而且 TDengine 支持 REST 接口,应用可以直接通过 HTTP POST 请求 BODY 中包含的 SQL 语句来操作数据库。
|
||||
|
||||
10. 数据安全共享:TDengine 通过数据库视图功能和权限管理,确保数据访问的安全性。结合数据订阅功能实现灵活精细的数据分发控制,保护数据安全和隐私
|
||||
10. 数据安全:TDengine 提供了丰富的用户管理和权限管理功能以控制不同用户对数据库和表的访问权限,提供了 IP 白名单功能以控制不同帐号只能从特定的服务器接入集群。TDengine 支持系统管理员对不同数据库按需加密,数据加密后对读写完全透明且对性能的影响很小。还提供了审计日志功能以记录系统中的敏感操作。
|
||||
|
||||
11. 编程连接器:TDengine 提供了丰富的编程语言连接器,包括 C/C++、Java、Go、Node.js、Rust、Python、C#、R、PHP 等,并支持 REST ful 接口,方便应用通过HTTP POST 请求操作数据库。
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
title: 快速入门
|
||||
toc_max_heading_level: 4
|
||||
description: 'TDengine 基本功能'
|
||||
---
|
||||
|
||||
本章主要介绍 TDengine 的数据模型以及基本的写入和查询功能。
|
||||
本章主要介绍 TDengine 的数据模型以及写入和查询功能。
|
||||
|
||||
```mdx-code-block
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
---
|
||||
title: TDengine 高级功能
|
||||
toc_max_heading_level: 4
|
||||
title: 高级功能
|
||||
description: 'TDengine 高级功能'
|
||||
---
|
||||
|
||||
TDengine 不仅是一个高性能、分布式的时序数据库核心产品,而且集成了专为时序数据量身定制的一系列功能,包括数据订阅、缓存、流计算和 ETL 等。这些功能共同构成了一个完整的时序数据处理解决方案。因此,当你选择使用 TDengine 时,你的应用程序无须额外集成 Kafka、Redis、Spark 或 Flink 等第三方工具,从而极大地简化应用程序的设计复杂度,并显著降低运维成本。下图直观地展示了传统大数据平台架构与TDengine 架构之间的异同点,突显了 TDengine 在时序数据处理领域的独特优势。
|
||||
|
||||

|
||||
|
||||
本章主要介绍 TDengine 的一些高级功能,如数据订阅、缓存、流计算、边云协同和数据接入等。
|
||||
本章主要介绍 TDengine 的高级功能,如数据订阅、缓存、流计算、边云协同和数据接入。
|
||||
|
||||
```mdx-code-block
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
|
|
|
@ -8,13 +8,15 @@ toc_max_heading_level: 4
|
|||
|
||||
## 手动部署
|
||||
|
||||
按照以下步骤手动搭建 TDengine 集群。
|
||||
### 部署 taosd
|
||||
|
||||
### 清除数据
|
||||
taosd 是 TDengine 集群中最主要的服务组件,本节介绍手动部署 taosd 集群的步骤。
|
||||
|
||||
#### 1. 清除数据
|
||||
|
||||
如果搭建集群的物理节点中存在之前的测试数据或者装过其他版本(如 1.x/2.x)的TDengine,请先将其删除,并清空所有数据。
|
||||
|
||||
### 检查环境
|
||||
#### 2. 检查环境
|
||||
|
||||
在进行 TDengine 集群部署之前,全面检查所有 dnode 以及应用程序所在物理节点的网络设置至关重要。以下是检查步骤:
|
||||
|
||||
|
@ -25,11 +27,11 @@ toc_max_heading_level: 4
|
|||
|
||||
通过以上步骤,你可以确保所有节点在网络层面顺利通信,从而为成功部署TDengine 集群奠定坚实基础
|
||||
|
||||
### 安装 TDengine
|
||||
#### 3. 安装
|
||||
|
||||
为了确保集群内各物理节点的一致性和稳定性,请在所有物理节点上安装相同版本的 TDengine。
|
||||
|
||||
### 修改配置
|
||||
#### 4. 修改配置
|
||||
|
||||
修改 TDengine 的配置文件(所有节点的配置文件都需要修改)。假设准备启动的第 1 个 dnode 的 endpoint 为 h1.taosdata.com:6030,其与集群配置相关参数如下。
|
||||
|
||||
|
@ -54,7 +56,7 @@ serverPort 6030
|
|||
|charset | 字符集编码 |
|
||||
|ttlChangeOnWrite | ttl 到期时间是否伴随表的修改操作而改变 |
|
||||
|
||||
### 启动集群
|
||||
#### 5. 启动
|
||||
|
||||
按照前述步骤启动第 1 个 dnode,例如 h1.taosdata.com。接着在终端中执行 taos,启动 TDengine 的 CLI 程序 taos,并在其中执行 show dnodes 命令,以查看当前集群中的所有 dnode 信息。
|
||||
|
||||
|
@ -67,7 +69,7 @@ taos> show dnodes;
|
|||
|
||||
可以看到,刚刚启动的 dnode 节点的 endpoint 为 h1.taosdata.com:6030。这个地址就是新建集群的 first Ep。
|
||||
|
||||
### 添加 dnode
|
||||
#### 6. 添加 dnode
|
||||
|
||||
按照前述步骤,在每个物理节点启动 taosd。每个 dnode 都需要在 taos.cfg 文件中将 firstEp 参数配置为新建集群首个节点的 endpoint,在本例中是 h1.taosdata.com:6030。在第 1 个 dnode 所在机器,在终端中运行 taos,打开 TDengine 的 CLI 程序 taos,然后登录TDengine 集群,执行如下 SQL。
|
||||
|
||||
|
@ -88,7 +90,7 @@ show dnodes;
|
|||
- 两个没有配置 firstEp 参数的 dnode 在启动后会独立运行。这时无法将其中一个dnode 加入另外一个 dnode,形成集群。
|
||||
- TDengine 不允许将两个独立的集群合并成新的集群。
|
||||
|
||||
### 添加 mnode
|
||||
#### 7. 添加 mnode
|
||||
|
||||
在创建 TDengine 集群时,首个 dnode 将自动成为集群的 mnode,负责集群的管理和协调工作。为了实现 mnode 的高可用性,后续添加的 dnode 需要手动创建 mnode。请注意,一个集群最多允许创建 3 个 mnode,且每个 dnode 上只能创建一个 mnode。当集群中的 dnode 数量达到或超过 3 个时,你可以为现有集群创建 mnode。在第 1个 dnode 中,首先通过 TDengine 的 CLI 程序 taos 登录 TDengine,然后执行如下 SQL。
|
||||
|
||||
|
@ -98,21 +100,14 @@ create mnode on dnode <dnodeId>
|
|||
|
||||
请注意将上面示例中的 dnodeId 替换为刚创建 dnode 的序号(可以通过执行 `show dnodes` 命令获得)。最后执行如下 `show mnodes`,查看新创建的 mnode 是否成功加入集群。
|
||||
|
||||
### 删除 dnode
|
||||
|
||||
对于错误加入集群的 dnode 可以通过 `drop dnode <dnodeID>` 命令删除。
|
||||
|
||||
**Tips**
|
||||
- 一旦 dnode 被删除,它将无法直接重新加入集群。如果需要重新加入此类节点,你应首先对该节点进行初始化操作,即清空其数据文件夹。
|
||||
- 在执行 drop dnode 命令时,集群会先将待删除 dnode 上的数据迁移至其他节点。请注意,drop dnode 与停止 taosd 进程是两个截然不同的操作,请勿混淆。由于删除 dnode 前须执行数据迁移,因此被删除的 dnode 必须保持在线状态,直至删除操作完成。删除操作结束后,方可停止 taosd 进程。
|
||||
- 一旦 dnode 被删除,集群中的其他节点将感知到此操作,并且不再接收该 dnodeId 的请求。dnodeId 是由集群自动分配的,用户无法手动指定。
|
||||
|
||||
### 常见问题
|
||||
|
||||
在搭建 TDengine 集群的过程中,如果在执行 create dnode 命令以添加新节点后,新节点始终显示为离线状态,请按照以下步骤进行排查。
|
||||
第 1 步,检查新节点上的 taosd 服务是否已经正常启动。你可以通过查看日志文件或使用 ps 命令来确认。
|
||||
第 2 步,如果 taosd 服务已启动,接下来请检查新节点的网络连接是否畅通,并确认防火墙是否已关闭。网络不通或防火墙设置可能会阻止节点与集群的其他节点通信。
|
||||
第 3 步,使用 taos -h fqdn 命令尝试连接到新节点,然后执行 show dnodes 命令。这将显示新节点作为独立集群的运行状态。如果显示的列表与主节点上显示的不一致,说明新节点可能已自行组成一个单节点集群。要解决这个问题,请按照以下步骤操作。首先,停止新节点上的 taosd 服务。其次,清空新节点上 taos.cfg 配置文件中指定的 dataDir 目录下的所有文件。这将删除与该节点相关的所有数据和配置信息。最后,重新启动新节点上的 taosd 服务。这将使新节点恢复到初始状态,并准备好重新加入主集群。
|
||||
|
||||
- 第 1 步,检查新节点上的 taosd 服务是否已经正常启动。你可以通过查看日志文件或使用 ps 命令来确认。
|
||||
- 第 2 步,如果 taosd 服务已启动,接下来请检查新节点的网络连接是否畅通,并确认防火墙是否已关闭。网络不通或防火墙设置可能会阻止节点与集群的其他节点通信。
|
||||
- 第 3 步,使用 taos -h fqdn 命令尝试连接到新节点,然后执行 show dnodes 命令。这将显示新节点作为独立集群的运行状态。如果显示的列表与主节点上显示的不一致,说明新节点可能已自行组成一个单节点集群。要解决这个问题,请按照以下步骤操作。首先,停止新节点上的 taosd 服务。其次,清空新节点上 taos.cfg 配置文件中指定的 dataDir 目录下的所有文件。这将删除与该节点相关的所有数据和配置信息。最后,重新启动新节点上的 taosd 服务。这将使新节点恢复到初始状态,并准备好重新加入主集群。
|
||||
|
||||
### 部署 taosAdapter
|
||||
|
||||
|
@ -205,6 +200,23 @@ http {
|
|||
}
|
||||
```
|
||||
|
||||
### 部署 taosKeeper
|
||||
|
||||
如果要想使用 TDegnine 的监控功能,taosKeeper 是一个必要的组件,关于监控请参考[TDinsight](../../reference/components/tdinsight),关于部署 taosKeeper 的细节请参考[taosKeeper参考手册](../../reference/components/taoskeeper)。
|
||||
|
||||
### 部署 taosX
|
||||
|
||||
如果想使用 TDengine 的数据接入能力,需要部署 taosX 服务,关于它的详细说明和部署请参考[taosX 参考手册](../../reference/components/taosx)。
|
||||
|
||||
### 部署 taosX-Agent
|
||||
|
||||
有些数据源如 Pi, OPC 等,因为网络条件和数据源访问的限制,taosX 无法直接访问数据源,这种情况下需要部署一个代理服务 taosX-Agent,关于它的详细说明和部署请参考[taosX-Agent 参考手册](../../reference/components/taosx-agent)。
|
||||
|
||||
### 部署 taos-Explorer
|
||||
|
||||
TDengine 提供了可视化管理 TDengine 集群的能力,要想使用图形化界面需要部署 taos-Explorer 服务,关于它的详细说明和部署请参考[taos-Explorer 参考手册](../../reference/components/explorer)
|
||||
|
||||
|
||||
## Docker 部署
|
||||
|
||||
本节将介绍如何在 Docker 容器中启动 TDengine 服务并对其进行访问。你可以在 docker run 命令行或者 docker-compose 文件中使用环境变量来控制容器中服务的行为。
|
||||
|
|
|
@ -10,7 +10,7 @@ sidebar_label: 集群维护
|
|||
|
||||
## 数据重整
|
||||
|
||||
TDengine 面向多种写入场景,而很多写入场景下,TDengine 的存储会导致数据存储的放大或数据文件的空洞等。这一方面影响数据的存储效率,另一方面也会影响查询效率。为了解决上述问题,TDengine 企业版提供了对数据的重整功能,即 DATA COMPACT 功能,将存储的数据文件重新整理,删除文件空洞和无效数据,提高数据的组织度,从而提高存储和查询的效率。
|
||||
TDengine 面向多种写入场景,而很多写入场景下,TDengine 的存储会导致数据存储的放大或数据文件的空洞等。这一方面影响数据的存储效率,另一方面也会影响查询效率。为了解决上述问题,TDengine 企业版提供了对数据的重整功能,即 DATA COMPACT 功能,将存储的数据文件重新整理,删除文件空洞和无效数据,提高数据的组织度,从而提高存储和查询的效率。数据重整功能在 3.0.3.0 版本第一次发布,此后又经过了多次迭代优化,建议使用最新版本。
|
||||
|
||||
### 语法
|
||||
|
||||
|
@ -39,7 +39,7 @@ KILL COMPACT compact_id;
|
|||
|
||||
## Vgroup Leader 再平衡
|
||||
|
||||
当多副本集群中的一个或多个节点因为升级或其它原因而重启后,有可能出现集群中各个 dnode 负载不均衡的现象,极端情况下会出现所有 vgroup 的 leader 都位于同一个 dnode 的情况。为了解决这个问题,可以使用下面的命令
|
||||
当多副本集群中的一个或多个节点因为升级或其它原因而重启后,有可能出现集群中各个 dnode 负载不均衡的现象,极端情况下会出现所有 vgroup 的 leader 都位于同一个 dnode 的情况。为了解决这个问题,可以使用下面的命令,该命令在 3.0.4.0 版本中首次发布,建议尽可能使用最新版本。
|
||||
|
||||
```SQL
|
||||
balance vgroup leader; # 再平衡所有 vgroup 的 leader
|
||||
|
@ -73,7 +73,7 @@ restore qnode on dnode <dnode_id>;# 恢复dnode上的qnode
|
|||
|
||||
## 分裂虚拟组
|
||||
|
||||
当一个 vgroup 因为子表数过多而导致 CPU 或 Disk 资源使用量负载过高时,增加 dnode 节点后,可通过split vgroup命令把该vgroup分裂为两个虚拟组。分裂完成后,新产生的两个 vgroup 承担原来由一个 vgroup 提供的读写服务。
|
||||
当一个 vgroup 因为子表数过多而导致 CPU 或 Disk 资源使用量负载过高时,增加 dnode 节点后,可通过split vgroup命令把该vgroup分裂为两个虚拟组。分裂完成后,新产生的两个 vgroup 承担原来由一个 vgroup 提供的读写服务。该命令在 3.0.6.0 版本第一次发布,建议尽可能使用最新版本。
|
||||
|
||||
```sql
|
||||
split vgroup <vgroup_id>
|
||||
|
@ -97,7 +97,7 @@ split vgroup <vgroup_id>
|
|||
|
||||
## 双副本
|
||||
|
||||
双副本是一种特殊的数据库高可用配置,本节对它的使用和维护操作进行特别说明。
|
||||
双副本是一种特殊的数据库高可用配置,本节对它的使用和维护操作进行特别说明。该功能在 3.3.0.0 版本中第一次发布,建议尽可能使用最新版本。
|
||||
|
||||
### 查看 Vgroups 的状态
|
||||
|
||||
|
|
|
@ -4,14 +4,13 @@ title: 多级存储与对象存储
|
|||
toc_max_heading_level: 4
|
||||
---
|
||||
|
||||
TDengine 特有的多级存储功能,其作用是将较近的热度较高的数据存储在高速介质上,而时间久远热度很低的数据存储在低成本介质上,达成了以下目标:
|
||||
本节介绍 TDengine Enterprise 特有的多级存储功能,其作用是将较近的热度较高的数据存储在高速介质上,而时间久远热度很低的数据存储在低成本介质上,达成了以下目标:
|
||||
- 降低存储成本 -- 将数据分级存储后,海量极冷数据存入廉价存储介质带来显著经济性
|
||||
- 提升写入性能 -- 得益于每级存储可支持多个挂载点,WAL 预写日志也支持 0 级的多挂载点并行写入,极大提升写入性能(实际场景测得支持持续写入每秒 3 亿测点以上),在机械硬盘上可获得极高磁盘 IO 吞吐(实测可达 2GB/s)
|
||||
- 方便维护 -- 配置好各级存储挂载点后,系统数据迁移等工作,无需人工干预;存储扩容更灵活、方便
|
||||
- 对 SQL 透明 -- 无论查询的数据是否跨级,一条 SQL 可返回所有数据,简单高效
|
||||
|
||||
|
||||
多级存储所涉及的各层存储介质都是本地存储设备。除了本地存储设备之外,TDengine 还支持使用对象存储(S3),将最冷的一批数据保存在最廉价的介质上,以进一步降低存储成本,并在必要时仍然可以进行查询,且数据存储在哪里也对 SQL 透明。
|
||||
多级存储所涉及的各层存储介质都是本地存储设备。除了本地存储设备之外,TDengine Enterprise 还支持使用对象存储(S3),将最冷的一批数据保存在最廉价的介质上,以进一步降低存储成本,并在必要时仍然可以进行查询,且数据存储在哪里也对 SQL 透明。支持对象存储在 3.3.0.0 版本中首次发布,建议使用最新版本。
|
||||
|
||||
## 多级存储
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ title: 用户和权限管理
|
|||
toc_max_heading_level: 4
|
||||
---
|
||||
|
||||
TDengine 默认仅配置了一个 root 用户,该用户拥有最高权限。TDengine 支持对系统资源、库、表、视图和主题的访问权限控制。root 用户可以为每个用户针对不同的资源设置不同的访问权限。本节介绍 TDengine 中的用户和权限管理。
|
||||
TDengine 默认仅配置了一个 root 用户,该用户拥有最高权限。TDengine 支持对系统资源、库、表、视图和主题的访问权限控制。root 用户可以为每个用户针对不同的资源设置不同的访问权限。本节介绍 TDengine 中的用户和权限管理。用户和权限管理是 TDengine Enterprise 特有功能。
|
||||
|
||||
## 用户管理
|
||||
|
||||
|
|
|
@ -4,7 +4,7 @@ title: 更多安全策略
|
|||
toc_max_heading_level: 4
|
||||
---
|
||||
|
||||
除了传统的用户和权限管理之外,TDengine 还有其他的安全策略,例如 IP 白名单、审计日志、数据加密等。
|
||||
除了传统的用户和权限管理之外,TDengine 还有其他的安全策略,例如 IP 白名单、审计日志、数据加密等,这些都是 TDengine Enterprise 特有功能,其中白名单功能在 3.2.0.0 版本首次发布,审计日志在 3.1.1.0 版本中首次发布,数据库加密在 3.3.0.0 中首次发布,建议使用最新版本。
|
||||
|
||||
## IP 白名单
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@ toc_max_heading_level: 4
|
|||
|
||||
## 简介
|
||||
|
||||
1. 部分用户因为部署环境的特殊性只能部署两台服务器,同时希望实现一定的服务高可用和数据高可靠。本文主要描述基于数据复制和客户端 Failover 两项关键技术的 TDengine 双活系统的产品行为,包括双活系统的架构、配置、运维等。TDengine 双活既可以用于前面所述资源受限的环境,也可用于在两套 TDengine 集群(不限资源)之间的灾备场景。
|
||||
1. 部分用户因为部署环境的特殊性只能部署两台服务器,同时希望实现一定的服务高可用和数据高可靠。本文主要描述基于数据复制和客户端 Failover 两项关键技术的 TDengine 双活系统的产品行为,包括双活系统的架构、配置、运维等。TDengine 双活既可以用于前面所述资源受限的环境,也可用于在两套 TDengine 集群(不限资源)之间的灾备场景。双活是 TDengine Enterprise 特有功能,在 3.3.0.0 版本中第一次发布,建议使用最新版本。
|
||||
|
||||
2. 双活系统的定义是:业务系统中有且仅有两台服务器,其上分别部署一套服务,在业务层看来这两台机器和两套服务是一个完整的系统,对其中的细节业务层不需要感知。双活中的两个节点通常被称为 Master-Slave,意为”主从“或”主备“,本文档中可能会出现混用的情况。
|
||||
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
---
|
||||
title: 运维管理
|
||||
toc_max_heading_level: 4
|
||||
title: 运维指南
|
||||
description: 'TDengine 运维指南'
|
||||
---
|
||||
|
||||
本章主要介绍如何规划、建设、维护以及监控 TDengine 集群。
|
||||
本章主要介绍如何规划、部署、维护和监控 TDengine 集群。
|
||||
|
||||
```mdx-code-block
|
||||
import DocCardList from '@theme/DocCardList';
|
||||
|
|
|
@ -41,7 +41,7 @@ TDengine 提供了丰富的应用程序开发接口,为了便于用户快速
|
|||
3. 使用 Websocket 连接,用户也无需安装客户端驱动程序 taosc。
|
||||
4. 连接云服务实例,必须使用 REST 连接 或 Websocket 连接。
|
||||
|
||||
一般我们建议使用 **Websocket 连接**。
|
||||
**推荐使用 WebSocket 连接**
|
||||
|
||||
## 安装客户端驱动 taosc
|
||||
|
||||
|
|
|
@ -13,6 +13,8 @@ import TabItem from "@theme/TabItem";
|
|||
- 预编译:当使用参数绑定时,SQL 语句可以被预编译并缓存,后续使用不同的参数值执行时,可以直接使用预编译的版本,提高执行效率。
|
||||
- 减少网络开销:参数绑定还可以减少发送到数据库的数据量,因为只需要发送参数值而不是完整的 SQL 语句,特别是在执行大量相似的插入或更新操作时,这种差异尤为明显。
|
||||
|
||||
**Tips: 数据写入推荐使用参数绑定方式**
|
||||
|
||||
下面我们继续以智能电表为例,展示各语言连接器使用参数绑定高效写入的功能:
|
||||
1. 准备一个参数化的 SQL 插入语句,用于向超级表 `meters` 中插入数据。这个语句允许动态地指定子表名、标签和列值。
|
||||
2. 循环生成多个子表及其对应的数据行。对于每个子表:
|
||||
|
|
|
@ -3,7 +3,7 @@ title: taosX 参考手册
|
|||
sidebar_label: taosX
|
||||
---
|
||||
|
||||
taosX 是 TDengine 中的一个核心组件,提供零代码数据接入的能力,taosX 支持两种运行模式:服务模式和命令行模式。本节讲述如何以这两种方式使用 taosX。要想使用 taosX 需要先安装 TDengine Enterprise 安装包。
|
||||
taosX 是 TDengine Enterprise 中的一个核心组件,提供零代码数据接入的能力,taosX 支持两种运行模式:服务模式和命令行模式。本节讲述如何以这两种方式使用 taosX。要想使用 taosX 需要先安装 TDengine Enterprise 安装包。
|
||||
|
||||
## 命令行模式
|
||||
|
||||
|
|
|
@ -3,7 +3,7 @@ title: taosX-Agent 参考手册
|
|||
sidebar_label: taosX-Agent
|
||||
---
|
||||
|
||||
本节讲述如何部署 `Agent` (for `taosX`)。使用之前需要安装 TDengine Enterprise 安装包之后。
|
||||
本节讲述如何部署 `Agent` (for `taosX`)。使用之前需要安装 TDengine Enterprise 安装包之后,taosX-Agent 用于在部分数据接入场景,如 Pi, OPC UA, OPC DA 等对访问数据源有一定限制或者网络环境特殊的场景下,可以将 taosX-Agent 部署在靠近数据源的环境中甚至与数据源在相同的服务器上,由 taosX-Agent 负责从数据源读取数据并发送给 taosX。
|
||||
|
||||
## 配置
|
||||
|
||||
|
|
|
@ -14,17 +14,102 @@ taosKeeper 是 TDengine 3.0 版本监控指标的导出工具,通过简单的
|
|||
## 安装
|
||||
|
||||
taosKeeper 有两种安装方式:
|
||||
taosKeeper 安装方式:
|
||||
|
||||
- 安装 TDengine 官方安装包的同时会自动安装 taosKeeper, 详情请参考[ TDengine 安装](../../../get-started/)。
|
||||
|
||||
- 单独编译 taosKeeper 并安装,详情请参考 [taosKeeper](https://github.com/taosdata/taoskeeper) 仓库。
|
||||
|
||||
## 配置和运行方式
|
||||
## 配置
|
||||
|
||||
### 配置
|
||||
taosKeeper 需要在操作系统终端执行,该工具支持三种配置方式:命令行参数、环境变量 和 配置文件。优先级为:命令行参数、环境变量、配置文件参数。 一般我们推荐使用配置文件。
|
||||
|
||||
taosKeeper 需要在操作系统终端执行,该工具支持三种配置方式:[命令行参数](#命令行参数启动)、[环境变量](#环境变量启动) 和 [配置文件](#配置文件启动)。优先级为:命令行参数、环境变量、配置文件参数。
|
||||
### 命令行参数和环境变量
|
||||
命令行参数 和 环境变量说明可以参考命令 `taoskeeper --help` 的输出。下面是一个例子:
|
||||
```shell
|
||||
Usage of taosKeeper v3.3.2.0:
|
||||
--debug enable debug mode. Env "TAOS_KEEPER_DEBUG"
|
||||
-P, --port int http port. Env "TAOS_KEEPER_PORT" (default 6043)
|
||||
--logLevel string log level (panic fatal error warn warning info debug trace). Env "TAOS_KEEPER_LOG_LEVEL" (default "info")
|
||||
--gopoolsize int coroutine size. Env "TAOS_KEEPER_POOL_SIZE" (default 50000)
|
||||
-R, --RotationInterval string interval for refresh metrics, such as "300ms", Valid time units are "ns", "us" (or "µs"), "ms", "s", "m", "h". Env "TAOS_KEEPER_ROTATION_INTERVAL" (default "15s")
|
||||
--tdengine.host string TDengine server's ip. Env "TAOS_KEEPER_TDENGINE_HOST" (default "127.0.0.1")
|
||||
--tdengine.port int TDengine REST server(taosAdapter)'s port. Env "TAOS_KEEPER_TDENGINE_PORT" (default 6041)
|
||||
--tdengine.username string TDengine server's username. Env "TAOS_KEEPER_TDENGINE_USERNAME" (default "root")
|
||||
--tdengine.password string TDengine server's password. Env "TAOS_KEEPER_TDENGINE_PASSWORD" (default "taosdata")
|
||||
--tdengine.usessl TDengine server use ssl or not. Env "TAOS_KEEPER_TDENGINE_USESSL"
|
||||
--metrics.prefix string prefix in metrics names. Env "TAOS_KEEPER_METRICS_PREFIX"
|
||||
--metrics.database.name string database for storing metrics data. Env "TAOS_KEEPER_METRICS_DATABASE" (default "log")
|
||||
--metrics.tables stringArray export some tables that are not super table, multiple values split with white space. Env "TAOS_KEEPER_METRICS_TABLES"
|
||||
--environment.incgroup whether running in cgroup. Env "TAOS_KEEPER_ENVIRONMENT_INCGROUP"
|
||||
--log.path string log path. Env "TAOS_KEEPER_LOG_PATH" (default "/var/log/taos")
|
||||
--log.rotationCount uint log rotation count. Env "TAOS_KEEPER_LOG_ROTATION_COUNT" (default 5)
|
||||
--log.rotationTime duration log rotation time. Env "TAOS_KEEPER_LOG_ROTATION_TIME" (default 24h0m0s)
|
||||
--log.rotationSize string log rotation size(KB MB GB), must be a positive integer. Env "TAOS_KEEPER_LOG_ROTATION_SIZE" (default "100000000")
|
||||
-c, --config string config path default /etc/taos/taoskeeper.toml
|
||||
-V, --version Print the version and exit
|
||||
-h, --help Print this help message and exit
|
||||
```
|
||||
|
||||
|
||||
|
||||
### 配置文件
|
||||
|
||||
taosKeeper 支持用 `taoskeeper -c <keeper config file>` 命令来指定配置文件。
|
||||
若不指定配置文件,taosKeeper 会使用默认配置文件,其路径为: `/etc/taos/taoskeeper.toml` 。
|
||||
若既不指定 taosKeeper 配置文件,且 `/etc/taos/taoskeeper.toml` 也不存在,将使用默认配置。
|
||||
|
||||
**下面是配置文件的示例:**
|
||||
```toml
|
||||
# Start with debug middleware for gin
|
||||
debug = false
|
||||
|
||||
# Listen port, default is 6043
|
||||
port = 6043
|
||||
|
||||
# log level
|
||||
loglevel = "info"
|
||||
|
||||
# go pool size
|
||||
gopoolsize = 50000
|
||||
|
||||
# interval for metrics
|
||||
RotationInterval = "15s"
|
||||
|
||||
[tdengine]
|
||||
host = "127.0.0.1"
|
||||
port = 6041
|
||||
username = "root"
|
||||
password = "taosdata"
|
||||
usessl = false
|
||||
|
||||
[metrics]
|
||||
# metrics prefix in metrics names.
|
||||
prefix = "taos"
|
||||
|
||||
# export some tables that are not super table
|
||||
tables = []
|
||||
|
||||
# database for storing metrics data
|
||||
[metrics.database]
|
||||
name = "log"
|
||||
# database options for db storing metrics data
|
||||
[metrics.database.options]
|
||||
vgroups = 1
|
||||
buffer = 64
|
||||
KEEP = 90
|
||||
cachemodel = "both"
|
||||
|
||||
[environment]
|
||||
# Whether running in cgroup.
|
||||
incgroup = false
|
||||
|
||||
[log]
|
||||
rotationCount = 5
|
||||
rotationTime = "24h"
|
||||
rotationSize = 100000000
|
||||
```
|
||||
|
||||
## 启动
|
||||
|
||||
**在运行 taosKeeper 之前要确保 TDengine 集群与 taosAdapter 已经在正确运行。** 并且 TDengine 已经开启监控服务,TDengine 配置文件 `taos.cfg` 中至少需要配置 `monitor` 和 `monitorFqdn`。
|
||||
|
||||
|
@ -36,8 +121,6 @@ monitorFqdn localhost # taoskeeper 服务的 FQDN
|
|||
TDengine 监控配置相关,具体请参考:[TDengine 监控配置](../../../operation/monitor)。
|
||||
|
||||
|
||||
### 启动
|
||||
|
||||
<Tabs>
|
||||
<TabItem label="Linux" value="linux">
|
||||
|
||||
|
@ -79,8 +162,8 @@ Active: inactive (dead)
|
|||
|
||||
- `systemctl` 命令需要 _root_ 权限来运行,如果您非 _root_ 用户,请在命令前添加 `sudo`。
|
||||
- 如果系统中不支持 `systemd`,也可以用手动运行 `/usr/local/taos/bin/taoskeeper` 方式启动 taoskeeper 服务。
|
||||
- 故障排查:
|
||||
- 如果服务异常请查看系统日志获取更多信息。
|
||||
- 故障排查:如果服务异常请查看日志获取更多信息。日志文件默认放在 `/var/log/taos` 下。
|
||||
|
||||
:::
|
||||
</TabItem>
|
||||
|
||||
|
@ -100,8 +183,7 @@ Active: inactive (dead)
|
|||
|
||||
- `launchctl` 命令管理`com.tdengine.taoskeeper`需要管理员权限,务必在前面加 `sudo` 来增强安全性。
|
||||
- `sudo launchctl list | grep taoskeeper` 指令返回的第一列是 `taoskeeper` 程序的 PID,若为 `-` 则说明 taoskeeper 服务未运行。
|
||||
- 故障排查:
|
||||
- 如果服务异常请查看系统日志获取更多信息。
|
||||
- 故障排查:如果服务异常请查看日志获取更多信息。日志文件默认放在 `/var/log/taos` 下。
|
||||
|
||||
:::
|
||||
|
||||
|
@ -109,88 +191,82 @@ Active: inactive (dead)
|
|||
</Tabs>
|
||||
|
||||
|
||||
#### 配置文件启动
|
||||
## 健康检查
|
||||
|
||||
执行以下命令即可快速体验 taosKeeper。当不指定 taosKeeper 配置文件时,优先使用 `/etc/taos/taoskeeper.toml` 配置,否则将使用默认配置。
|
||||
可以访问 taosKeeper 的 `check_health` 接口来判断服务是否存活,如果服务正常则会返回 HTTP 200 状态码:
|
||||
|
||||
```
|
||||
$ curl -i http://127.0.0.1:6043/check_health
|
||||
```
|
||||
|
||||
返回结果:
|
||||
|
||||
```
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json; charset=utf-8
|
||||
Date: Wed, 07 Aug 2024 06:19:50 GMT
|
||||
Content-Length: 21
|
||||
|
||||
{"version":"3.3.2.3"}
|
||||
```
|
||||
|
||||
|
||||
## 数据收集与监控
|
||||
|
||||
taosKeeper 作为 TDengine 监控指标的导出工具,可以将 TDengine 产生的监控数据记录在指定数据库中(默认的监控数据是 `log`),这些监控数据可以用来配置 TDengine 监控。
|
||||
|
||||
### 查看监控数据
|
||||
|
||||
可以查看 `log` 库下的超级表,每个超级表都对应一组监控指标,具体指标不再赘述。
|
||||
```shell
|
||||
taos> use log;
|
||||
Database changed.
|
||||
|
||||
taos> show stables;
|
||||
stable_name |
|
||||
=================================
|
||||
taosd_dnodes_status |
|
||||
taosd_vnodes_info |
|
||||
keeper_monitor |
|
||||
taosd_vgroups_info |
|
||||
taos_sql_req |
|
||||
taos_slow_sql |
|
||||
taosd_mnodes_info |
|
||||
taosd_cluster_info |
|
||||
taosd_sql_req |
|
||||
taosd_dnodes_info |
|
||||
adapter_requests |
|
||||
taosd_cluster_basic |
|
||||
taosd_dnodes_data_dirs |
|
||||
taosd_dnodes_log_dirs |
|
||||
Query OK, 14 row(s) in set (0.006542s)
|
||||
|
||||
```
|
||||
|
||||
可以查看一个超级表的最近一条上报记录,如:
|
||||
|
||||
``` shell
|
||||
$ taoskeeper -c <keeper config file>
|
||||
taos> select last_row(*) from taosd_dnodes_info;
|
||||
last_row(_ts) | last_row(disk_engine) | last_row(system_net_in) | last_row(vnodes_num) | last_row(system_net_out) | last_row(uptime) | last_row(has_mnode) | last_row(io_read_disk) | last_row(error_log_count) | last_row(io_read) | last_row(cpu_cores) | last_row(has_qnode) | last_row(has_snode) | last_row(disk_total) | last_row(mem_engine) | last_row(info_log_count) | last_row(cpu_engine) | last_row(io_write_disk) | last_row(debug_log_count) | last_row(disk_used) | last_row(mem_total) | last_row(io_write) | last_row(masters) | last_row(cpu_system) | last_row(trace_log_count) | last_row(mem_free) |
|
||||
======================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================
|
||||
2024-08-07 14:54:09.174 | 0.000000000000000 | 3379.093240947399863 | 37.000000000000000 | 5265.998201139278535 | 64402.000000000000000 | 1.000000000000000 | 8323.261934108399146 | 6.000000000000000 | 40547.386655118425551 | 16.000000000000000 | 0.000000000000000 | 0.000000000000000 | 5.272955781120000e+11 | 2443032.000000000000000 | 423.000000000000000 | 0.556269622200215 | 677731.836503547732718 | 356380.000000000000000 | 4.997186764800000e+10 | 65557284.000000000000000 | 714177.054532129666768 | 37.000000000000000 | 2.642280705451021 | 0.000000000000000 | 11604276.000000000000000 |
|
||||
Query OK, 1 row(s) in set (0.003168s)
|
||||
```
|
||||
|
||||
**下面是配置文件的示例:**
|
||||
```toml
|
||||
# gin 框架是否启用 debug
|
||||
debug = false
|
||||
|
||||
# 服务监听端口, 默认为 6043
|
||||
port = 6043
|
||||
### 使用 TDInsight 配置监控
|
||||
|
||||
# 日志级别,包含 panic、error、info、debug、trace等
|
||||
loglevel = "info"
|
||||
收集到监控数据以后,就可以使用 TDInsight 来配置 TDengine 的监控,具体请参考 [TDinsight 参考手册](../tdinsight/)
|
||||
|
||||
# 程序中使用协程池的大小
|
||||
gopoolsize = 50000
|
||||
|
||||
# 查询 TDengine 监控数据轮询间隔
|
||||
RotationInterval = "15s"
|
||||
## 集成 Prometheus
|
||||
|
||||
[tdengine]
|
||||
host = "127.0.0.1"
|
||||
port = 6041
|
||||
username = "root"
|
||||
password = "taosdata"
|
||||
taoskeeper 提供了 `/metrics` 接口,返回了 Prometheus 格式的监控数据,Prometheus 可以从 taoskeeper 抽取监控数据,实现通过 Prometheus 监控 TDengine 的目的。
|
||||
|
||||
[metrics]
|
||||
# 监控指标前缀
|
||||
prefix = "taos"
|
||||
|
||||
# 存放监控数据的数据库
|
||||
database = "log"
|
||||
### 导出监控指标
|
||||
|
||||
# 指定需要监控的普通表
|
||||
tables = []
|
||||
|
||||
# 监控数据的配置选项
|
||||
[metrics.databaseoptions]
|
||||
cachemodel = "none"
|
||||
|
||||
[environment]
|
||||
# 容器模式收集信息
|
||||
incgroup = false
|
||||
|
||||
[log]
|
||||
# 日志文件滚动个数
|
||||
rotationCount = 5
|
||||
# 日志文件切割时间
|
||||
rotationTime = "24h"
|
||||
# 日志文件切割大小 (字节)
|
||||
rotationSize = 100000000
|
||||
|
||||
```
|
||||
|
||||
### 获取监控指标
|
||||
|
||||
taosKeeper 作为 TDengine 监控指标的导出工具,可以将 TDengine 产生的监控数据记录在指定数据库中,并提供导出接口。
|
||||
|
||||
#### 查看监控结果集
|
||||
|
||||
```shell
|
||||
$ taos
|
||||
# 如上示例,使用 log 库作为监控日志存储位置
|
||||
> use log;
|
||||
> select * from taosd_cluster_info limit 1;
|
||||
```
|
||||
|
||||
结果示例:
|
||||
|
||||
```shell
|
||||
_ts | cluster_uptime | dbs_total | tbs_total | stbs_total | vgroups_total | vgroups_alive | vnodes_total | vnodes_alive | mnodes_total | mnodes_alive | connections_total | topics_total | streams_total | dnodes_total | dnodes_alive | grants_expire_time | grants_timeseries_used | grants_timeseries_total | cluster_id |
|
||||
===================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================================
|
||||
2024-06-04 03:03:34.341 | 0.000000000000000 | 2.000000000000000 | 1.000000000000000 | 4.000000000000000 | 4.000000000000000 | 4.000000000000000 | 4.000000000000000 | 4.000000000000000 | 1.000000000000000 | 1.000000000000000 | 2.000000000000000 | 0.000000000000000 | 0.000000000000000 | 1.000000000000000 | 1.000000000000000 | 0.000000000000000 | 3.000000000000000 | 0.000000000000000 | 554014120921134497 |
|
||||
Query OK, 1 row(s) in set (0.001652s)
|
||||
```
|
||||
|
||||
#### 导出监控指标
|
||||
下面通过 `curl` 命令展示 `/metrics` 接口返回的数据格式:
|
||||
|
||||
```shell
|
||||
$ curl http://127.0.0.1:6043/metrics
|
||||
|
@ -219,28 +295,8 @@ taos_cluster_info_first_ep{cluster_id="554014120921134497",value="tdengine:6030"
|
|||
taos_cluster_info_first_ep_dnode_id{cluster_id="554014120921134497"} 1
|
||||
```
|
||||
|
||||
### check\_health
|
||||
|
||||
```
|
||||
$ curl -i http://127.0.0.1:6043/check_health
|
||||
```
|
||||
|
||||
返回结果:
|
||||
|
||||
```
|
||||
HTTP/1.1 200 OK
|
||||
Content-Type: application/json; charset=utf-8
|
||||
Date: Mon, 03 Apr 2023 07:20:38 GMT
|
||||
Content-Length: 19
|
||||
|
||||
{"version":"1.0.0"}
|
||||
```
|
||||
|
||||
### 集成 Prometheus
|
||||
|
||||
taoskeeper 提供了 `/metrics` 接口,返回了 Prometheus 格式的监控数据,Prometheus 可以从 taoskeeper 抽取监控数据,实现通过 Prometheus 监控 TDengine 的目的。
|
||||
|
||||
#### 抽取配置
|
||||
### 抽取配置
|
||||
|
||||
Prometheus 提供了 `scrape_configs` 配置如何从 endpoint 抽取监控数据,通常只需要修改 `static_configs` 中的 targets 配置为 taoskeeper 的 endpoint 地址,更多配置信息请参考 [Prometheus 配置文档](https://prometheus.io/docs/prometheus/latest/configuration/configuration/#scrape_config)。
|
||||
|
||||
|
@ -255,7 +311,7 @@ scrape_configs:
|
|||
- targets: ["localhost:6043"]
|
||||
```
|
||||
|
||||
#### Dashboard
|
||||
### Dashboard
|
||||
|
||||
我们提供了 `TaosKeeper Prometheus Dashboard for 3.x` dashboard,提供了和 TDinsight 类似的监控 dashboard。
|
||||
|
||||
|
|
|
@ -29,7 +29,8 @@ TDengine 提供了丰富的应用程序开发接口,为了便于用户快速
|
|||
TDengine 版本更新往往会增加新的功能特性,列表中的连接器版本为连接器最佳适配版本。
|
||||
|
||||
| **TDengine 版本** | **Java** | **Python** | **Go** | **C#** | **Node.js** | **Rust** |
|
||||
| ---------------------- | --------- | ---------- | ------------ | ------------- | --------------- | -------- |
|
||||
| ---------------------- | ------------- | ------------------------------------------- | ------------ | ------------- | --------------- | -------- |
|
||||
| **3.3.0.0 及以上** | 3.3.2.0及以上 | taospy 2.7.15及以上,taos-ws-py 0.3.2及以上 | 3.5.5及以上 | 3.1.3及以上 | 3.1.0及以上 | 当前版本 |
|
||||
| **3.0.0.0 及以上** | 3.0.2以上 | 当前版本 | 3.0 分支 | 3.0.0 | 3.1.0 | 当前版本 |
|
||||
| **2.4.0.14 及以上** | 2.0.38 | 当前版本 | develop 分支 | 1.0.2 - 1.0.6 | 2.0.10 - 2.0.12 | 当前版本 |
|
||||
| **2.4.0.4 - 2.4.0.13** | 2.0.37 | 当前版本 | develop 分支 | 1.0.2 - 1.0.6 | 2.0.10 - 2.0.12 | 当前版本 |
|
||||
|
|
|
@ -511,7 +511,7 @@ static int32_t doSendCommitMsg(tmq_t* tmq, int32_t vgId, SEpSet* epSet, STqOffse
|
|||
|
||||
void* abuf = POINTER_SHIFT(buf, sizeof(SMsgHead));
|
||||
|
||||
SEncoder encoder;
|
||||
SEncoder encoder = {0};
|
||||
tEncoderInit(&encoder, abuf, len);
|
||||
if(tEncodeMqVgOffset(&encoder, &pOffset) < 0) {
|
||||
tEncoderClear(&encoder);
|
||||
|
@ -953,7 +953,7 @@ void tmqSendHbReq(void* param, void* tmrId) {
|
|||
tscError("tmqSendHbReq asyncSendMsgToServer failed");
|
||||
}
|
||||
|
||||
atomic_val_compare_exchange_8(&pollFlag, 1, 0);
|
||||
(void)atomic_val_compare_exchange_8(&pollFlag, 1, 0);
|
||||
OVER:
|
||||
tDestroySMqHbReq(&req);
|
||||
if(tmrId != NULL){
|
||||
|
@ -2394,7 +2394,7 @@ TAOS_RES* tmq_consumer_poll(tmq_t* tmq, int64_t timeout) {
|
|||
}
|
||||
}
|
||||
|
||||
atomic_val_compare_exchange_8(&pollFlag, 0, 1);
|
||||
(void)atomic_val_compare_exchange_8(&pollFlag, 0, 1);
|
||||
|
||||
while (1) {
|
||||
tmqHandleAllDelayedTask(tmq);
|
||||
|
@ -3133,7 +3133,7 @@ int64_t getCommittedFromServer(tmq_t* tmq, char* tname, int32_t vgId, SEpSet* ep
|
|||
|
||||
void* abuf = POINTER_SHIFT(buf, sizeof(SMsgHead));
|
||||
|
||||
SEncoder encoder;
|
||||
SEncoder encoder = {0};
|
||||
tEncoderInit(&encoder, abuf, len);
|
||||
code = tEncodeMqVgOffset(&encoder, &pOffset);
|
||||
if (code < 0) {
|
||||
|
|
|
@ -1204,8 +1204,12 @@ static int32_t taosSetSystemCfg(SConfig *pCfg) {
|
|||
SConfigItem *pItem = NULL;
|
||||
|
||||
TAOS_CHECK_GET_CFG_ITEM(pCfg, pItem, "timezone");
|
||||
if (0 == strlen(pItem->str)) {
|
||||
uError("timezone is not set");
|
||||
} else {
|
||||
TAOS_CHECK_RETURN(osSetTimezone(pItem->str));
|
||||
uDebug("timezone format changed from %s to %s", pItem->str, tsTimezoneStr);
|
||||
}
|
||||
TAOS_CHECK_RETURN(cfgSetItem(pCfg, "timezone", tsTimezoneStr, pItem->stype, true));
|
||||
|
||||
TAOS_CHECK_GET_CFG_ITEM(pCfg, pItem, "locale");
|
||||
|
@ -1216,7 +1220,7 @@ static int32_t taosSetSystemCfg(SConfig *pCfg) {
|
|||
|
||||
int32_t code = taosSetSystemLocale(locale, charset);
|
||||
if (TSDB_CODE_SUCCESS != code) {
|
||||
uInfo("failed to set locale %s, since: %s", locale, tstrerror(code));
|
||||
uError("failed to set locale:%s, since: %s", locale, tstrerror(code));
|
||||
char curLocale[TD_LOCALE_LEN] = {0};
|
||||
char curCharset[TD_CHARSET_LEN] = {0};
|
||||
taosGetSystemLocale(curLocale, curCharset);
|
||||
|
@ -1568,13 +1572,13 @@ int32_t taosCreateLog(const char *logname, int32_t logFileNum, const char *cfgDi
|
|||
const char *envFile, char *apolloUrl, SArray *pArgs, bool tsc) {
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
int32_t lino = 0;
|
||||
SConfig *pCfg = NULL;
|
||||
|
||||
if (tsCfg == NULL) {
|
||||
TAOS_CHECK_RETURN(osDefaultInit());
|
||||
TAOS_CHECK_GOTO(osDefaultInit(), &lino, _exit);
|
||||
}
|
||||
|
||||
SConfig *pCfg = NULL;
|
||||
TAOS_CHECK_RETURN(cfgInit(&pCfg));
|
||||
TAOS_CHECK_GOTO(cfgInit(&pCfg), &lino, _exit);
|
||||
|
||||
if (tsc) {
|
||||
tsLogEmbedded = 0;
|
||||
|
@ -1604,7 +1608,7 @@ int32_t taosCreateLog(const char *logname, int32_t logFileNum, const char *cfgDi
|
|||
|
||||
SConfigItem *pDebugItem = NULL;
|
||||
TAOS_CHECK_GET_CFG_ITEM(pCfg, pDebugItem, "debugFlag");
|
||||
TAOS_CHECK_RETURN(taosSetAllDebugFlag(pCfg, pDebugItem->i32));
|
||||
TAOS_CHECK_GOTO(taosSetAllDebugFlag(pCfg, pDebugItem->i32), &lino, _exit);
|
||||
|
||||
if ((code = taosMulModeMkDir(tsLogDir, 0777, true)) != TSDB_CODE_SUCCESS) {
|
||||
printf("failed to create dir:%s since %s\n", tsLogDir, tstrerror(code));
|
||||
|
|
|
@ -463,7 +463,7 @@ int32_t tqProcessVgCommittedInfoReq(STQ* pTq, SRpcMsg* pMsg) {
|
|||
terrno = TSDB_CODE_OUT_OF_MEMORY;
|
||||
return terrno;
|
||||
}
|
||||
SEncoder encoder;
|
||||
SEncoder encoder = {0};
|
||||
tEncoderInit(&encoder, buf, len);
|
||||
code = tEncodeMqVgOffset(&encoder, &vgOffset);
|
||||
tEncoderClear(&encoder);
|
||||
|
|
|
@ -106,7 +106,7 @@ int32_t tqMetaSaveOffset(STQ* pTq, STqOffset* pOffset) {
|
|||
void* buf = NULL;
|
||||
int32_t code = TDB_CODE_SUCCESS;
|
||||
int32_t vlen;
|
||||
SEncoder encoder;
|
||||
SEncoder encoder = {0};
|
||||
tEncodeSize(tEncodeSTqOffset, pOffset, vlen, code);
|
||||
if (code < 0) {
|
||||
goto END;
|
||||
|
@ -201,7 +201,7 @@ int32_t tqMetaSaveHandle(STQ* pTq, const char* key, const STqHandle* pHandle) {
|
|||
int32_t code = TDB_CODE_SUCCESS;
|
||||
int32_t vlen;
|
||||
void* buf = NULL;
|
||||
SEncoder encoder;
|
||||
SEncoder encoder = {0};
|
||||
tEncodeSize(tEncodeSTqHandle, pHandle, vlen, code);
|
||||
if (code < 0) {
|
||||
goto END;
|
||||
|
|
|
@ -595,7 +595,7 @@ int32_t buildSubmitMsgImpl(SSubmitReq2* pSubmitReq, int32_t vgId, void** pMsg, i
|
|||
int32_t len = 0;
|
||||
tEncodeSize(tEncodeSubmitReq, pSubmitReq, len, code);
|
||||
|
||||
SEncoder encoder;
|
||||
SEncoder encoder = {0};
|
||||
len += sizeof(SSubmitReq2Msg);
|
||||
|
||||
pBuf = rpcMallocCont(len);
|
||||
|
@ -1230,7 +1230,7 @@ int32_t doBuildAndSendDeleteMsg(SVnode* pVnode, char* stbFullName, SSDataBlock*
|
|||
return code;
|
||||
}
|
||||
|
||||
SEncoder encoder;
|
||||
SEncoder encoder = {0};
|
||||
void* serializedDeleteReq = rpcMallocCont(len + sizeof(SMsgHead));
|
||||
void* abuf = POINTER_SHIFT(serializedDeleteReq, sizeof(SMsgHead));
|
||||
tEncoderInit(&encoder, abuf, len);
|
||||
|
|
|
@ -484,6 +484,7 @@ static void tsdbCachePutBatch(SLastCol *pLastCol, const void *key, size_t klen,
|
|||
code = tsdbCacheSerialize(pLastCol, &rocks_value, &vlen);
|
||||
if (code) {
|
||||
tsdbError("tsdb/cache: vgId:%d, serialize failed since %s.", TD_VID(pTsdb->pVnode), tstrerror(code));
|
||||
return;
|
||||
}
|
||||
|
||||
(void)taosThreadMutexLock(&rCache->rMutex);
|
||||
|
@ -1143,13 +1144,13 @@ static int32_t tsdbCacheUpdate(STsdb *pTsdb, tb_uid_t suid, tb_uid_t uid, SArray
|
|||
code = tsdbCacheSerialize(&lastColTmp, &value, &vlen);
|
||||
if (code) {
|
||||
tsdbError("tsdb/cache: vgId:%d, serialize failed since %s.", TD_VID(pTsdb->pVnode), tstrerror(code));
|
||||
}
|
||||
|
||||
} else {
|
||||
(void)taosThreadMutexLock(&pTsdb->rCache.rMutex);
|
||||
|
||||
rocksdb_writebatch_put(wb, (char *)&idxKey->key, ROCKS_KEY_LEN, value, vlen);
|
||||
|
||||
(void)taosThreadMutexUnlock(&pTsdb->rCache.rMutex);
|
||||
}
|
||||
|
||||
pLastCol = &lastColTmp;
|
||||
SLastCol *pTmpLastCol = taosMemoryCalloc(1, sizeof(SLastCol));
|
||||
|
@ -1411,6 +1412,11 @@ static int32_t tsdbCacheLoadFromRaw(STsdb *pTsdb, tb_uid_t uid, SArray *pLastArr
|
|||
if (IS_LAST_KEY(idxKey->key)) {
|
||||
if (NULL == lastTmpIndexArray) {
|
||||
lastTmpIndexArray = taosArrayInit(num_keys, sizeof(int32_t));
|
||||
if (!lastTmpIndexArray) {
|
||||
taosArrayDestroy(lastrowTmpIndexArray);
|
||||
|
||||
TAOS_RETURN(TSDB_CODE_OUT_OF_MEMORY);
|
||||
}
|
||||
}
|
||||
(void)taosArrayPush(lastTmpIndexArray, &(i));
|
||||
lastColIds[lastIndex] = idxKey->key.cid;
|
||||
|
@ -1419,6 +1425,11 @@ static int32_t tsdbCacheLoadFromRaw(STsdb *pTsdb, tb_uid_t uid, SArray *pLastArr
|
|||
} else {
|
||||
if (NULL == lastrowTmpIndexArray) {
|
||||
lastrowTmpIndexArray = taosArrayInit(num_keys, sizeof(int32_t));
|
||||
if (!lastrowTmpIndexArray) {
|
||||
taosArrayDestroy(lastTmpIndexArray);
|
||||
|
||||
TAOS_RETURN(TSDB_CODE_OUT_OF_MEMORY);
|
||||
}
|
||||
}
|
||||
(void)taosArrayPush(lastrowTmpIndexArray, &(i));
|
||||
lastrowColIds[lastrowIndex] = idxKey->key.cid;
|
||||
|
@ -1428,6 +1439,11 @@ static int32_t tsdbCacheLoadFromRaw(STsdb *pTsdb, tb_uid_t uid, SArray *pLastArr
|
|||
}
|
||||
|
||||
pTmpColArray = taosArrayInit(lastIndex + lastrowIndex, sizeof(SLastCol));
|
||||
if (!pTmpColArray) {
|
||||
taosArrayDestroy(lastrowTmpIndexArray);
|
||||
taosArrayDestroy(lastTmpIndexArray);
|
||||
TAOS_RETURN(TSDB_CODE_OUT_OF_MEMORY);
|
||||
}
|
||||
|
||||
if (lastTmpIndexArray != NULL) {
|
||||
(void)mergeLastCid(uid, pTsdb, &lastTmpColArray, pr, lastColIds, lastIndex, lastSlotIds);
|
||||
|
@ -1510,13 +1526,13 @@ static int32_t tsdbCacheLoadFromRaw(STsdb *pTsdb, tb_uid_t uid, SArray *pLastArr
|
|||
code = tsdbCacheSerialize(pLastCol, &value, &vlen);
|
||||
if (code) {
|
||||
tsdbError("tsdb/cache: vgId:%d, serialize failed since %s.", TD_VID(pTsdb->pVnode), tstrerror(code));
|
||||
}
|
||||
|
||||
} else {
|
||||
SLastKey *key = &idxKey->key;
|
||||
size_t klen = ROCKS_KEY_LEN;
|
||||
rocksdb_writebatch_put(wb, (char *)key, klen, value, vlen);
|
||||
taosMemoryFree(value);
|
||||
}
|
||||
}
|
||||
|
||||
if (wb) {
|
||||
rocksMayWrite(pTsdb, false, true, false);
|
||||
|
|
|
@ -449,11 +449,14 @@ void doSetTableGroupOutputBuf(SOperatorInfo* pOperator, int32_t numOfOutput, uin
|
|||
SResultRow* pResultRow =
|
||||
doSetResultOutBufByKey(pAggInfo->aggSup.pResultBuf, pResultRowInfo, (char*)&groupId, sizeof(groupId), true,
|
||||
groupId, pTaskInfo, false, &pAggInfo->aggSup, true);
|
||||
if (pResultRow == NULL || pTaskInfo->code != 0) {
|
||||
T_LONG_JMP(pTaskInfo->env, pTaskInfo->code);
|
||||
}
|
||||
/*
|
||||
* not assign result buffer yet, add new result buffer
|
||||
* all group belong to one result set, and each group result has different group id so set the id to be one
|
||||
*/
|
||||
if (pResultRow == NULL || pResultRow->pageId == -1) {
|
||||
if (pResultRow->pageId == -1) {
|
||||
int32_t ret = addNewResultRowBuf(pResultRow, pAggInfo->aggSup.pResultBuf, pAggInfo->binfo.pRes->info.rowSize);
|
||||
if (ret != TSDB_CODE_SUCCESS) {
|
||||
T_LONG_JMP(pTaskInfo->env, terrno);
|
||||
|
|
|
@ -88,20 +88,26 @@ static void switchCtxOrder(SqlFunctionCtx* pCtx, int32_t numOfOutput) {
|
|||
}
|
||||
}
|
||||
|
||||
static bool overlapWithTimeWindow(SInterval* pInterval, SDataBlockInfo* pBlockInfo, int32_t order) {
|
||||
static int32_t overlapWithTimeWindow(SInterval* pInterval, SDataBlockInfo* pBlockInfo, int32_t order, bool* overlap) {
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
STimeWindow w = {0};
|
||||
|
||||
// 0 by default, which means it is not a interval operator of the upstream operator.
|
||||
if (pInterval->interval == 0) {
|
||||
return false;
|
||||
*overlap = false;
|
||||
return code;
|
||||
}
|
||||
|
||||
if (order == TSDB_ORDER_ASC) {
|
||||
w = getAlignQueryTimeWindow(pInterval, pBlockInfo->window.skey);
|
||||
ASSERT(w.ekey >= pBlockInfo->window.skey);
|
||||
if(w.ekey < pBlockInfo->window.skey) {
|
||||
qError("w.ekey:%" PRId64 " < pBlockInfo->window.skey:%" PRId64, w.ekey, pBlockInfo->window.skey);
|
||||
return TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
if (w.ekey < pBlockInfo->window.ekey) {
|
||||
return true;
|
||||
*overlap = true;
|
||||
return code;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
|
@ -110,17 +116,25 @@ static bool overlapWithTimeWindow(SInterval* pInterval, SDataBlockInfo* pBlockIn
|
|||
break;
|
||||
}
|
||||
|
||||
ASSERT(w.ekey > pBlockInfo->window.ekey);
|
||||
if(w.ekey <= pBlockInfo->window.ekey) {
|
||||
qError("w.ekey:%" PRId64 " <= pBlockInfo->window.ekey:%" PRId64, w.ekey, pBlockInfo->window.ekey);
|
||||
return TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
|
||||
}
|
||||
if (TMAX(w.skey, pBlockInfo->window.skey) <= pBlockInfo->window.ekey) {
|
||||
return true;
|
||||
*overlap = true;
|
||||
return code;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
w = getAlignQueryTimeWindow(pInterval, pBlockInfo->window.ekey);
|
||||
ASSERT(w.skey <= pBlockInfo->window.ekey);
|
||||
if(w.skey > pBlockInfo->window.ekey) {
|
||||
qError("w.skey:%" PRId64 " > pBlockInfo->window.skey:%" PRId64, w.skey, pBlockInfo->window.ekey);
|
||||
return TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
if (w.skey > pBlockInfo->window.skey) {
|
||||
return true;
|
||||
*overlap = true;
|
||||
return code;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
|
@ -129,14 +143,19 @@ static bool overlapWithTimeWindow(SInterval* pInterval, SDataBlockInfo* pBlockIn
|
|||
break;
|
||||
}
|
||||
|
||||
ASSERT(w.skey < pBlockInfo->window.skey);
|
||||
if(w.skey >= pBlockInfo->window.skey){
|
||||
qError("w.skey:%" PRId64 " >= pBlockInfo->window.skey:%" PRId64, w.skey, pBlockInfo->window.skey);
|
||||
return TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
|
||||
}
|
||||
if (pBlockInfo->window.skey <= TMIN(w.ekey, pBlockInfo->window.ekey)) {
|
||||
return true;
|
||||
*overlap = true;
|
||||
return code;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
*overlap = false;
|
||||
return code;
|
||||
}
|
||||
|
||||
// this function is for table scanner to extract temporary results of upstream aggregate results.
|
||||
|
@ -319,9 +338,18 @@ static int32_t loadDataBlock(SOperatorInfo* pOperator, STableScanBase* pTableSca
|
|||
|
||||
bool loadSMA = false;
|
||||
*status = pTableScanInfo->dataBlockLoadFlag;
|
||||
if (pOperator->exprSupp.pFilterInfo != NULL ||
|
||||
overlapWithTimeWindow(&pTableScanInfo->pdInfo.interval, &pBlock->info, pTableScanInfo->cond.order)) {
|
||||
if (pOperator->exprSupp.pFilterInfo != NULL) {
|
||||
(*status) = FUNC_DATA_REQUIRED_DATA_LOAD;
|
||||
} else {
|
||||
bool overlap = false;
|
||||
int ret =
|
||||
overlapWithTimeWindow(&pTableScanInfo->pdInfo.interval, &pBlock->info, pTableScanInfo->cond.order, &overlap);
|
||||
if (ret != TSDB_CODE_SUCCESS) {
|
||||
return ret;
|
||||
}
|
||||
if (overlap) {
|
||||
(*status) = FUNC_DATA_REQUIRED_DATA_LOAD;
|
||||
}
|
||||
}
|
||||
|
||||
SDataBlockInfo* pBlockInfo = &pBlock->info;
|
||||
|
@ -358,7 +386,10 @@ static int32_t loadDataBlock(SOperatorInfo* pOperator, STableScanBase* pTableSca
|
|||
}
|
||||
}
|
||||
|
||||
ASSERT(*status == FUNC_DATA_REQUIRED_DATA_LOAD);
|
||||
if(*status != FUNC_DATA_REQUIRED_DATA_LOAD) {
|
||||
qError("[loadDataBlock] invalid status:%d", *status);
|
||||
return TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
|
||||
}
|
||||
|
||||
// try to filter data block according to sma info
|
||||
if (pOperator->exprSupp.pFilterInfo != NULL && (!loadSMA)) {
|
||||
|
@ -413,7 +444,10 @@ static int32_t loadDataBlock(SOperatorInfo* pOperator, STableScanBase* pTableSca
|
|||
return code;
|
||||
}
|
||||
|
||||
ASSERT(p == pBlock);
|
||||
if(p != pBlock) {
|
||||
qError("[loadDataBlock] p != pBlock");
|
||||
return TSDB_CODE_QRY_EXECUTOR_INTERNAL_ERROR;
|
||||
}
|
||||
doSetTagColumnData(pTableScanInfo, pBlock, pTaskInfo, pBlock->info.rows);
|
||||
|
||||
// restore the previous value
|
||||
|
|
|
@ -666,7 +666,9 @@ static bool isCalculatedWin(SIntervalAggOperatorInfo* pInfo, const STimeWindow*
|
|||
* every tuple in every block.
|
||||
* And the boundedQueue keeps refreshing all records with smaller ts key.
|
||||
*/
|
||||
static bool filterWindowWithLimit(SIntervalAggOperatorInfo* pOperatorInfo, STimeWindow* win, uint64_t groupId) {
|
||||
static bool filterWindowWithLimit(SIntervalAggOperatorInfo* pOperatorInfo, STimeWindow* win, uint64_t groupId, SExecTaskInfo* pTaskInfo) {
|
||||
int32_t code = TSDB_CODE_SUCCESS;
|
||||
int32_t lino = 0;
|
||||
if (!pOperatorInfo->limited // if no limit info, no filter will be applied
|
||||
|| pOperatorInfo->binfo.inputTsOrder != pOperatorInfo->binfo.outputTsOrder
|
||||
// if input/output ts order mismatch, no filter
|
||||
|
@ -678,6 +680,7 @@ static bool filterWindowWithLimit(SIntervalAggOperatorInfo* pOperatorInfo, STime
|
|||
|
||||
if (pOperatorInfo->pBQ == NULL) {
|
||||
pOperatorInfo->pBQ = createBoundedQueue(pOperatorInfo->limit - 1, tsKeyCompFn, taosMemoryFree, pOperatorInfo);
|
||||
QUERY_CHECK_NULL(pOperatorInfo->pBQ, code, lino, _end, terrno);
|
||||
}
|
||||
|
||||
bool shouldFilter = false;
|
||||
|
@ -694,12 +697,21 @@ static bool filterWindowWithLimit(SIntervalAggOperatorInfo* pOperatorInfo, STime
|
|||
|
||||
// cur win not been filtered out and not been pushed into BQ yet, push it into BQ
|
||||
PriorityQueueNode node = {.data = taosMemoryMalloc(sizeof(TSKEY))};
|
||||
QUERY_CHECK_NULL(node.data, code, lino, _end, terrno);
|
||||
|
||||
*((TSKEY*)node.data) = win->skey;
|
||||
|
||||
if (NULL == taosBQPush(pOperatorInfo->pBQ, &node)) {
|
||||
taosMemoryFree(node.data);
|
||||
return true;
|
||||
}
|
||||
|
||||
_end:
|
||||
if (code != TSDB_CODE_SUCCESS) {
|
||||
qError("%s failed at line %d since %s", __func__, lino, tstrerror(code));
|
||||
pTaskInfo->code = code;
|
||||
T_LONG_JMP(pTaskInfo->env, code);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -731,7 +743,7 @@ static bool hashIntervalAgg(SOperatorInfo* pOperatorInfo, SResultRowInfo* pResul
|
|||
|
||||
STimeWindow win =
|
||||
getActiveTimeWindow(pInfo->aggSup.pResultBuf, pResultRowInfo, ts, &pInfo->interval, pInfo->binfo.inputTsOrder);
|
||||
if (filterWindowWithLimit(pInfo, &win, tableGroupId)) return false;
|
||||
if (filterWindowWithLimit(pInfo, &win, tableGroupId, pTaskInfo)) return false;
|
||||
|
||||
int32_t ret = setTimeWindowOutputBuf(pResultRowInfo, &win, (scanFlag == MAIN_SCAN), &pResult, tableGroupId,
|
||||
pSup->pCtx, numOfOutput, pSup->rowEntryInfoOffset, &pInfo->aggSup, pTaskInfo);
|
||||
|
@ -770,7 +782,7 @@ static bool hashIntervalAgg(SOperatorInfo* pOperatorInfo, SResultRowInfo* pResul
|
|||
int32_t prevEndPos = forwardRows - 1 + startPos;
|
||||
startPos = getNextQualifiedWindow(&pInfo->interval, &nextWin, &pBlock->info, tsCols, prevEndPos,
|
||||
pInfo->binfo.inputTsOrder);
|
||||
if (startPos < 0 || filterWindowWithLimit(pInfo, &nextWin, tableGroupId)) {
|
||||
if (startPos < 0 || filterWindowWithLimit(pInfo, &nextWin, tableGroupId, pTaskInfo)) {
|
||||
break;
|
||||
}
|
||||
// null data, failed to allocate more memory buffer
|
||||
|
|
|
@ -156,6 +156,10 @@ _exit:
|
|||
int32_t executeGeomFromTextFunc(SColumnInfoData *pInputData, int32_t i, SColumnInfoData *pOutputData) {
|
||||
int32_t code = TSDB_CODE_FAILED;
|
||||
|
||||
if (!IS_VAR_DATA_TYPE((pInputData)->info.type)) {
|
||||
return TSDB_CODE_FUNC_FUNTION_PARA_VALUE;
|
||||
}
|
||||
|
||||
char *input = colDataGetData(pInputData, i);
|
||||
unsigned char *output = NULL;
|
||||
|
||||
|
|
|
@ -147,7 +147,17 @@ static int32_t initWktRegex(pcre2_code **ppRegex, pcre2_match_data **ppMatchData
|
|||
"*)(([-+]?[0-9]+\\.?[0-9]*)|([-+]?[0-9]*\\.?[0-9]+))(e[-+]?[0-9]+)?){1,3}( *))*( *)\\)))( *))*( *)\\)))( *))*( "
|
||||
"*)\\)))|(GEOCOLLECTION\\((?R)(( *)(,)( *)(?R))*( *)\\))( *)$");
|
||||
|
||||
code = doRegComp(ppRegex, ppMatchData, wktPatternWithSpace);
|
||||
pcre2_code *pRegex = NULL;
|
||||
pcre2_match_data *pMatchData = NULL;
|
||||
code = doRegComp(&pRegex, &pMatchData, wktPatternWithSpace);
|
||||
if (code < 0) {
|
||||
taosMemoryFree(wktPatternWithSpace);
|
||||
return TSDB_CODE_OUT_OF_MEMORY;
|
||||
}
|
||||
|
||||
*ppRegex = pRegex;
|
||||
*ppMatchData = pMatchData;
|
||||
|
||||
taosMemoryFree(wktPatternWithSpace);
|
||||
return code;
|
||||
}
|
||||
|
|
|
@ -464,7 +464,7 @@ struct SFilterInfo {
|
|||
(colInfo).type = RANGE_TYPE_UNIT; \
|
||||
(colInfo).dataType = FILTER_UNIT_DATA_TYPE(u); \
|
||||
if (taosArrayPush((SArray *)((colInfo).info), &u) == NULL) { \
|
||||
FLT_ERR_RET(TSDB_CODE_OUT_OF_MEMORY); \
|
||||
FLT_ERR_RET(terrno); \
|
||||
} \
|
||||
} while (0)
|
||||
#define FILTER_PUSH_VAR_HASH(colInfo, ha) \
|
||||
|
@ -481,6 +481,9 @@ struct SFilterInfo {
|
|||
#define FILTER_COPY_IDX(dst, src, n) \
|
||||
do { \
|
||||
*(dst) = taosMemoryMalloc(sizeof(uint32_t) * n); \
|
||||
if (NULL == *(dst)) { \
|
||||
FLT_ERR_JRET(terrno); \
|
||||
} \
|
||||
(void)memcpy(*(dst), src, sizeof(uint32_t) * n); \
|
||||
} while (0)
|
||||
|
||||
|
|
|
@ -1660,12 +1660,14 @@ int tdbBtcOpen(SBTC *pBtc, SBTree *pBt, TXN *pTxn) {
|
|||
if (pTxn == NULL) {
|
||||
TXN *pTxn = tdbOsCalloc(1, sizeof(*pTxn));
|
||||
if (!pTxn) {
|
||||
pBtc->pTxn = NULL;
|
||||
return terrno;
|
||||
}
|
||||
|
||||
int32_t ret = tdbTxnOpen(pTxn, 0, tdbDefaultMalloc, tdbDefaultFree, NULL, 0);
|
||||
if (ret < 0) {
|
||||
tdbOsFree(pTxn);
|
||||
pBtc->pTxn = NULL;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
@ -1881,7 +1883,6 @@ int tdbBtreeNext(SBTC *pBtc, void **ppKey, int *kLen, void **ppVal, int *vLen) {
|
|||
if (cd.vLen > 0) {
|
||||
pVal = tdbRealloc(*ppVal, cd.vLen);
|
||||
if (pVal == NULL) {
|
||||
tdbFree(pKey);
|
||||
return terrno;
|
||||
}
|
||||
|
||||
|
|
|
@ -51,10 +51,11 @@ int32_t osDefaultInit() {
|
|||
taosSeedRand(taosSafeRand());
|
||||
taosGetSystemLocale(tsLocale, tsCharset);
|
||||
taosGetSystemTimezone(tsTimezoneStr, &tsTimezone);
|
||||
code = taosSetSystemTimezone(tsTimezoneStr, tsTimezoneStr, &tsDaylight, &tsTimezone);
|
||||
if (code) {
|
||||
if (strlen(tsTimezoneStr) > 0) { // ignore empty timezone
|
||||
if ((code = taosSetSystemTimezone(tsTimezoneStr, tsTimezoneStr, &tsDaylight, &tsTimezone)) != TSDB_CODE_SUCCESS)
|
||||
return code;
|
||||
}
|
||||
|
||||
taosGetSystemInfo();
|
||||
|
||||
// deadlock in query
|
||||
|
|
|
@ -244,6 +244,12 @@ static int32_t doSetConf(SConfigItem *pItem, const char *value, ECfgSrcType styp
|
|||
|
||||
static int32_t cfgSetTimezone(SConfigItem *pItem, const char *value, ECfgSrcType stype) {
|
||||
TAOS_CHECK_RETURN(doSetConf(pItem, value, stype));
|
||||
if (strlen(value) == 0) {
|
||||
uError("cfg:%s, type:%s src:%s, value:%s, skip to set timezone", pItem->name, cfgDtypeStr(pItem->dtype),
|
||||
cfgStypeStr(stype), value);
|
||||
TAOS_RETURN(TSDB_CODE_SUCCESS);
|
||||
}
|
||||
|
||||
TAOS_CHECK_RETURN(osSetTimezone(value));
|
||||
TAOS_RETURN(TSDB_CODE_SUCCESS);
|
||||
}
|
||||
|
|
|
@ -5,14 +5,24 @@ int32_t doRegComp(pcre2_code** ppRegex, pcre2_match_data** ppMatchData, const ch
|
|||
int errorcode;
|
||||
PCRE2_SIZE erroroffset;
|
||||
|
||||
*ppRegex = pcre2_compile((PCRE2_SPTR8)pattern, PCRE2_ZERO_TERMINATED, options, &errorcode, &erroroffset, NULL);
|
||||
if (*ppRegex == NULL) {
|
||||
pcre2_code* pRegex = NULL;
|
||||
pcre2_match_data* pMatchData = NULL;
|
||||
|
||||
pRegex = pcre2_compile((PCRE2_SPTR8)pattern, PCRE2_ZERO_TERMINATED, options, &errorcode, &erroroffset, NULL);
|
||||
if (pRegex == NULL) {
|
||||
PCRE2_UCHAR buffer[256];
|
||||
(void)pcre2_get_error_message(errorcode, buffer, sizeof(buffer));
|
||||
return 1;
|
||||
return -1;
|
||||
}
|
||||
|
||||
*ppMatchData = pcre2_match_data_create_from_pattern(*ppRegex, NULL);
|
||||
pMatchData = pcre2_match_data_create_from_pattern(pRegex, NULL);
|
||||
if (pMatchData == NULL) {
|
||||
pcre2_code_free(pRegex);
|
||||
return -1;
|
||||
}
|
||||
|
||||
*ppRegex = pRegex;
|
||||
*ppMatchData = pMatchData;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -122,7 +122,7 @@ def scan_files_path(source_file_path):
|
|||
for file in files:
|
||||
if any(item in root for item in scan_dir_list):
|
||||
file_path = os.path.join(root, file)
|
||||
if (file_path.endswith(".c") or file_path.endswith(".h") or file_path.endswith(".cpp")) and all(item not in file_path for item in scan_skip_file_list):
|
||||
if (file_path.endswith(".c") or file_name.endswith(".h") or file_path.endswith(".cpp")) and all(item not in file_path for item in scan_skip_file_list):
|
||||
all_file_path.append(file_path)
|
||||
logger.info("Found %s files" % len(all_file_path))
|
||||
|
||||
|
@ -134,7 +134,7 @@ def input_files(change_files):
|
|||
for line in file:
|
||||
file_name = line.strip()
|
||||
if any(dir_name in file_name for dir_name in scan_dir_list):
|
||||
if (file_name.endswith(".c") or file_name.endswith(".h") or line.endswith(".cpp")) and all(dir_name not in file_name for dir_name in scan_skip_file_list):
|
||||
if (file_name.endswith(".c") or line.endswith(".cpp")) and all(dir_name not in file_name for dir_name in scan_skip_file_list):
|
||||
if "enterprise" in file_name:
|
||||
file_name = os.path.join(TD_project_path, file_name)
|
||||
else:
|
||||
|
|
|
@ -544,6 +544,8 @@
|
|||
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/limit.py
|
||||
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/log.py
|
||||
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/log.py -R
|
||||
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/logical_operators.py
|
||||
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/logical_operators.py -R
|
||||
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/lower.py
|
||||
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/lower.py -R
|
||||
,,y,system-test,./pytest.sh python3 ./test.py -f 2-query/ltrim.py
|
||||
|
|
|
@ -0,0 +1,120 @@
|
|||
from wsgiref.headers import tspecials
|
||||
from util.log import *
|
||||
from util.cases import *
|
||||
from util.sql import *
|
||||
import numpy as np
|
||||
|
||||
DBNAME = "db"
|
||||
|
||||
class TDTestCase:
|
||||
def init(self, conn, logSql, replicaVar=1):
|
||||
self.replicaVar = int(replicaVar)
|
||||
tdLog.debug("start to execute %s" % __file__)
|
||||
tdSql.init(conn.cursor())
|
||||
|
||||
self.rowNum = 10
|
||||
self.batchNum = 5
|
||||
self.ts = 1537146000000
|
||||
|
||||
def run(self,dbname=DBNAME):
|
||||
tdSql.prepare()
|
||||
|
||||
tdSql.execute(f'''create table {dbname}.tb (ts timestamp, v int, f float, b varchar(8))''')
|
||||
tdSql.execute(f"insert into {dbname}.tb values('2024-07-04 10:00:00', 1, 2.0, 't0')")
|
||||
tdSql.execute(f"insert into {dbname}.tb values('2024-07-04 10:01:00', 11, 12.1, 't0')")
|
||||
tdSql.execute(f"insert into {dbname}.tb values('2024-07-04 10:02:00', 21, 22.2, 't0')")
|
||||
tdSql.execute(f"insert into {dbname}.tb values('2024-07-04 10:03:00', 31, 32.3, 't0')")
|
||||
tdSql.execute(f"insert into {dbname}.tb values('2024-07-04 10:04:00', 41, 42.4, 't0')")
|
||||
tdSql.execute(f"insert into {dbname}.tb values('2024-07-04 10:05:00', 51, 52.5, 't1')")
|
||||
tdSql.execute(f"insert into {dbname}.tb values('2024-07-04 10:06:00', 61, 62.6, 't1')")
|
||||
tdSql.execute(f"insert into {dbname}.tb values('2024-07-04 10:07:00', 71, 72.7, 't1')")
|
||||
tdSql.execute(f"insert into {dbname}.tb values('2024-07-04 10:08:00', 81, 82.8, 't1')")
|
||||
tdSql.execute(f"insert into {dbname}.tb values('2024-07-04 10:09:00', 91, 92.9, 't1')")
|
||||
tdSql.execute(f"insert into {dbname}.tb values('2024-07-04 10:00:00',101,112.9, 't2')")
|
||||
tdSql.execute(f"insert into {dbname}.tb values('2024-07-04 10:01:00',111,112.1, 't2')")
|
||||
tdSql.execute(f"insert into {dbname}.tb values('2024-07-04 10:02:00',121,122.2, 't2')")
|
||||
tdSql.execute(f"insert into {dbname}.tb values('2024-07-04 10:03:00',131,132.3, 't2')")
|
||||
tdSql.execute(f"insert into {dbname}.tb values('2024-07-04 10:04:00',141,142.4, 't2')")
|
||||
tdSql.execute(f"insert into {dbname}.tb values('2024-07-04 10:05:00',151,152.5, 't3')")
|
||||
tdSql.execute(f"insert into {dbname}.tb values('2024-07-04 10:06:00',161,162.6, 't3')")
|
||||
tdSql.execute(f"insert into {dbname}.tb values('2024-07-04 10:07:00',171,172.7, 't3')")
|
||||
tdSql.execute(f"insert into {dbname}.tb values('2024-07-04 10:08:00',181,182.8, 't3')")
|
||||
tdSql.execute(f"insert into {dbname}.tb values('2024-07-04 10:09:00',191,192.9, 't3')")
|
||||
#test for operator and
|
||||
tdSql.query('''select
|
||||
`T_9048C6F41B2A45CE94FF3`.`ts` as `__fcol_0`,
|
||||
`T_9048C6F41B2A45CE94FF3`.`v` as `__fcol_1`,
|
||||
`T_9048C6F41B2A45CE94FF3`.`f` as `__fcol_2`,
|
||||
`T_9048C6F41B2A45CE94FF3`.`b` as `__fcol_3`,
|
||||
`T_9048C6F41B2A45CE94FF3`.`v` > 0
|
||||
and `T_9048C6F41B2A45CE94FF3`.`f` > `T_9048C6F41B2A45CE94FF3`.`v`
|
||||
from `db`.`tb` as `T_9048C6F41B2A45CE94FF3`
|
||||
limit 5000''')
|
||||
tdSql.checkRows(10)
|
||||
#test for operator or
|
||||
tdSql.query('''select
|
||||
`T_9048C6F41B2A45CE94FF3`.`ts` as `__fcol_0`,
|
||||
`T_9048C6F41B2A45CE94FF3`.`v` as `__fcol_1`,
|
||||
`T_9048C6F41B2A45CE94FF3`.`f` as `__fcol_2`,
|
||||
`T_9048C6F41B2A45CE94FF3`.`b` as `__fcol_3`,
|
||||
`T_9048C6F41B2A45CE94FF3`.`v` > 0
|
||||
or `T_9048C6F41B2A45CE94FF3`.`f` > `T_9048C6F41B2A45CE94FF3`.`v`
|
||||
from `db`.`tb` as `T_9048C6F41B2A45CE94FF3`
|
||||
limit 5000''')
|
||||
tdSql.checkRows(10)
|
||||
#test for operator in
|
||||
tdSql.query('''select
|
||||
`T_9048C6F41B2A45CE94FF3`.`ts` as `__fcol_0`,
|
||||
`T_9048C6F41B2A45CE94FF3`.`v` as `__fcol_1`,
|
||||
`T_9048C6F41B2A45CE94FF3`.`f` as `__fcol_2`,
|
||||
`T_9048C6F41B2A45CE94FF3`.`b` as `__fcol_3`,
|
||||
`T_9048C6F41B2A45CE94FF3`.`v` in (1)
|
||||
from `db`.`tb` as `T_9048C6F41B2A45CE94FF3`
|
||||
limit 5000;''')
|
||||
tdSql.checkRows(10)
|
||||
#test for operator not
|
||||
tdSql.query('''select
|
||||
`T_9048C6F41B2A45CE94FF3`.`ts` as `__fcol_0`,
|
||||
`T_9048C6F41B2A45CE94FF3`.`v` as `__fcol_1`,
|
||||
`T_9048C6F41B2A45CE94FF3`.`f` as `__fcol_2`,
|
||||
`T_9048C6F41B2A45CE94FF3`.`b` as `__fcol_3`,
|
||||
not `T_9048C6F41B2A45CE94FF3`.`v` > 0
|
||||
from `db`.`tb` as `T_9048C6F41B2A45CE94FF3`
|
||||
limit 5000''')
|
||||
tdSql.checkRows(10)
|
||||
#test for operator between and
|
||||
tdSql.query('''select
|
||||
`T_9048C6F41B2A45CE94FF3`.`ts` as `__fcol_0`,
|
||||
`T_9048C6F41B2A45CE94FF3`.`v` as `__fcol_1`,
|
||||
`T_9048C6F41B2A45CE94FF3`.`f` as `__fcol_2`,
|
||||
`T_9048C6F41B2A45CE94FF3`.`b` as `__fcol_3`,
|
||||
`T_9048C6F41B2A45CE94FF3`.`v` between 1 and 200
|
||||
from `db`.`tb` as `T_9048C6F41B2A45CE94FF3`
|
||||
limit 5000''')
|
||||
tdSql.checkRows(10)
|
||||
#test for operator is null
|
||||
tdSql.query('''select
|
||||
`T_9048C6F41B2A45CE94FF3`.`ts` as `__fcol_0`,
|
||||
`T_9048C6F41B2A45CE94FF3`.`v` as `__fcol_1`,
|
||||
`T_9048C6F41B2A45CE94FF3`.`f` as `__fcol_2`,
|
||||
`T_9048C6F41B2A45CE94FF3`.`b` as `__fcol_3`,
|
||||
`T_9048C6F41B2A45CE94FF3`.`v` is null
|
||||
from `db`.`tb` as `T_9048C6F41B2A45CE94FF3`
|
||||
limit 5000''')
|
||||
tdSql.checkRows(10)
|
||||
#test for operator is not null
|
||||
tdSql.query('''select
|
||||
`T_9048C6F41B2A45CE94FF3`.`ts` as `__fcol_0`,
|
||||
`T_9048C6F41B2A45CE94FF3`.`v` as `__fcol_1`,
|
||||
`T_9048C6F41B2A45CE94FF3`.`f` as `__fcol_2`,
|
||||
`T_9048C6F41B2A45CE94FF3`.`b` as `__fcol_3`,
|
||||
`T_9048C6F41B2A45CE94FF3`.`v` is not null
|
||||
from `db`.`tb` as `T_9048C6F41B2A45CE94FF3`
|
||||
limit 5000''')
|
||||
tdSql.checkRows(10)
|
||||
def stop(self):
|
||||
tdSql.close()
|
||||
tdLog.success("%s successfully executed" % __file__)
|
||||
|
||||
tdCases.addWindows(__file__, TDTestCase())
|
||||
tdCases.addLinux(__file__, TDTestCase())
|
|
@ -454,7 +454,7 @@ int buildStable(TAOS* pConn, TAOS_RES* pRes) {
|
|||
taos_free_result(pRes);
|
||||
#else
|
||||
pRes = taos_query(pConn,
|
||||
"create stream meters_summary_s trigger at_once IGNORE EXPIRED 0 into meters_summary as select "
|
||||
"create stream meters_summary_s trigger at_once IGNORE EXPIRED 0 fill_history 1 into meters_summary as select "
|
||||
"_wstart, max(current) as current, "
|
||||
"groupid, location from meters partition by groupid, location interval(10m)");
|
||||
if (taos_errno(pRes) != 0) {
|
||||
|
|
Loading…
Reference in New Issue