MAC
安装 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
安装 Boost :确保安装较新的 Boost 版本。
brew install boost
brew link boost
检查 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
构建编译环境
下载安装 Flex、Bison
安装 Boost
安装 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
-Dcmake.generator=""选项来指定使用的生成器名称,例如: -Dcmake.generator="Visual Studio 16 2019"。(通过cmake --help命令可以查看 CMake 支持的生成器列表)-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:编译报错undefined reference to '_libc_sinle_thread'如何处理?
A:
<?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>
下面将给出 Session 接口的简要介绍和原型定义:
void open();
void open(bool enableRPCCompression);
注意: 客户端的 RPC 压缩开启状态需和服务端一致。
void close();
void setStorageGroup(const std::string &storageGroupId);
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);
推荐使用 insertTablet 帮助提高写入效率。
void insertTablet(Tablet &tablet);
void insertTablets(std::unordered_map<std::string, Tablet *> &tablets);
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);
void insertRecords(const std::vector<std::string> &deviceIds, const std::vector<int64_t> ×, const std::vector<std::vector<std::string>> &measurementsList, const std::vector<std::vector<TSDataType::TSDataType>> &typesList, const std::vector<std::vector<char *>> &valuesList);
void insertRecordsOfOneDevice(const std::string &deviceId, std::vector<int64_t> ×, 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> ×, 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> ×, std::vector<std::vector<std::string>> &measurementsList, const std::vector<std::vector<std::string>> &valuesList);
对齐时间序列的写入使用 insertAlignedXXX 接口,其余与上述接口类似:
void deleteData(const std::string &path, int64_t time); void deleteData(const std::vector<std::string> &deviceId, int64_t time);
void executeNonQueryStatement(const std::string &sql);
void executeNonQueryStatement(const std::string &sql);
示例工程源代码:
example/client-cpp-example/src/SessionExample.cppexample/client-cpp-example/src/AlignedTimeseriesSessionExample.cpp (使用对齐时间序列)编译成功后,示例代码工程位于 example/client-cpp-example/target
MAC:本地 Maven 编译 Thrift 时如出现以下链接的问题,可以尝试将 xcode-commandline 版本从 12 降低到 11.5 https://stackoverflow.com/questions/63592445/ld-unsupported-tapi-file-type-tapi-tbd-in-yaml-file/65518087#65518087
Windows:Maven 编译 Thrift 时需要使用 wget 下载远端文件,可能出现以下报错:
Failed to delete cached file C:\Users\Administrator\.m2\repository\.cache\download-maven-plugin\index.ser
解决方法: