Skip to content

Fix RpcDataSet deadlock, timezone compatibility, column index issues, and deprecation cleanup#48

Open
CritasWang wants to merge 1 commit intomainfrom
fix/rpc-dataset-issues
Open

Fix RpcDataSet deadlock, timezone compatibility, column index issues, and deprecation cleanup#48
CritasWang wants to merge 1 commit intomainfrom
fix/rpc-dataset-issues

Conversation

@CritasWang
Copy link
Contributor

Summary / 概述

Fix four bugs in the C# client library and clean up all deprecated API usages in samples.

修复 C# 客户端库中的四个 Bug,并清理示例代码中所有已废弃 API 的使用。

Bug Fixes / Bug 修复

1. RpcDataSet.Next() deadlock / RpcDataSet.Next() 死锁

Next() internally called Close().Wait() and FetchResults() with synchronous blocking, which causes deadlocks when the underlying Thrift async calls capture a synchronization context.

Next() 内部通过 Close().Wait()FetchResults() 进行同步阻塞调用,当底层 Thrift 异步调用捕获同步上下文时会导致死锁。

Fix: Added NextAsync() and FetchResultsAsync() as proper async methods. The old Next() is preserved but marked [Obsolete] for backward compatibility. Added HasNextAsync() to SessionDataSet.

修复: 新增 NextAsync()FetchResultsAsync() 作为正确的异步方法。旧的 Next() 保留但标记为 [Obsolete] 以保证向后兼容。在 SessionDataSet 上新增 HasNextAsync()

2. GetDate("Time") index out of range / GetDate("Time") 索引越界

When calling GetDate("Time") or GetInt("Time"), the TsBlock column index resolves to -1 (the special timestamp marker), but GetDateByTsBlockColumnIndex and GetIntByTsBlockColumnIndex did not handle this case.

调用 GetDate("Time")GetInt("Time") 时,TsBlock 列索引解析为 -1(时间戳特殊标记),但 GetDateByTsBlockColumnIndexGetIntByTsBlockColumnIndex 未处理此情况。

Fix: Added -1 index handling to return the timestamp value from _curTsBlock.GetTimeByIndex().

修复: 添加了 -1 索引处理,从 _curTsBlock.GetTimeByIndex() 返回时间戳值。

3. TimeZoneNotFoundException on Windows / Windows 上时区异常

SessionPool.Builder defaults zoneId to "Asia/Shanghai" (IANA format), but TimeZoneInfo.FindSystemTimeZoneById() on Windows expects Windows timezone IDs like "China Standard Time", causing TimeZoneNotFoundException.

SessionPool.Builder 默认 zoneId"Asia/Shanghai"(IANA 格式),但 Windows 上的 TimeZoneInfo.FindSystemTimeZoneById() 期望 Windows 时区 ID(如 "China Standard Time"),导致 TimeZoneNotFoundException

Fix: Added FindTimeZoneSafe() with an IANA-to-Windows timezone mapping dictionary as fallback.

修复: 新增 FindTimeZoneSafe() 方法,内置 IANA 到 Windows 时区映射字典作为回退。

4. RowRecord obsolete constructor / RowRecord 废弃构造函数

RpcDataSet.GetRow() and IoTDBCommand.BindParamters() used the deprecated RowRecord(long, List<object>, List<string>) constructor without TSDataType information.

RpcDataSet.GetRow()IoTDBCommand.BindParamters() 使用了不带 TSDataType 信息的废弃构造函数 RowRecord(long, List<object>, List<string>)

Fix: Both now collect List<TSDataType> and use the 4-arg constructor.

修复: 两处均改为收集 List<TSDataType> 并使用 4 参数构造函数。

Deprecation Cleanup / 废弃 API 清理

  • Migrated all new SessionPool(host, port, poolSize) to SessionPool.Builder pattern across all sample files

  • Migrated all new RowRecord(timestamp, values, measures) to 4-arg constructor with List<TSDataType> across all sample files

  • Updated all HasNext() calls to await HasNextAsync() in samples

  • Added #pragma warning disable CS0618 in IoTDBDataReader where sync HasNext() is required by the ADO.NET DbDataReader.Read() interface

  • 将所有示例文件中的 new SessionPool(host, port, poolSize) 迁移为 SessionPool.Builder 模式

  • 将所有示例文件中的 new RowRecord(timestamp, values, measures) 迁移为带 List<TSDataType> 的 4 参数构造函数

  • 将示例中所有 HasNext() 调用更新为 await HasNextAsync()

  • IoTDBDataReader 中因 ADO.NET DbDataReader.Read() 接口要求同步调用,添加了 #pragma warning disable CS0618

Files Changed / 变更文件

Library / 库代码:

  • src/Apache.IoTDB/DataStructure/RpcDataSet.cs — async methods, timezone fix, column index fix, GetRow fix
  • src/Apache.IoTDB/DataStructure/SessionDataSet.cs — HasNextAsync()
  • src/Apache.IoTDB/SessionPool.cs — use HasNextAsync() in CheckTimeSeriesExistsAsync
  • src/Apache.IoTDB.Data/IoTDBCommand.cs — RowRecord with TSDataType
  • src/Apache.IoTDB.Data/IoTDBDataReader.cs — pragma suppress for sync HasNext()

Samples / 示例代码:

  • All SessionPoolTest.*.cs files — Builder pattern, RowRecord 4-arg, HasNextAsync
  • TableSessionPoolTest.cs, SessionPoolTest.Utils.cs — HasNextAsync
  • Apache-IoTDB-Client-CSharp-UserCase/Program.cs — HasNextAsync

link: #47

- Add async NextAsync()/FetchResultsAsync() to RpcDataSet, mark sync Next() as obsolete
- Add HasNextAsync() to SessionDataSet for non-blocking iteration
- Fix TimeZoneNotFoundException by adding IANA-to-Windows timezone mapping
- Fix GetDateByTsBlockColumnIndex/GetIntByTsBlockColumnIndex for Time column (index -1)
- Fix RowRecord obsolete constructor usage in RpcDataSet.GetRow() and IoTDBCommand
- Migrate all samples from deprecated SessionPool(host,port,poolSize) to Builder pattern
- Migrate all samples from deprecated RowRecord 3-arg constructor to 4-arg with TSDataType
@CritasWang CritasWang requested review from HTHou and lausannel and removed request for HTHou February 26, 2026 08:47
@HTHou HTHou requested a review from Copilot February 26, 2026 09:34
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR addresses four critical bugs in the C# IoTDB client library and modernizes all sample code to use non-deprecated APIs. The changes resolve deadlock issues in asynchronous operations, fix timezone compatibility problems on Windows, correct column index handling for timestamp fields, and ensure proper type information is passed when constructing RowRecord objects.

Changes:

  • Fixed RpcDataSet.Next() deadlock by introducing proper async methods (NextAsync(), FetchResultsAsync(), HasNextAsync())
  • Added timezone compatibility layer to handle IANA/Windows timezone ID differences
  • Fixed -1 column index handling for timestamp fields in GetDate() and GetInt() methods
  • Updated RowRecord constructor calls throughout to include TSDataType information

Reviewed changes

Copilot reviewed 16 out of 16 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
src/Apache.IoTDB/SessionPool.cs Updated to use new HasNextAsync() method
src/Apache.IoTDB/DataStructure/SessionDataSet.cs Added HasNextAsync() and marked sync HasNext() as obsolete
src/Apache.IoTDB/DataStructure/RpcDataSet.cs Implemented async methods, timezone mapping, timestamp column index fix, and RowRecord constructor update
src/Apache.IoTDB.Data/IoTDBDataReader.cs Added pragma directives to suppress obsolete warnings for required sync calls
src/Apache.IoTDB.Data/IoTDBCommand.cs Updated BindParamters() to collect and pass TSDataType list
samples/Apache.IoTDB.Samples/*.cs Migrated all sample code to use Builder pattern, 4-arg RowRecord constructor, and HasNextAsync()
Apache-IoTDB-Client-CSharp-UserCase/Program.cs Updated to use HasNextAsync()

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +632 to +633
List<string> measurementList = new List<string>();
List<TSDataType> dataTypeList = new List<TSDataType>();
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

These two new lists are populated inside the loop but only when localfield != null. If the loop encounters null fields, the lists will have mismatched lengths compared to fieldList, which could lead to incorrect RowRecord construction. Consider adding corresponding entries for null fields or document why this is safe.

Copilot uses AI. Check for mistakes.
}
}

return TimeZoneInfo.Local;
Copy link

Copilot AI Feb 26, 2026

Choose a reason for hiding this comment

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

Falling back to TimeZoneInfo.Local when the requested timezone cannot be found may lead to incorrect time conversions. Consider throwing a more informative exception or logging a warning to alert users that their specified timezone could not be resolved.

Suggested change
return TimeZoneInfo.Local;
throw new TimeZoneNotFoundException($"The specified time zone ID '{zoneId}' could not be found on this system.");

Copilot uses AI. Check for mistakes.
break;
case TSDataType.TIMESTAMP:
localfield = null;
timestamp = GetLong(columnName);

Choose a reason for hiding this comment

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

timestamp in initialize RowRecord is not valid because it accepts any column of the timestamp type. If the data contains another column of the timestamp type, an error will occur.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants