跳至主要內容

C++ 原生接口

...大约 11 分钟

C++ 原生接口

依赖

  • Java 8+
  • Maven 3.5+
  • Flex
  • Bison 2.7+
  • Boost 1.56+
  • OpenSSL 1.0+
  • GCC 5.5.0+

安装

安装相关依赖

  • MAC

    1. 安装 Bison :Mac 环境下预安装了 Bison 2.3 版本,但该版本过低不能够用来编译 Thrift。

      使用 Bison 2.3 版本会报以下错误:
      invalid directive: '%code'

      使用下面 brew 命令更新 bison 版本:

      brew install bison
      brew link bison --force
      

      添加环境变量:

      echo 'export PATH="/usr/local/opt/bison/bin:$PATH"' >> ~/.bash_profile
      
    2. 安装 Boost :确保安装较新的 Boost 版本。

      brew install boost
      brew link boost
      
    3. 检查 OpenSSL :确保 openssl 库已安装,默认的 openssl 头文件路径为"/usr/local/opt/openssl/include"

      如果在编译过程中出现找不到 openssl 的错误,尝试添加-Dopenssl.include.dir=""

  • Ubuntu 20

    使用以下命令安装所有依赖:

    sudo apt-get install gcc-9 g++-9 libstdc++-9-dev bison flex libboost-all-dev libssl-dev zlib1g-dev
    
  • CentOS 7.x

    使用 yum 命令安装部分依赖。

    sudo yum install bison flex openssl-devel
    

    使用 yum 安装的 GCC、Boost 版本过低,在编译时会报错,需自行安装或升级。

  • Windows

    1. 构建编译环境

      • 安装 MS Visual Studio(推荐安装 2019 版本):安装时需要勾选 Visual Studio C/C++ IDE and compiler(supporting CMake, Clang, MinGW)。
      • 下载安装 CMakeopen in new window
    2. 下载安装 Flex、Bison

      • 下载 Win_Flex_Bisonopen in new window
      • 下载后需要将可执行文件重命名为 flex.exe 和 bison.exe 以保证编译时能够被找到,添加可执行文件的目录到 PATH 环境变量中。
    3. 安装 Boost

    4. 安装 OpenSSL

执行编译

从 git 克隆源代码:

git clone https://github.com/apache/iotdb.git

默认的主分支是master分支,如果你想使用某个发布版本,请切换分支 (如 0.13 版本):

git checkout rel/0.13

在 IoTDB 根目录下执行 maven 编译:

  • Mac & Linux

    mvn package -P compile-cpp -pl example/client-cpp-example -am -DskipTest
    
  • Windows

    mvn package -P compile-cpp -pl iotdb-client/client-cpp,iotdb-core/datanode,example/client-cpp-example -am -Dcmake.generator="your cmake generator" -Dboost.include.dir=${your boost header folder} -Dboost.library.dir=${your boost lib (stage) folder} -DskipTests
    
    • CMake 根据不同编译平台使用不同的生成器,需添加-Dcmake.generator=""选项来指定使用的生成器名称,例如: -Dcmake.generator="Visual Studio 16 2019"。(通过cmake --help命令可以查看 CMake 支持的生成器列表)
    • 为了帮助 CMake 找到本地安装好的 Boost,在编译命令中需添加相关参数,例如:-DboostIncludeDir="C:\Program Files (x86)\boost_1_78_0" -DboostLibraryDir="C:\Program Files (x86)\boost_1_78_0\stage\lib"

编译成功后,打包好的 zip 文件位于 client-cpp/target/client-cpp-1.3.0-SNAPSHOT-cpp-${os}.zip

编译 Q&A

Q:编译报错undefined reference to '_libc_sinle_thread'如何处理?

A:

  • 删除 C++client 的 pom.xml 里关于test相关的编译和运行操作,修改后的 pom 如下所示:
      
<?xml version="1.0" encoding="UTF-8"?>
<!--

    Licensed to the Apache Software Foundation (ASF) under one
    or more contributor license agreements.  See the NOTICE file
    distributed with this work for additional information
    regarding copyright ownership.  The ASF licenses this file
    to you under the Apache License, Version 2.0 (the
    "License"); you may not use this file except in compliance
    with the License.  You may obtain a copy of the License at

        http://www.apache.org/licenses/LICENSE-2.0

    Unless required by applicable law or agreed to in writing,
    software distributed under the License is distributed on an
    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
    KIND, either express or implied.  See the License for the
    specific language governing permissions and limitations
    under the License.

-->
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.apache.iotdb</groupId>
        <artifactId>iotdb-client</artifactId>
        <version>1.3.1-SNAPSHOT</version>
    </parent>
    <artifactId>client-cpp</artifactId>
    <packaging>pom</packaging>
    <name>IoTDB: Client: Client for CPP</name>
    <description>C++ client</description>
    <!-- TODO: The tests don't run, if distribution has not been built locally and fails without reasoning -->
    <properties>
        <catch2.url>https://alioss.timecho.com/upload/catch.hpp</catch2.url>
        <cmake.build.type>Release</cmake.build.type>
        <!-- Default value of cmake root -->
        <cmake.root.dir>${project.build.directory}/dependency/cmake/</cmake.root.dir>
        <thrift.exec.absolute.path>${project.build.directory}/thrift/bin/${thrift.executable}</thrift.exec.absolute.path>
    </properties>
    <dependencies>
        <dependency>
            <groupId>org.apache.iotdb</groupId>
            <artifactId>iotdb-thrift-commons</artifactId>
            <version>1.3.1-SNAPSHOT</version>
            <scope>provided</scope>
        </dependency>
    </dependencies>
    <build>
        <plugins>
            <!-- Build and do session integration test -->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-dependency-plugin</artifactId>
                <executions>
                    <execution>
                        <id>get-thrift</id>
                        <goals>
                            <goal>unpack</goal>
                        </goals>
                        <phase>generate-sources</phase>
                        <configuration>
                            <artifactItems>
                                <artifactItem>
                                    <groupId>org.apache.iotdb.tools</groupId>
                                    <artifactId>iotdb-tools-thrift</artifactId>
                                    <version>${iotdb-tools-thrift.version}</version>
                                    <classifier>${os.classifier}</classifier>
                                    <type>zip</type>
                                    <overWrite>true</overWrite>
                                    <outputDirectory>${project.build.directory}/thrift</outputDirectory>
                                </artifactItem>
                            </artifactItems>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>com.googlecode.maven-download-plugin</groupId>
                <artifactId>download-maven-plugin</artifactId>
                <executions>
                    <execution>
                        <id>get-catch2</id>
                        <goals>
                            <goal>wget</goal>
                        </goals>
                        <phase>generate-resources</phase>
                        <configuration>
                            <url>${catch2.url}</url>
                            <unpack>false</unpack>
                            <outputDirectory>${project.build.directory}/build/test/catch2</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>com.coderplus.maven.plugins</groupId>
                <artifactId>copy-rename-maven-plugin</artifactId>
                <executions>
                    <!-- TODO: Do this differently using the artifact downloader -->
                    <execution>
                        <id>copy-protocol-thrift-source</id>
                        <goals>
                            <goal>copy</goal>
                        </goals>
                        <configuration>
                            <fileSets>
                                <fileSet>
                                    <sourceFile>../../iotdb-protocol/thrift-datanode/src/main/thrift/client.thrift</sourceFile>
                                    <destinationFile>${project.build.directory}/protocols/client.thrift</destinationFile>
                                </fileSet>
                                <fileSet>
                                    <sourceFile>../../iotdb-protocol/thrift-commons/src/main/thrift/common.thrift</sourceFile>
                                    <destinationFile>${project.build.directory}/protocols/common.thrift</destinationFile>
                                </fileSet>
                            </fileSets>
                        </configuration>
                    </execution>
                    <!-- TODO: Do this differently using the maven-resources-plugin -->
                    <execution>
                        <!-- Copy source file and CmakeLists.txt into target directory -->
                        <id>copy-cmakelist-file</id>
                        <goals>
                            <goal>copy</goal>
                        </goals>
                        <phase>compile</phase>
                        <configuration>
                            <fileSets>
                                <fileSet>
                                    <sourceFile>${project.basedir}/src/main/CMakeLists.txt</sourceFile>
                                    <destinationFile>${project.build.directory}/build/main/CMakeLists.txt</destinationFile>
                                </fileSet>
                                <fileSet>
                                    <sourceFile>${project.basedir}/src/main/Session.h</sourceFile>
                                    <destinationFile>${project.build.directory}/build/main/generated-sources-cpp/Session.h</destinationFile>
                                </fileSet>
                                <fileSet>
                                    <sourceFile>${project.basedir}/src/main/Session.cpp</sourceFile>
                                    <destinationFile>${project.build.directory}/build/main/generated-sources-cpp/Session.cpp</destinationFile>
                                </fileSet>
                            </fileSets>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>org.apache.thrift.tools</groupId>
                <artifactId>maven-thrift-plugin</artifactId>
                <executions>
                    <execution>
                        <id>generate-thrift-sources-cpp</id>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                        <!-- Move from generate-sources to generate-resources to avoid double executions -->
                        <phase>generate-resources</phase>
                        <configuration>
                            <generator>cpp:no_skeleton</generator>
                            <thriftExecutable>${thrift.exec.absolute.path}</thriftExecutable>
                            <thriftSourceRoot>${project.build.directory}/protocols</thriftSourceRoot>
                            <outputDirectory>${project.build.directory}/build/main/generated-sources-cpp</outputDirectory>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
            <plugin>
                <groupId>com.googlecode.cmake-maven-project</groupId>
                <artifactId>cmake-maven-plugin</artifactId>
                <executions>
                    <!-- Uses a CMake generator to generate the build using the build tool of choice -->
                    <execution>
                        <id>cmake-generate</id>
                        <goals>
                            <goal>generate</goal>
                        </goals>
                        <phase>compile</phase>
                        <configuration>
                            <generator>${cmake.generator}</generator>
                            <sourcePath>${project.build.directory}/build/main</sourcePath>
                            <targetPath>${project.build.directory}/build/main</targetPath>
                            <options>
                                <option>-DBOOST_INCLUDEDIR=${boost.include.dir}</option>
                            </options>
                        </configuration>
                    </execution>
                    <!-- Generate Cmake build directory to compile testing program -->
                    <!-- Actually executes the build -->
                    <execution>
                        <id>cmake-compile</id>
                        <goals>
                            <goal>compile</goal>
                        </goals>
                        <phase>compile</phase>
                        <configuration>
                            <config>${cmake.build.type}</config>
                            <!-- The directory where the "generate" step generated the build configuration -->
                            <projectDirectory>${project.build.directory}/build/main</projectDirectory>
                        </configuration>
                    </execution>
                    <!-- Actually executes the testing compilation -->
                </executions>
            </plugin>
            <!--Package all C++ header files and client library-->
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-assembly-plugin</artifactId>
                <executions>
                    <execution>
                        <id>package-client-cpp</id>
                        <goals>
                            <goal>single</goal>
                        </goals>
                        <phase>package</phase>
                        <configuration>
                            <finalName>${project.artifactId}-${project.version}</finalName>
                            <descriptors>
                                <descriptor>src/assembly/client-cpp.xml</descriptor>
                            </descriptors>
                        </configuration>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
    <profiles>
        <profile>
            <id>.os-unix</id>
            <activation>
                <os>
                    <name>Linux</name>
                    <family>unix</family>
                    <arch>!aarch64</arch>
                </os>
            </activation>
            <properties>
                <iotdb.start.script>start-standalone.sh</iotdb.start.script>
                <iotdb.stop.script>stop-standalone.sh</iotdb.stop.script>
                <os.suffix>linux</os.suffix>
            </properties>
        </profile>
        <profile>
            <id>.os-unix-arm</id>
            <activation>
                <os>
                    <name>Linux</name>
                    <family>unix</family>
                    <arch>aarch64</arch>
                </os>
            </activation>
            <properties>
                <iotdb.start.script>start-standalone.sh</iotdb.start.script>
                <iotdb.stop.script>stop-standalone.sh</iotdb.stop.script>
                <os.suffix>linux</os.suffix>
            </properties>
        </profile>
        <profile>
            <id>.os-mac</id>
            <activation>
                <os>
                    <family>mac</family>
                    <arch>!aarch64</arch>
                </os>
            </activation>
            <properties>
                <iotdb.start.script>start-standalone.sh</iotdb.start.script>
                <iotdb.stop.script>stop-standalone.sh</iotdb.stop.script>
                <os.suffix>mac</os.suffix>
            </properties>
        </profile>
        <profile>
            <id>.os-mac-arm</id>
            <activation>
                <os>
                    <family>mac</family>
                    <arch>aarch64</arch>
                </os>
            </activation>
            <properties>
                <iotdb.start.script>start-standalone.sh</iotdb.start.script>
                <iotdb.stop.script>stop-standalone.sh</iotdb.stop.script>
                <os.suffix>mac</os.suffix>
            </properties>
        </profile>
        <profile>
            <id>.os-windows</id>
            <activation>
                <os>
                    <family>windows</family>
                </os>
            </activation>
            <properties>
                <iotdb.start.script>start-standalone.bat</iotdb.start.script>
                <iotdb.stop.script>stop-standalone.bat</iotdb.stop.script>
                <os.suffix>win</os.suffix>
            </properties>
        </profile>
    </profiles>
</project>
  • 再次执行 mvn clean package -P with-cpp -pl iotdb-client/client-cpp -am -DskipTests,成功build

基本接口说明

下面将给出 Session 接口的简要介绍和原型定义:

初始化

  • 开启 Session
void open(); 
  • 开启 Session,并决定是否开启 RPC 压缩
void open(bool enableRPCCompression); 

注意: 客户端的 RPC 压缩开启状态需和服务端一致。

  • 关闭 Session
void close(); 

数据定义接口(DDL)

Database 管理

  • 设置 database
void setStorageGroup(const std::string &storageGroupId);
  • 删除单个或多个 database
void deleteStorageGroup(const std::string &storageGroup);
void deleteStorageGroups(const std::vector<std::string> &storageGroups);

时间序列管理

  • 创建单个或多个非对齐时间序列
void createTimeseries(const std::string &path, TSDataType::TSDataType dataType, TSEncoding::TSEncoding encoding,
                          CompressionType::CompressionType compressor);
                          
void createMultiTimeseries(const std::vector<std::string> &paths,
                           const std::vector<TSDataType::TSDataType> &dataTypes,
                           const std::vector<TSEncoding::TSEncoding> &encodings,
                           const std::vector<CompressionType::CompressionType> &compressors,
                           std::vector<std::map<std::string, std::string>> *propsList,
                           std::vector<std::map<std::string, std::string>> *tagsList,
                           std::vector<std::map<std::string, std::string>> *attributesList,
                           std::vector<std::string> *measurementAliasList);
  • 创建对齐时间序列
void createAlignedTimeseries(const std::string &deviceId,
                             const std::vector<std::string> &measurements,
                             const std::vector<TSDataType::TSDataType> &dataTypes,
                             const std::vector<TSEncoding::TSEncoding> &encodings,
                             const std::vector<CompressionType::CompressionType> &compressors);
  • 删除一个或多个时间序列
void deleteTimeseries(const std::string &path);
void deleteTimeseries(const std::vector<std::string> &paths);
  • 检查时间序列是否存在
bool checkTimeseriesExists(const std::string &path);

元数据模版

  • 创建元数据模板
void createSchemaTemplate(const Template &templ);
  • 挂载元数据模板
void setSchemaTemplate(const std::string &template_name, const std::string &prefix_path);

请注意,如果一个子树中有多个孩子节点需要使用模板,可以在其共同父母节点上使用 setSchemaTemplate 。而只有在已有数据点插入模板对应的物理量时,模板才会被设置为激活状态,进而被 show timeseries 等查询检测到。

  • 卸载元数据模板
void unsetSchemaTemplate(const std::string &prefix_path, const std::string &template_name);

注意:目前不支持从曾经在prefixPath路径及其后代节点使用模板插入数据后(即使数据已被删除)卸载模板。

  • 在创建概念元数据模板以后,还可以通过以下接口增加或删除模板内的物理量。请注意,已经挂载的模板不能删除内部的物理量。
// 为指定模板新增一组对齐的物理量,若其父节点在模板中已经存在,且不要求对齐,则报错
void addAlignedMeasurementsInTemplate(const std::string &template_name,
                                      const std::vector<std::string> &measurements,
                                      const std::vector<TSDataType::TSDataType> &dataTypes,
                                      const std::vector<TSEncoding::TSEncoding> &encodings,
                                      const std::vector<CompressionType::CompressionType> &compressors);

// 为指定模板新增一个对齐物理量, 若其父节点在模板中已经存在,且不要求对齐,则报错
void addAlignedMeasurementsInTemplate(const std::string &template_name,
                                      const std::string &measurement,
                                      TSDataType::TSDataType dataType,
                                      TSEncoding::TSEncoding encoding,
                                      CompressionType::CompressionType compressor);

// 为指定模板新增一个不对齐物理量, 若其父节在模板中已经存在,且要求对齐,则报错
void addUnalignedMeasurementsInTemplate(const std::string &template_name,
                                        const std::vector<std::string> &measurements,
                                        const std::vector<TSDataType::TSDataType> &dataTypes,
                                        const std::vector<TSEncoding::TSEncoding> &encodings,
                                        const std::vector<CompressionType::CompressionType> &compressors);

// 为指定模板新增一组不对齐的物理量, 若其父节在模板中已经存在,且要求对齐,则报错
void addUnalignedMeasurementsInTemplate(const std::string &template_name,
                                        const std::string &measurement,
                                        TSDataType::TSDataType dataType,
                                        TSEncoding::TSEncoding encoding,
                                        CompressionType::CompressionType compressor);

// 从指定模板中删除一个节点及其子树
void deleteNodeInTemplate(const std::string &template_name, const std::string &path);
  • 对于已经创建的元数据模板,还可以通过以下接口查询模板信息:
// 查询返回目前模板中所有物理量的数量
int countMeasurementsInTemplate(const std::string &template_name);

// 检查模板内指定路径是否为物理量
bool isMeasurementInTemplate(const std::string &template_name, const std::string &path);

// 检查在指定模板内是否存在某路径
bool isPathExistInTemplate(const std::string &template_name, const std::string &path);

// 返回指定模板内所有物理量的路径
std::vector<std::string> showMeasurementsInTemplate(const std::string &template_name);

// 返回指定模板内某前缀路径下的所有物理量的路径
std::vector<std::string> showMeasurementsInTemplate(const std::string &template_name, const std::string &pattern);

数据操作接口(DML)

数据写入

推荐使用 insertTablet 帮助提高写入效率。

  • 插入一个 Tablet,Tablet 是一个设备若干行数据块,每一行的列都相同。
    • 写入效率高。
    • 支持写入空值:空值处可以填入任意值,然后通过 BitMap 标记空值。
void insertTablet(Tablet &tablet);
  • 插入多个 Tablet
void insertTablets(std::unordered_map<std::string, Tablet *> &tablets);
  • 插入一个 Record,一个 Record 是一个设备一个时间戳下多个测点的数据
void insertRecord(const std::string &deviceId, int64_t time, const std::vector<std::string> &measurements,
                  const std::vector<TSDataType::TSDataType> &types, const std::vector<char *> &values);
  • 插入多个 Record
void insertRecords(const std::vector<std::string> &deviceIds,
                   const std::vector<int64_t> &times,
                   const std::vector<std::vector<std::string>> &measurementsList,
                   const std::vector<std::vector<TSDataType::TSDataType>> &typesList,
                   const std::vector<std::vector<char *>> &valuesList);
  • 插入同属于一个 device 的多个 Record
void insertRecordsOfOneDevice(const std::string &deviceId,
                              std::vector<int64_t> &times,
                              std::vector<std::vector<std::string>> &measurementsList,
                              std::vector<std::vector<TSDataType::TSDataType>> &typesList,
                              std::vector<std::vector<char *>> &valuesList);

带有类型推断的写入

服务器需要做类型推断,可能会有额外耗时,速度较无需类型推断的写入慢。

void insertRecord(const std::string &deviceId, int64_t time, const std::vector<std::string> &measurements,
                  const std::vector<std::string> &values);


void insertRecords(const std::vector<std::string> &deviceIds,
                   const std::vector<int64_t> &times,
                   const std::vector<std::vector<std::string>> &measurementsList,
                   const std::vector<std::vector<std::string>> &valuesList);


void insertRecordsOfOneDevice(const std::string &deviceId,
                              std::vector<int64_t> &times,
                              std::vector<std::vector<std::string>> &measurementsList,
                              const std::vector<std::vector<std::string>> &valuesList);

对齐时间序列写入

对齐时间序列的写入使用 insertAlignedXXX 接口,其余与上述接口类似:

  • insertAlignedRecord
  • insertAlignedRecords
  • insertAlignedRecordsOfOneDevice
  • insertAlignedTablet
  • insertAlignedTablets

数据删除

  • 删除一个或多个时间序列在某个时间点前或这个时间点的数据
void deleteData(const std::string &path, int64_t time);
void deleteData(const std::vector<std::string> &deviceId, int64_t time);

IoTDB-SQL 接口

  • 执行查询语句
void executeNonQueryStatement(const std::string &sql);
  • 执行非查询语句
void executeNonQueryStatement(const std::string &sql);

示例代码

示例工程源代码:

  • example/client-cpp-example/src/SessionExample.cpp
  • example/client-cpp-example/src/AlignedTimeseriesSessionExample.cpp (使用对齐时间序列)

编译成功后,示例代码工程位于 example/client-cpp-example/target

FAQ

Thrift 编译相关问题

  1. MAC:本地 Maven 编译 Thrift 时如出现以下链接的问题,可以尝试将 xcode-commandline 版本从 12 降低到 11.5
    https://stackoverflow.com/questions/63592445/ld-unsupported-tapi-file-type-tapi-tbd-in-yaml-file/65518087#65518087open in new window

  2. Windows:Maven 编译 Thrift 时需要使用 wget 下载远端文件,可能出现以下报错:

    Failed to delete cached file C:\Users\Administrator\.m2\repository\.cache\download-maven-plugin\index.ser
    

    解决方法:

    • 尝试删除 ".m2\repository\.cache" 目录并重试。
    • 在添加 pom 文件对应的 download-maven-plugin 中添加 "<skipCache>true</skipCache>"

Copyright © 2024 The Apache Software Foundation.
Apache IoTDB, IoTDB, Apache, the Apache feather logo, and the Apache IoTDB project logo are either registered trademarks or trademarks of The Apache Software Foundation in all countries

Have a question? Connect with us on QQ, WeChat, or Slack. Join the community now.