close
Skip to content

[Feature] [Connector-V2] [IoTDB] Added source and sink connectors to support IoTDB 2.X#9872

Merged
davidzollo merged 25 commits into
apache:devfrom
LJW21-02:dev
Oct 10, 2025
Merged

[Feature] [Connector-V2] [IoTDB] Added source and sink connectors to support IoTDB 2.X#9872
davidzollo merged 25 commits into
apache:devfrom
LJW21-02:dev

Conversation

@LJW21-02

Copy link
Copy Markdown
Contributor

Purpose of this pull request

This pull request adds both source and sink connectors to support IoTDB version >= 2.X.

Does this PR introduce any user-facing change?

No

How was this patch tested?

e2e tests

Check list

@github-actions github-actions Bot removed the Zeta label Sep 18, 2025
Comment thread docs/zh/connector-v2/source/IoTDBv2.md Outdated

| 数据源 | 支持的版本 | 地址 |
|-------|------------------------------|----------------|
| IoTDB | `0.13.0 <= version <= 1.3.X` | localhost:6667 |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is incorrect

sinkConfig.setEnableRPCCompression(
pluginConfig.get(IoTDBSinkOptions.ENABLE_RPC_COMPRESSION));
if (pluginConfig.getOptional(IoTDBSinkOptions.CONNECTION_TIMEOUT_IN_MS).isPresent()) {
checkNotNull(sinkConfig.getEnableRPCCompression());

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why check here?


try {
if (session != null) {
session.close();

@zhangshenghang zhangshenghang Sep 19, 2025

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

flush method exception, which can result in the inability to shut down resources

@LJW21-02

Copy link
Copy Markdown
Contributor Author

@zhangshenghang Hi, thank you for your review and suggestions! I’ve addressed the changes. Could you please take another look?

} else {
session.insertRecords(
batchRecords.getDeviceIds(),
batchRecords.getTimestamps(),

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should there be a break in this for clause?

@davidzollo

davidzollo commented Sep 19, 2025

Copy link
Copy Markdown
Contributor

Please paste the result picture of your local running to check the accuracy. For example, using this task config file seatunnel-e2e/seatunnel-connector-v2-e2e/connector-iotdb-v2-e2e/src/test/resources/iotdb/iotdb_source_to_sink_table.conf, then you can check whether the count is the same between the sink side and the source side. You can use a small dataset to check.

@LJW21-02

Copy link
Copy Markdown
Contributor Author

@zhangshenghang Hi! All the checks have passed.

Comment thread docs/en/connector-v2/source/IoTDBv2.md Outdated
| thrift_default_buffer_size | int | No | - | The thrift_default_buffer_size of the IoTDB when you select |
| thrift_max_frame_size | int | No | - | The thrift max frame size |
| enable_cache_leader | boolean | No | - | Enable_cache_leader of the IoTDB when you select |
| version | string | No | - | SQL semantic version used by the client, The possible values are: `V_0_12`, `V_0_13` |

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does V2 still works fine in V_0_12, V_0_13? Please check

Comment thread docs/en/connector-v2/source/IoTDBv2.md Outdated

> IoTDB 数据接收器

## 描述

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please describe the supported engine.

@LJW21-02

Copy link
Copy Markdown
Contributor Author

@davidzollo @zhangshenghang Hi! Thank you for the feedback! I've implemented all the suggested changes and passed all the checks. Please review when you have a moment.

@Hisoka-X

Copy link
Copy Markdown
Member

I am a little confused. Why is iotdb v2 a separate connector? Can't the original connector directly upgrade its dependencies to be compatible with v2?

Comment on lines +216 to +231
for (int reader : readers) {
List<IoTDBv2SourceSplit> assignmentForReader = pendingSplit.remove(reader);
if (assignmentForReader != null && !assignmentForReader.isEmpty()) {
log.info("Assign splits {} to reader {}", assignmentForReader, reader);
try {
context.assignSplit(reader, assignmentForReader);
} catch (Exception e) {
log.error(
"Failed to assign splits {} to reader {}",
assignmentForReader,
reader,
e);
pendingSplit.put(reader, assignmentForReader);
}
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

synchronized (stateLock) {
...
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this enumerator class, please guard every access to pendingSplit/shouldEnumerate with the same stateLock—wrap addPendingSplit, assignSplit, addSplitsBack, registerReader, and currentUnassignedSplitSize in that lock

Comment on lines +205 to +210
int readerCount = context.currentParallelism();
for (IoTDBv2SourceSplit split : splits) {
int ownerReader = getSplitOwner(split.splitId(), readerCount);
log.info("Assigning {} to {} reader.", split, ownerReader);
pendingSplit.computeIfAbsent(ownerReader, r -> new ArrayList<>()).add(split);
}

@davidzollo davidzollo Sep 27, 2025

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

pendingSplit is a competitive resource and should be locked,
synchronized (stateLock) {
...
}

@LJW21-02

Copy link
Copy Markdown
Contributor Author

I am a little confused. Why is iotdb v2 a separate connector? Can't the original connector directly upgrade its dependencies to be compatible with v2?

Hi @Hisoka-X ! We use a separate connector because each of them supports different IoTDB version, which also requires different dependency to handle things differently.


private ITableSession buildTableSession(ReadonlyConfig conf) throws IoTDBConnectionException {
TableSessionBuilder sessionBuilder = new TableSessionBuilder().enableCompression(false);
String nodeUrlsString = conf.get(NODE_URLS);

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should not be String; it should be List

Comment thread docs/zh/connector-v2/source/IoTDBv2.md Outdated

| 名称 | 类型 | 是否必填 | 默认值 | 描述 |
|----------------------------|---------|------|------|----------------------------------------------------------------------------------|
| node_urls | string | 是 | - | IoTDB 集群地址,格式为 `"host1:port"` 或 `"host1:port,host2:port"` |

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It should not be String; it should be List, and all other related parts should be modified.

@zhangshenghang

Copy link
Copy Markdown
Member

I am a little confused. Why is iotdb v2 a separate connector? Can't the original connector directly upgrade its dependencies to be compatible with v2?

Hi @Hisoka-X ! We use a separate connector because each of them supports different IoTDB version, which also requires different dependency to handle things differently.

While review the code, I found that a lot of the code is duplicated with the existing code. Can it be optimized? @Hisoka-X @LJW21-02

@Hisoka-X

Copy link
Copy Markdown
Member

Can it be optimized?

+1

Comment on lines +39 to +43
<dependency>
<groupId>com.timecho.iotdb</groupId>
<artifactId>shade-iotdb-session</artifactId>
<version>2.0.6.1</version>
</dependency>

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is shade-iotdb-session not backward compatible?

@LJW21-02

Copy link
Copy Markdown
Contributor Author

@zhangshenghang Thank you again for the review suggestions! I've made all the changes mentioned above, and the code now passes all tests.

@Hisoka-X Hisoka-X left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does V1 have many users? Can we just remove it? After all, we can't support it forever.

@zhangshenghang

Copy link
Copy Markdown
Member

Does V1 have many users? Can we just remove it? After all, we can't support it forever.

Please take a look at this problem。@LJW21-02

I have no other questions.

@LJW21-02

LJW21-02 commented Oct 9, 2025

Copy link
Copy Markdown
Contributor Author

Hi @Hisoka-X ! Since V1 and V2 are not compatible and some users still rely on V1, we'd recommend keeping it for now to avoid potential issues for existing users.

@CritasWang

Copy link
Copy Markdown

V1 有很多用户吗?我们可以删除它吗?毕竟,我们不能永远支持它。

我们可以考虑在 Apache IoTDB 1.x 版本不再维护一段时间后移除它,但当前来说(至少 1 年内)它应该都会继续维护

@davidzollo davidzollo left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

+1


@Override
public int currentUnassignedSplitSize() {
return pendingSplit.size();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

synchronized (stateLock) {
...
}

Comment on lines +199 to +201
if (!pendingSplit.isEmpty()) {
assignSplit(Collections.singletonList(subtaskId));
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

synchronized (stateLock) {
...
}

Comment on lines +216 to +231
for (int reader : readers) {
List<IoTDBv2SourceSplit> assignmentForReader = pendingSplit.remove(reader);
if (assignmentForReader != null && !assignmentForReader.isEmpty()) {
log.info("Assign splits {} to reader {}", assignmentForReader, reader);
try {
context.assignSplit(reader, assignmentForReader);
} catch (Exception e) {
log.error(
"Failed to assign splits {} to reader {}",
assignmentForReader,
reader,
e);
pendingSplit.put(reader, assignmentForReader);
}
}
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In this enumerator class, please guard every access to pendingSplit/shouldEnumerate with the same stateLock—wrap addPendingSplit, assignSplit, addSplitsBack, registerReader, and currentUnassignedSplitSize in that lock

@davidzollo davidzollo merged commit 6b7db1e into apache:dev Oct 10, 2025
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants