Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
34 commits
Select commit Hold shift + click to select a range
2f51c16
refactor(consul)!: adopt typed plugin construction
nick2781 Oct 26, 2026
fc9035a
fix(hash)!: standardize Murmur digests and retain legacy MSVC access
nick2781 Oct 26, 2026
d8b3a61
test(hash): isolate standalone Murmur header checks
nick2781 Oct 26, 2026
b794cfc
test(consul): exercise construction across application jobs
nick2781 Oct 26, 2026
87e24d4
docs(hash): distinguish affected routing consumers
nick2781 Oct 26, 2026
c9bdebe
chore(consul): synchronize preceding merge candidate
nick2781 Oct 26, 2026
5a8b002
chore(hash): synchronize preceding merge candidate
nick2781 Oct 26, 2026
15b0901
docs(consul): publish construction guide in canonical pages
nick2781 Oct 26, 2026
7f2256f
build(deps): bump fast-uri from 3.1.8 to 3.1.9 in /docs/site
dependabot[bot] Oct 26, 2026
3bed670
refactor(proto): remove unused codec scaffolding
nick2781 Oct 26, 2026
53222f8
refactor(hash): remove platform header dependencies
nick2781 Oct 26, 2026
5a4944c
chore(integration): synchronize accepted hash candidate
nick2781 Oct 26, 2026
69af843
chore(hash): synchronize preceding Consul candidate
nick2781 Oct 26, 2026
ab53c06
chore(integration): synchronize preceding plugin changes
nick2781 Oct 26, 2026
9c6b94e
chore(integration): synchronize preceding header cleanup
nick2781 Oct 26, 2026
94009f4
build(deps): combine fast-uri update with Consul validation
nick2781 Oct 26, 2026
40795f8
chore(integration): synchronize preceding merge candidate
nick2781 Oct 26, 2026
2f6cdf4
refactor(etcd)!: replace plugin creation macros
nick2781 Oct 26, 2026
ae9b546
chore(integration): combine preceding cleanup with Etcd construction
nick2781 Oct 26, 2026
d38982c
fix(tests): probe Net DSO listener and peer closure
nick2781 Oct 26, 2026
5c621eb
fix(tests): bound the Net listener shutdown probe
nick2781 Oct 26, 2026
dd02b81
chore(integration): retain the Net listener test fix
nick2781 Oct 26, 2026
37a88f3
chore(integration): include the Net listener test fix
nick2781 Oct 26, 2026
ab1a01c
refactor(osssdk)!: use typed plugin construction
nick2781 Oct 26, 2026
663a4bd
refactor(kafka)!: replace plugin creation macros
nick2781 Oct 26, 2026
c3f1423
chore(integration): combine OSS SDK and Kafka construction
nick2781 Oct 26, 2026
377b504
chore(integration): synchronize OSS SDK merge candidate
nick2781 Oct 26, 2026
fb85954
docs(roadmap): align supported behavior and remaining acceptance
nick2781 Oct 26, 2026
b66d345
fix(buffer)!: transfer receive storage with move-only ownership
nick2781 Oct 26, 2026
6697839
perf(buffer): isolate write capacity preparation
nick2781 Oct 26, 2026
58222d7
chore(integration): synchronize accepted documentation
nick2781 Oct 26, 2026
9923f33
fix(lifecycle): retain libraries after native unload failure
nick2781 Oct 26, 2026
d310173
test(lifecycle): isolate native readiness deadline
nick2781 Oct 26, 2026
1174d56
chore(branch): synchronize tested buffer fixes
nick2781 Oct 26, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/guides/applications.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ On macOS/Linux, Ctrl+C or `SIGTERM` requests shutdown through the application's

After task completion and the active callback stack returns, the manager waits for every module to report `ready_to_shut()`, then synchronously invokes shutdown hooks and unloading. A module must use its owner-frame readiness check to stop/drain native work and confirm native thread exit before allowing unload. When all hooks succeed, Timers logs `PreShut` and then `Shut`, and the launcher exits. A hook may block; the handler-count budget is not a shutdown-duration bound.

If a shutdown hook returns `false` or throws, the launcher reports its phase, module and available exception details once, keeps the process/resources alive, and does not continue unloading. `plugin_manager::update()` returning `false` or throwing during drain also locks the launcher into retention; owner updates continue where possible, but later completion cannot resume unloading.
If a shutdown hook returns `false` or throws, the launcher reports its phase, module and available exception details once, keeps the process/resources alive, and does not continue unloading. A failed native library close similarly reports `unload: <plugin>`, retains that library handle and wrapper, and stops before closing later libraries. Repeated `stop()` stays failed without repeating plugin exits or close calls. Earlier shutdown work and successful library closes are not rolled back. A successful `FreeLibrary` or `dlclose` call does not prove that the OS library image was unmapped or that arbitrary hot update is safe. `plugin_manager::update()` returning `false` or throwing during drain also locks the launcher into retention; owner updates continue where possible, but later completion cannot resume unloading.

`--shutdown_timeout_ms=N` configures a non-negative int64 wait in milliseconds; the default `0` waits indefinitely. A positive limit uses a monotonic clock and reports elapsed time, pending managed-task count and the waiting phase once. On expiry the process and resources stay alive, owner updates continue, and unloading remains disabled even if work completes later. This is a cooperative owner-loop wait limit: it cannot interrupt a blocking user `update()`, readiness check, shutdown hook or unload call. It is not a hard process-stop deadline, cancellation policy or successful shutdown. This managed-task drain does not prove that arbitrary callbacks, native pool workers or background cleanup have finished; see [module task integration](tasks.md#shared-business-executor-for-modules). Timers's logs alone are not a readiness or shutdown guarantee for every plugin combination.

Expand Down
2 changes: 1 addition & 1 deletion docs/guides/applications_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@ macOS/Linux 可使用 Ctrl+C 或 `SIGTERM`,由应用主循环处理停止请

任务完成且当前回调返回后,管理器等待所有模块的 `ready_to_shut()` 返回就绪,再同步执行关闭钩子与卸载。模块应在 owner frame 的就绪检查中停止并排空原生工作,确认原生线程退出后才允许卸载。所有钩子成功时,Timers 依次输出 `PreShut` 和 `Shut`,随后启动器退出。钩子可能阻塞;handler 数量预算不代表停机耗时上限。

关闭钩子返回 `false` 或抛出异常时,启动器输出一次阶段、模块及可用的异常信息,保留进程和资源,不再继续卸载。排空期间的 `plugin_manager::update()` 返回 `false` 或抛出异常,也会锁定资源保留状态;启动器尽可能继续 owner 更新,但后续完成不能恢复卸载。
关闭钩子返回 `false` 或抛出异常时,启动器输出一次阶段、模块及可用的异常信息,保留进程和资源,不再继续卸载。原生动态库关闭失败时同样报告 `unload: <plugin>`,保留该库句柄与包装对象,并停止关闭后续库。重复 `stop()` 继续返回失败,不重复执行插件出口或关闭调用。先前完成的停机工作与成功关闭的库不会回滚。`FreeLibrary` 或 `dlclose` 成功不证明操作系统已移除库映像,也不证明任意热更新安全。排空期间的 `plugin_manager::update()` 返回 `false` 或抛出异常,也会锁定资源保留状态;启动器尽可能继续 owner 更新,但后续完成不能恢复卸载。

`--shutdown_timeout_ms=N` 设置等待时限,单位为毫秒,接受非负 int64 整数;默认值 `0` 表示无限等待。正数使用单调时钟计时,超时后输出一次实际等待时间、待完成的业务任务数和等待阶段。进程与资源继续保留,owner 更新继续运行;即使工作随后完成,也不再卸载。这是 owner loop 的协作式等待时限,不能中断阻塞中的用户 `update()`、就绪检查、关闭钩子或卸载调用,不构成强制进程退出期限、自动取消策略或成功停机。业务任务排空不证明外部回调、原生连接池线程或后台清理已经完成,详见[模块任务集成](tasks_CN.md#模块共用业务执行器)。仅凭 Timers 的日志,不能推断所有插件组合都具备相同的就绪条件或停止保证。

Expand Down
6 changes: 4 additions & 2 deletions docs/guides/tasks.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,13 @@ Private database bridges use `manager.get_task_runtime()` to share that exact ex
| --- | --- |
| `running` | Update normally and accept tasks |
| `draining` | Continue module updates and the central poll; retain business state and services |
| `failed` | A shutdown hook returned failure or threw; do not continue unloading, and retain process/resources |
| `stopped` | Shutdown hooks completed; repeated `stop()` returns `true` |
| `failed` | A shutdown hook failed/threw or a native library close failed; stop further unloading and retain remaining resources |
| `stopped` | Shutdown hooks and native close calls succeeded; repeated `stop()` returns `true` |

Use `get_shutdown_state()`, `get_shutdown_failure()` and `get_shutdown_exception()` to distinguish waiting from failure. The launcher keeps pumping while tasks remain, and reports a hook failure once while retaining the process. There is no implicit shutdown timeout, cancellation, detach or frame destruction as a drain substitute. The pending-task check does not wait for completion. The poll budget limits handler count, not execution time, and does not bound user-hook or total shutdown latency.

`dynamic_library::unload()` returns `false` on a native close failure and keeps its handle. Success clears the handle; unloading an empty or already closed wrapper returns `true` without another native call. Manager failure records `unload: <plugin>` and latches the existing failed state, retaining the failed wrapper and remaining libraries. It does not retry plugin exits or closes on a later `stop()`, roll back previous teardown, or establish OS image removal.

Use the manager and its groups on their constructing thread. Do not mutate module registries or recursively update from update/shutdown hooks or executor callbacks. While any managed task is pending, no module can unregister: another module’s task may still borrow that provider. Destroying a manager with tasks, on an active callback stack or from another thread terminates; destruction is not a drain entry point.

<Aside type="caution" title="Task completion does not release native IO resources">
Expand Down
6 changes: 4 additions & 2 deletions docs/guides/tasks_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -72,11 +72,13 @@ runtime 和任务组必须在同一线程构造、操作和销毁。`manual_runt
| --- | --- |
| `running` | 正常更新并受理任务 |
| `draining` | 继续模块更新与统一轮询,保持业务状态和服务存活 |
| `failed` | 关闭钩子返回失败或抛出异常;不继续卸载,保留进程和资源 |
| `stopped` | 关闭钩子完成;重复 `stop()` 返回 `true` |
| `failed` | 关闭钩子失败/抛出异常,或原生动态库关闭失败;停止后续卸载,保留剩余资源 |
| `stopped` | 关闭钩子与原生关闭调用成功;重复 `stop()` 返回 `true` |

通过 `get_shutdown_state()`、`get_shutdown_failure()` 和 `get_shutdown_exception()` 区分等待与失败。应用启动器在任务未完成时继续驱动主循环;钩子失败时输出一次原因并保留进程。本实现不设置隐含停机时限,也不以取消、分离任务或销毁协程替代排空。待完成任务的检查不会等待其结束;轮询预算只限制 handler 数量,不限制业务代码或关闭钩子的执行时间。

`dynamic_library::unload()` 在原生关闭失败时返回 `false` 并保留句柄;成功后清空句柄。空包装对象或已关闭对象再次卸载时直接返回 `true`,不再调用原生 API。管理器记录 `unload: <plugin>` 并保持既有失败状态,保留失败的包装对象与其余库。后续 `stop()` 不重试插件出口或关闭,也不回滚先前停机工作;这些结果不代表操作系统已移除库映像。

管理器及其任务必须在构造线程操作。更新/关闭钩子或执行器回调中不能增删模块或递归更新;只要管理器仍有任务,任何模块都不能注销,因为其他模块的任务可能仍引用该服务提供方。管理器在仍有任务、执行回调中或跨线程析构时会终止进程,析构不是排空入口。

<Aside type="caution" title="任务完成不等于 IO 资源已释放">
Expand Down
2 changes: 2 additions & 0 deletions docs/reference/directory-structure.md
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ The MySQL/Redis interfaces have one source each: `src/plugins/mysql/mysql_module

Core has one source copy under `src/core/`. `ark::core` maps its explicit public headers into the selected build tree, preserving `<ark/plugin_manager.hpp>` and nested include paths. Edit source headers rather than generated copies. The `app`/`app_d` executable and manifest format are unchanged.

`<ark/buffer.hpp>` retains its public path with move-only ownership; rebuild affected Core/Net consumers for the source/layout change. See [receive-buffer ownership](network.md#receive-buffer-ownership) for migration, allocation-hook compatibility and focused tests.

## CMake targets

| Target | Usage |
Expand Down
2 changes: 2 additions & 0 deletions docs/reference/directory-structure_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ MySQL、Redis 的唯一公开接口源码分别是 `src/plugins/mysql/mysql_modu

核心头文件只有 `src/core/` 中的一份源码。`ark::core` 将显式公开清单映射到选定构建目录,保留 `<ark/plugin_manager.hpp>` 等包含路径。修改源码头文件,不编辑生成副本。启动程序仍为 `app`/`app_d`,清单格式保持不变。

`<ark/buffer.hpp>` 保留原有公开路径,所有权改为仅支持移动;源码/布局发生变化,需要重建受影响的 Core/Net 消费者。迁移、分配钩子兼容性与定向测试见[收包缓冲的所有权](network_CN.md#收包缓冲的所有权)。

## CMake 目标

| 目标 | 用途 |
Expand Down
21 changes: 21 additions & 0 deletions docs/reference/network.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,6 +95,27 @@ TCP, WebSocket and RUDP endpoints use a 4 KiB initial application receive buffer

This is the framing buffer for application messages, configured separately from kernel socket send/receive buffers. It is not a 4 KiB maximum message size. The [local receive-buffer report](../performance/receive-buffers.md) retains the allocation, fragmented-input and large-batch throughput tradeoff. It does not establish network RTT or connection capacity.

## Receive-buffer ownership

**Breaking source/layout change:** `<ark/buffer.hpp>` exposes a move-only `ark::buffer`. Copy construction and copy assignment are deleted to prevent two objects from deleting the same array. Rebuild the Core/Net consumers and their plugins together. The tracked Net sessions already prohibit copying and own their buffer in place; copying a `shared_ptr` session handle does not copy that buffer. This repository audit does not establish whether external consumers relied on the former implicit copy operations.

Move construction and move assignment are `noexcept` and transfer the allocation, unread bytes, capacity and cursor state. Assignment releases the destination's previous allocation; self-move leaves it unchanged. A moved-from buffer has zero capacity, zero unread bytes and a null data pointer; it can be destroyed, assigned or written to again. Existing public method signatures remain available. Standalone construction still defaults to 512 KiB, while Net sessions retain their separately configured 4 KiB default.

```cpp
ark::buffer pending(4096);
pending.write("abc", 3);
ark::buffer processing(std::move(pending)); // transfers ownership
pending.write("next", 4); // allocates fresh storage
```

Include `<utility>` for `std::move`. `get_data()` returns a borrowed pointer into the current allocation; keep its owner alive and reacquire the pointer after compaction, growth or ownership replacement. This change introduces no clone API. Applications that need independent data can explicitly write the readable bytes into another buffer while the source remains valid.

The buffer keeps `ARK_NEW_ARRAY` / `ARK_DELETE_ARRAY` as its narrow allocation compatibility boundary, now using the same pair for construction, growth and release. This corrects the previous growth path that bypassed custom hooks with raw `new[]` / `delete[]`. Define a compatible, nonthrowing release hook consistently across translation units before including the header. Without overrides, allocation still uses throwing `new[]`: `std::bad_alloc` propagates and failed growth retains the old bytes, capacity and cursors. If a custom allocator returns null, construction retains an empty zero-capacity buffer and `write()` returns `false` without changing the existing state.

A zero-length write succeeds without dereferencing its pointer; a null source with nonzero length returns `false`. Removing more than the unread length is a no-op, including an overflowing count. Unrepresentable growth throws `std::length_error` before allocation. Normal reads, writes, compaction and capacity growth retain their existing behavior.

With `ARK_BUILD_CORE_TESTS=ON`, `check-buffer` runs the lifetime/move, compaction/growth, boundary, deterministic default-allocation failure and separate custom-hook regressions; it is also part of `check-core`. The allocation-failure test fails one small array request instead of requesting excessive memory. `check-network` retains the existing Net framing/fragmented-input coverage. These checks do not establish service or capacity acceptance.

## Member callbacks and borrowed arguments

Endpoint constructors and client/server service registration bind the supplied
Expand Down
21 changes: 21 additions & 0 deletions docs/reference/network_CN.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,6 +80,27 @@ TCP、WebSocket 与 RUDP 端点使用 4 KiB 初始应用层收包缓冲,随后

这是应用消息的拆包缓冲,与内核 socket 收发缓冲分别配置,也不是 4 KiB 的最大消息限制。[本地收包缓冲报告](../performance/receive-buffers_CN.md)保留了内存申请、分片输入与大批量吞吐量之间的取舍,不把这些结果视为网络 RTT 或连接容量。

## 收包缓冲的所有权

**源码/布局不兼容变更:** `<ark/buffer.hpp>` 提供的 `ark::buffer` 仅支持移动。复制构造和复制赋值被显式删除,避免两个对象重复释放同一数组。Core/Net 消费者及其插件必须一起重建。仓库中的 Net Session 原本就禁止复制,并在对象内部持有缓冲;复制 `shared_ptr` Session 句柄不会复制该缓冲。这次仓库调用检查不能证明外部消费者从未使用原有隐式复制操作。

移动构造和移动赋值均为 `noexcept`,转移数组、未读数据、容量和游标状态。移动赋值释放目标原有数组;自身移动保持原状态。移出对象的容量和未读长度均为零,数据指针为空,可继续销毁、赋值或写入。原有公开方法签名继续保留。独立构造默认容量仍为 512 KiB,Net Session 继续使用独立配置的 4 KiB 默认容量。

```cpp
ark::buffer pending(4096);
pending.write("abc", 3);
ark::buffer processing(std::move(pending)); // 转移所有权
pending.write("next", 4); // 重新申请存储
```

使用 `std::move` 时包含 `<utility>`。`get_data()` 返回当前数组中的借用指针;所属对象必须保持有效,在压缩、扩容或替换所有权后重新获取指针。本次不增加 clone API。需要独立数据的应用可在源数据有效期间,将可读字节显式写入另一个缓冲。

缓冲通过 `ARK_NEW_ARRAY`/`ARK_DELETE_ARRAY` 保留最小分配兼容边界,构造、扩容和释放现在使用同一对钩子。这修正了原扩容路径通过裸 `new[]`/`delete[]` 绕过自定义钩子的问题。覆盖钩子时,须在包含头文件前定义匹配且释放时不抛异常的实现,并确保各编译单元定义一致。默认分配仍使用会抛异常的 `new[]`:`std::bad_alloc` 继续向外传播,扩容失败保留原有数据、容量和游标。自定义分配器返回空指针时,构造得到容量为零的空缓冲;`write()` 返回 `false`,不改变已有状态。

零长度写入成功且不解引用传入指针;非零长度的空源指针返回 `false`。移除数量超过未读长度时不改变状态,包括会使加法溢出的数量。容量无法表示时,在分配前抛出 `std::length_error`。正常读写、压缩和容量增长行为保持不变。

开启 `ARK_BUILD_CORE_TESTS=ON` 后,`check-buffer` 运行生命周期/移动、压缩/扩容、边界、默认分配确定性失败及独立自定义钩子回归,并纳入 `check-core`。分配失败测试只使一次小数组申请失败,不申请巨量内存。`check-network` 保留既有 Net 拆包与分片输入覆盖。这些检查不代表服务或容量验收。

## 成员回调与借用参数

端点构造函数与客户端/服务端服务的注册接口通过 C++20 `std::bind_front`,
Expand Down
Loading
Loading