CritasWang opened a new pull request, #62:
URL: https://github.com/apache/iotdb-client-csharp/pull/62

   Fixes #61
   
   ## What this fixes / 修复内容
   
   A `SessionPool` that outlived a server outage became permanently unusable: 
callers blocked forever with no
   exception, and the pool could not recover even after the server came back. 
Two independent defects combined
   to produce that.
   
   服务端断开后,`SessionPool` 会变得永久不可用:调用方永久阻塞且不抛异常,服务端恢复后也无法自愈。这是
   两个独立缺陷叠加的结果。
   
   ### 1. Pool wait timeout was written in ms and read in seconds / 池等待超时的单位错误
   
   `Open()` assigned `_clients.Timeout = _timeout * 5` (a millisecond value) 
while
   `ConcurrentClientQueue.Take()` consumed it via `TimeSpan.FromSeconds`. The 
500 ms default connection timeout
   therefore produced a **~41 minute** block before 
`SessionPoolDepletedException` surfaced; the legacy
   `timeout: 10000` constructor argument produced **13.9 hours**.
   
   `Open()` 以毫秒赋值而 `Take()` 按秒消费,500ms 的默认连接超时因此变成约 **41 分钟** 的阻塞,旧构造函数
   传 `timeout: 10000` 时更是 **13.9 小时**。
   
   - `ConcurrentClientQueue` now exposes `TimeoutInMs` and waits with 
`TimeSpan.FromMilliseconds`.
     `ConcurrentClientQueue` 改用 `TimeoutInMs`,并以 `TimeSpan.FromMilliseconds` 等待。
   - The old seconds-based `Timeout` property is kept as an `[Obsolete]` shim 
so existing callers still compile
     and behave as they intended.
     原秒级 `Timeout` 属性保留为 `[Obsolete]` 兼容包装,既有调用方仍可编译且语义符合预期。
   - The pool wait budget is no longer derived from the socket timeout. It is 
configurable via
     `SetPoolWaitTimeoutInMs` on both builders, defaulting to 10 s.
     池等待时间不再由 socket 超时推导,改为两个 Builder 上的 `SetPoolWaitTimeoutInMs`,默认 10 秒。
   
   ### 2. Pool slots leaked on every failed reconnection / 重连失败导致槽位泄漏
   
   When reconnection failed, the dead client was discarded without being 
returned and nothing replenished the
   pool, so capacity shrank by one per failure. After `PoolSize` failures every 
caller blocked on an empty queue
   that nobody would ever feed, and the pool stayed dead after the server 
recovered.
   
   重连失败时失效连接被丢弃且不归还,池无补充机制,每失败一次容量减一;`PoolSize` 次失败后所有调用都阻塞在
   无人投喂的空队列上,服务端恢复后连接池依然是死的。
   
   - Vacant slots are now tracked (`_vacantSlots`, surfaced as 
`SessionPool.VacantSlots`) instead of being
     silently dropped, so capacity stays at `PoolSize`.
     改为记录空槽(`_vacantSlots`,通过 `SessionPool.VacantSlots` 暴露),容量保持为 `PoolSize`。
   - `AcquireClientAsync` re-materializes a vacant slot when the queue is 
empty, so the pool heals itself on the
     next operation once the server is reachable — no `Close()` + `Open()` 
cycle needed.
     队列为空时 `AcquireClientAsync` 会就地重建空槽,服务端恢复后下一次操作即可自愈,无需 `Close()` + `Open()`。
   - `Reconnect()` now accepts a null original client so the self-heal path 
also works with `nodeUrls`
     (multi-node) configurations.
     `Reconnect()` 允许原始连接为 null,使 `nodeUrls`(多节点)配置下的自愈路径同样可用。
   
   ### 3. `IsOpen()` semantics documented / 明确 `IsOpen()` 语义
   
   `IsOpen()` is a lifecycle flag, not a connectivity probe — the client keeps 
no heartbeat, so it stays `true`
   after the server goes down. Behaviour is unchanged (and matches the Java 
client); this PR only documents it,
   because the guard `if (pool.IsOpen()) return;` is a common way to 
accidentally prevent a pool from ever being
   rebuilt.
   
   `IsOpen()` 是生命周期标志而非连通性探针——客户端无心跳,服务端断开后它仍为 `true`。行为未变(与 Java
   客户端一致),本 PR 仅补充文档说明,因为 `if (pool.IsOpen()) return;` 这种守卫很容易让连接池永远不被重建。
   
   ## Compatibility / 兼容性
   
   No breaking changes. New constructor overloads take the pool wait timeout as 
an extra parameter and the
   existing overloads delegate to them with the default; 
`ConcurrentClientQueue.Timeout` still compiles and now
   converts to/from `TimeoutInMs`.
   
   无破坏性变更。新增的构造函数重载多接收一个池等待超时参数,原有重载以默认值委托到新重载;
   `ConcurrentClientQueue.Timeout` 仍可编译,并与 `TimeoutInMs` 相互换算。
   
   Behavioural change worth calling out: a depleted pool now fails after 10 s 
by default instead of tens of
   minutes. Anyone who (unintentionally) relied on the long wait should set 
`SetPoolWaitTimeoutInMs` explicitly.
   
   需要注意的行为变化:池耗尽时现在默认 10 秒后失败,而不是数十分钟。若有人(无意中)依赖了原来的长等待,
   请显式设置 `SetPoolWaitTimeoutInMs`。
   
   ## Tests / 测试
   
   - `ConcurrentClientQueueTests` — timeout is honoured in milliseconds (the 
direct regression guard), the
     message reports the unit, `Return()` wakes a blocked `Take()`, a ready 
client is returned without waiting,
     and the obsolete `Timeout` shim converts correctly.
     `ConcurrentClientQueueTests` —— 超时按毫秒生效(针对该 bug 的直接回归测试)、异常消息标注单位、
     `Return()` 能唤醒阻塞的 `Take()`、有可用连接时立即返回、过时的 `Timeout` 兼容属性换算正确。
   - `SessionPoolConfigurationTests` — the pool wait timeout is independent of 
the connection timeout and is
     propagated by both `SessionPool.Builder` (host/port and nodeUrls paths) 
and `TableSessionPool.Builder`.
     `SessionPoolConfigurationTests` —— 池等待超时与连接超时相互独立,且能被 `SessionPool.Builder`
     (host/port 与 nodeUrls 两条路径)和 `TableSessionPool.Builder` 正确传递。
   
   `dotnet test tests/Apache.IoTDB.Tests` — 33 passed, 0 failed. `dotnet build 
Apache.IoTDB.sln` — 0 errors.
   `dotnet format --verify-no-changes` — clean.
   
   Note: the unit tests were executed locally against `net8.0` because no .NET 
5 arm64 runtime is available on
   this machine; the committed `TargetFramework` is unchanged at `net5.0`.
   说明:本机没有 .NET 5 的 arm64 运行时,单元测试在本地以 `net8.0` 执行;提交的 `TargetFramework` 仍为 
`net5.0`。
   
   ## Docs / 文档
   
   - `docs/SessionPool_Exception_Handling.md` — new sections on `IsOpen()` 
semantics and the pool wait timeout,
     `VacantSlots` added to the health metrics table, self-healing behaviour 
described, and the stale builder
     API names in the examples corrected (`.Host()` → `.SetHost()`, 
`.Timeout()` → `.SetConnectionTimeoutInMs()`,
     etc., which did not compile as written).
     `docs/SessionPool_Exception_Handling.md` —— 新增 `IsOpen()` 
语义与池等待超时章节,健康指标表补充
     `VacantSlots`,说明自愈行为,并修正示例中过时的 Builder API 名(原样无法编译)。
   - `docs/API.md` — clarified the `IsOpen` row.
     `docs/API.md` —— 澄清 `IsOpen` 一行的说明。
   


-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to